1、编码:
计算机只能识别二进制格式的数据,也就是0和1组成的数据
那么计算机是怎么识别英文的呢?
是因为计算机刚出来的时候,老外就编了一套字符编码,叫ASCII码,用不同的ASCII码对应不同的英文以及英文标点符号等!然后再转换成二进制格式
ASCII表图在下面,计算英文字符在计算机中表示的ASCII码:
因为计算机是老外发明的,所以老外就没考虑到其他语言的情况,所以计算机标准的ASCII码只能存英文以及英文的标点符号等,不能存其他语言!
但是假如我要存其他语言呢,计算机该怎么识别呢?
以中文为例:在计算机初期,已经有各种各样的编码对汉字“海”进行了编码并存进了计算机,下面我们就来看下不同编码对“海”字所存储的编码信息
可以看出,不同编码存储的信息是不一样的!所以这也就强调了用什么编码保存的文件,就用什么编码打开!不然就会造成乱码! 最好使用国际推荐编码:UTF-8
Encoding.Default使用的是操作系统的当前 ANSI 代码页的编码。
2、文本文件
文本文件可以用不同的编码方式来存储为二进制格式:UTF-8,ASCII,Unicode等
如果出现乱码,一般都是编码的问题,用什么编码保存,就应该用什么编码格式打开,
文本文件相关联的函数一般都有一个Encoding类!
什么是文本文件,能拖到记事本中,并能看得懂的文件就是文本文件,doc不是!
关键类:File操作文件,Directory操作目录(文件夹),Path操作路径(是对路径字符串进行的操作)!
3、流
用File.ReadAllText和File.WriteAllText进行文件读写是一次性读写,如果文件非常大,会占内存、慢!
需要读一行处理一行的机制,这就是流,Stream会读取要求的位置,长度的内容!
Stream不会将所有的内容一次性读取到内存中,有一个指针,指针指到哪里才能读写到哪里!
流有很多种类:文件流是其中一种,FileStream
byte[]是任何数据最根本的表示形式,任何数据最终都是二进制。
using (FileStream fs = new FileStream(@"C:UsersWHDesktopDos命令.txt", FileMode.Open)) { using (FileStream fs2 = new FileStream(@"C:UsersWHDesktopDos赋值.txt", FileMode.CreateNew)) { byte[] b = new byte[1024 * 1024 * 4]; //4M int getv = 0; //getv表示实际读了多长的内容 while ((getv = fs.Read(b, 0, b.Length)) > 0) { fs2.Write(b, 0, getv); } } }
Flush,Close,Dispose:
FileStream fs = new FileStream("c:\1a.txt", FileMode.Create); string result = "1234"; byte[] b = Encoding.UTF8.GetBytes(result); fs.Write(b, 0, b.Length);
执行上面代码,发现1a.txt文件里面的内容是空的,这就涉及到了文件的Flush,Close,Dispose相关知识了,
我们对FileStream的Write方法进行反编译,逐步查看此方法调用了那些东西,可以看到下面这段:
这就说明了,此方法会调用C++语言的动态库,这就属于非托管程序了,.net不知道此方法什么时候会执行结束,也就脱离了.net的管辖范围,
这就表示什么时候向文件里面写入流是不确定的!系统会把流全部积攒到内存中去!等到系统空闲的时候再写到文件中去!
操作系统会帮我们优化(等到空闲时去处理),如果你不想它帮我们优化,就使用Flush强制去执行就行了!
Flush方法是清理缓冲区,把缓冲区中的数据全部写到文件中去!
那么只要代码最后面加句Flush即可!
fs.Flush();//但是我们不应该手动调用Flush,而是使用Close方法!
fs.Close();//会把没有写入缓冲区的数据写入文件(Flush)再关闭
最佳方式:就是使用Using,因为Using会调用Dispose,Dispose会调用Close,而Close会调用Flush,所以最好使用Using!自己可以反编译去看!
Dispose: //执行与释放或重置非托管资源相关的应用程序定义的任务。
如果using,Flush,CLose,Dispose都不使用的话,那么就必须等应用程序结束,流才能全部写入文件
因为应用程序结束的话,FileStream被释放,也就是被Dispose了,自然而然流会被写入文件,
如果此段代码是放在一个click事件里面执行的话,照理由这个click事件返回,FileStream会被释放,但是发现文件还是无法立即写入的!
因为FileStream并没有被立即释放
File.OpenWrite和File.OpenRead:
这俩个方法主要是为了使用方便而已,没什么特别的!File.OpenWrite和File.OpenRead内部还是new了FileStream,自己可以反编译看下!
FileStream fs = new FileStream("c:\1a.txt", FileMode.Create) 就等于 FileStream fs = File.OpenWrite("c:\1a.txt");
FileStream fs = new FileStream("c:\1a.txt", FileMode.Open) 就等于 FileStream fs = File.OpenRead("c:\1a.txt");
Stream:
Stream类是FileStream(文件流)类的父类,有MemoryStream(内存流),GZipStream(压缩解压流),CryptoStream(加密流),尽量使用父类Stream!
GZipStream压缩
using (FileStream fs = File.OpenWrite(@"c:11.txt")) { using (GZipStream gz = new GZipStream(fs, CompressionMode.Compress)) { byte[] b = Encoding.UTF8.GetBytes("Hello World"); gz.Write(b, 0, b.Length); } }
GZipStream解压
using (FileStream fs = File.OpenRead(@"c:11.txt")) { using (GZipStream gz = new GZipStream(fs, CompressionMode.Decompress)) { using (FileStream fs2 = File.OpenWrite(@"c:11a.txt")) { int getByte; byte[] b = new byte[1024 * 1024 * 4]; while ((getByte = gz.Read(b, 0, b.Length)) > 0) { fs2.Write(b, 0, getByte); } } } }
.Net开源的压缩组件还有:ZIP-DotNetZip,7Zip-SevenZipSharp,综合-SharpCompress
详见:http://www.cnblogs.com/asxinyu/archive/2013/03/05/2943696.html
CryptoStream加密、解密
class Program { static void Main(string[] args) { Rijndael rijndael = Rijndael.Create(); byte[] key = rijndael.Key; byte[] iv = rijndael.IV; using (Stream readStream = File.OpenRead(@"d:原文.txt")) { using (Stream writeStream = File.OpenWrite(@"d:加密之后.txt")) { using (CryptoStream cs = new CryptoStream(writeStream, rijndael.CreateEncryptor(key, iv), CryptoStreamMode.Write)) { byte[] b = new byte[1024 * 1024 * 2]; int readlength = 0; while ((readlength = readStream.Read(b, 0, b.Length)) > 0) { cs.Write(b, 0, readlength); } } } } Console.WriteLine("加密完成!按任意键进行解密!"); Console.ReadKey(); using (Stream readStream = File.OpenRead(@"d:加密之后.txt")) { using (Stream writeStream = File.OpenWrite(@"d:解密之后.txt")) { using (CryptoStream cs = new CryptoStream(readStream, rijndael.CreateDecryptor(key, iv), CryptoStreamMode.Read)) { byte[] b = new byte[1024 * 1024 * 2]; int readlength = 0; while ((readlength = cs.Read(b, 0, b.Length)) > 0) { writeStream.Write(b, 0, readlength); } } } } Console.WriteLine("解密完成!按任意键退出程序!"); Console.ReadKey(); } }
StreamReader和StreamWriter
简化了对文本类型流的读取
using (FileStream fs = File.OpenRead(@"c:11.txt")) { using (StreamReader sr = new StreamReader(fs)) { //Console.WriteLine(sr.ReadToEnd()); // 用于从当前位置读到最后的位置,内容大的话会占内存 string text = string.Empty; while ((text = sr.ReadLine()) != null)//读取一行,如果读到了末尾,则返回null { Console.WriteLine(text); } } }
using (FileStream fs = File.OpenWrite(@"c:11.txt")) { using (StreamWriter sr = new StreamWriter(fs)) { sr.Write("123"); //sr.WriteLine("456"); } }
网络流:System.Net.ConnectStream
WebClient wc = new WebClient(); //wc.DownloadFile("http://www.baidu.com/1.doc", @"c:1.doc");//不建议使用! Stream s = wc.OpenRead("http://www.baidu.com/1.doc");//建议使用这种流的方式读取,打断点可以看出s为System.Net.ConnectStream类型 int getByte = 0; byte[] b = new byte[1024 * 1024 * 4]; using (s) { while ((getByte = s.Read(b, 0, b.Length)) > 0) { using (MemoryStream ms = new MemoryStream()) { ms.Write(b, 0, getByte); } } }
//因为有的Stream子类不支持指针的后退、Seek,而使用NPOI对excel进行操作时,HSSFWorkbook要求传入一个指针能随意移动的流memstream,而上面的网络流s不支持,所以把网络流转换成内存流即可!内存流支持!
HSSFWorkbook workbook = new HSSFWorkbook(memstream); HSSFSheet sheet = workbook.GetSheetAt(0); HSSFRow row = sheet.GetRow(0); MessageBox.Show(row.GetCell(0).StringCellValue);