C#文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory、directoryInfo、Path、Encoding)
操作文件类:File
操作路径类:Path
操作文件夹类:Directory
(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory、DirectoryInfo、Path、Encoding)
C#文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory,有需要的朋友可以参考下。
文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory、DirectoryInfo、Path、Encoding)
10.1、FileStream 要将字符转换为字节处理
10.1.1、定义一个流对象
Stream fs =new FileStream(@"D:\FINISH.TXT",FileMode.Open,FileAccess.Read,FileShare.Read);
说明:
Stream是父类,FileStream是子类,父类是一个抽象类,子类才是实现类。
FileMode是一个枚举类型,它有很多值:
Open:表示该流对象应该打开现有文件,如果文件不存在,那么就会打开异常的。
CreateNew:表示创建新文件,如果文件存在,那么就会发生异常。
Create:表示创建新文件,如果文件存在,那么就会被改写(清空再写)。
OpenOrCreate:表示如果文件存在就打开,不存在就创建。
FileAccess:控制本流对文件的访问权限:读、写、读写。
FileShare:当前的流在对指定文件进行访问的时候,控制别的流对该文件的访问权限:读、写、读写、没有任何权限,默认情况下,外界是没有权限来访问该文件的,除非指定。
10.1.2、读取文件
Stream fs =new FileStream(@"D:\FINISH.TXT",FileMode.Open);
int length = fs.Read(byte[] buffer,intoffset,intcount);
buffer:这个是字节数组,是用来存放读取的文件的。
offset:这个是buffer中的相对于起始索引0的偏移量,也就是从offset开始存放的。
count:计划从流文件中读取的字节数,count不要去超越buffer的长度。
返回值:该函数返回从文件中实际读取字节数。0<=返回值<= count
注意:
对于Read函数,只要流没有关闭它所指向的文件,那么第一次读取是从第一个字节开始的,第二次读取从第一次读取的最后一个字节的下一个开始,有seek会自动的将流当前指向的文件的位置往后移动,以后的读取依次类推。
读取文件的时候,fs有一个Length属性,表示它所指向的文件的字节大小,即文件的总长度。
10.1.3、写入文件
Stream fs =new FileStream(@"D:\FINISH.TXT",FileMode. Create);
fs.Write(byte[] buffer,intoffset,intcount);
buffer:这个是字节数组,就是将该字节数组中的数据写入到文件中的。
offset:这个是buffer中的相对于起始索引0的偏移量,也就是从offset开始读取buffer的。
count:从buffer中读取的字节数,写入到文件中,count <=buffer.length - offset。
返回值:该函数无返回值。
注意:对于Write函数,如果文件是已存在的,在第一次write之前,会将文件全部清空,然后只要流没有关闭它所指向的文件,那么第一次写入文件是从文件开头开始写入的,第二次写入是从第一次写入的最后一个字节的下一个开始,有seek会自动的将流当前指向的文件的位置往后移动,以后的写入依次类推。
这种写入只是写入到缓冲区中,文件中还没有,要想真的写入文件,还必须依赖下面的函数:
fs.Flush();
这个是将缓冲区的内容写入到基础流中,并清空缓冲区,这样才可以在文件中查看到内容。只要文件没有被关闭,就可以不停的Write和Flush,后面的写入是往文件末尾写。 如果缓冲区很大,可以Write一部分然后Flush一部分,分多次Write和Flush。
10.1.4、关闭文件
fs.Close()
这个是将缓冲区的内容写入到基础流中,并清空缓冲区,所以即使没有Flush(),调用的时候,一样会完成Flush()的功能;并关闭流与它所指向的文件之间的联系,并释放所有的与之关联的资源。这样这个文件就与该流没有任何的关系了,可以继续被别的流来访问了。所以当流使用完毕之后一定要关闭。当流关闭之后,就不能再用之前的流对象来操作文件了,否则会出错。
10.2、字节与整数、浮点数、字符串的相互转换
在读写文件的时候,经常涉及到数值与字节的相互转换、字符串与字节之间的相互转换,下面分别来说明:
10.2.1、32位整数与字节的相互转换
byte[] buffer =BitConverter.GetBytes(int a);
这个是将32位的整数(我们看到的是十进制的整数,32位是指在计算机中以二进制存放的时候,占有32个bit位)转换成为长度为4的字节数组:32位整数表示的是二进制的32个bit位,正好对应着4个字节,在字节中,从低八位到高八位加起来正好也是32位,最低位是二的零次方,然后是二的一次方,依次类推,所以转换的时候,首先将十进制的32位整数按照二进制转换成32个bit位,然后按照八位进行分割,变成四个字节,分别存放到buffer中,整数的低八位存放在buffer[0],最高的八位存放在buffer[3]中,编译调试的时候,看到的每一个字节的数字又是单个字节从二进制转换成十进制的值。
int a =BitConverter.ToInt32(byte[] buffer,intstartIndex)
这个是将buffer中的,从startIndex开始的四个字节,按照从低八位到高八位的顺序转换成为32位的整数值,startIndex是低八位,startIndex + 3是高八位。
10.2.2、64位double与字节的相互转换
byte[] buffer =BitConverter.GetBytes(double a);
这个是将64位的double转换成为长度为8的字节数组,double的低八位存放在buffer[0],最高的八位存放在buffer[7]中。
double a =BitConverter. ToDouble(byte[] buffer,int startIndex)
这个是将buffer中的,从startIndex开始的八个字节,按照从低八位到高八位的顺序转换成为64位的double值。
10.2.3、字符串与字节的相互转换
byte[] buffer =Encoding.Default.GetBytes(stringa);
这个是将一个字符串转换成为一个字节数组。
strings =Encoding.Default.GetString(byte[] buffer,intstartIndex,intcount);
这个是将buffer数组转换成为字符串,startIndex是buffer中的起始索引,count是buffer中的要转换的字节长度。
10.3、StreamWriter、StreamReader 直接处理字符
在读写文件的时候,经常要读写文本文件,在读写文本文件的时候有两个类是非常方便的。
10.3.1、写文本文件
StreamWriter sw =new StreamWriter(@"D:\test.txt");
定义了一个StreamWriter对象之后,首先是没有文件就创建文件,有就把文件内容清空(本节中的构造函数是这样的,但是可以调用其他的重载构造函数来完成不同的功能)。
sw.WriteLine("123");
这个函数是将一个字符串写入到文件的末尾,并且自动的加上\r\n换行。
sw.Write("123");
这个是将一个字符串写入到文件的末尾,不会加\r\n换行。
注意:以上的两个函数只是写入到缓冲区了,但是此时去查看文件,文件还是没有被写入的。
sw.Flush();
这个是将缓冲区的内容写入到基础流中,并清空缓冲区,这样才可以在文件中查看到内容。只要文件没有被关闭,就可以不停的Write和Flush,后面的写入是往文件末尾写。 如果缓冲区很大,可以Write一部分然后Flush一部分,分多次Write和Flush。
sw.Close()
这个是将缓冲区的内容写入到基础流中,并清空缓冲区,所以即使没有Flush(),调用的时候,一样会完成Flush()的功能;并关闭流与它所指向的文件之间的联系,并释放所有的与之关联的资源。这样这个文件就与该流没有任何的关系了,可以继续被别的流来访问了。所以当流使用完毕之后一定要关闭。当流关闭之后,就不能再用之前的流对象来操作文件了,否则会出错。
10.3.2、读文本文件
StreamReader sr =new StreamReader(@"D:\test.txt",Encoding.Default);
string str = sr.ReadLine();
这个函数是读取文本文件中的某一行,并将该行后面的\r\n删除掉,返回字符串,如果该行后面没有\r\n,那么就直接返回该行。读取总是从上一次读取之后再读取,如果读完了所有的行,再次读取就会返回null了。
string str = sr.ReadToEnd();
读取整个文本文件的,以字符串的形式返回。
注意:最后操作完成后要关闭流。文件如果不存在,那么就会在定义的时候异常。
10.4、File
该类是一个与文件有关的类,是一个静态类,它里面的函数是静态函数。主要提供了对文件的创建、删除、移动、打开文件的静态方法。
10.4.1、文件拷贝
File.Copy(string sourceFileName,string destFileName)
两个参数包含完整的路径和文件名,目标路径中不能有与destFileName同名文件,否则会异常。
File.Copy(string sourceFileName,string destFileName,bool overwrite)
前两个参数包含完整的路径和文件名,最后一个参数指示如果在目标路径中有同名文件,是否覆盖这个文件。
10.4.2、判断文件是否存在
File.Exists(string path);
bool isExist =File.Exists(@"c:\zwj");
如果path指定的文件还存在,那么就返回true,否则返回false
10.4.3、删除文件
File.Delete(string path);
删除path指定的文件。如果存在就删除,不存在也不会引发异常。
10.4.4、文件移动
File.Move(string sourceFileName,string destFileName)
两个参数包含完整的路径和文件名,目标路径中不能有与destFileName同名文件,否则会异常。
10.4.5、创建文件
File.Create(string path);
如果文件不存在,那么就创建;如果存在,且为可写,那么就覆盖;如果存在不可写,那么就会发生异常。
默认情况下,新创建的文件是可读写的。
10.4.6、与文件有关的几个时间
File.GetCreationTime(string path);
这个函数是获取文件的创建时间,返回DateTime。
File.GetLastAccessTime(string path);
这个函数是获取最后一次访问文件的时间,返回DateTime。
File.GetLastWriteTime(string path);
这个函数是获取文件的最后一次的修改时间,返回DateTime。
10.5、FileInfo类
该类也是一个与文件有关的类,但是该类不是一个静态类,该类必须经过实例化之后才可以使用。
FileInfo fi =new FileInfo(string fileName);
10.5.1、复制
fi.CopyTo(string destFileName)
目标路径中不能有与destFileName同名文件,否则会异常。
fi.CopyTo(string destFileName,bool overwrite)
最后一个参数指示如果在目标路径中有同名文件,是否覆盖这个文件。
注意:以上两个函数会返回FileInfo对象,这个对象是指向destFileName的。
10.5.2、删除
fi.Delete();
永久删除文件,文件不存在也不会发生异常。
10.5.3、移动
fi.MoveTo(string destFileName)
目标路径中不能有与destFileName同名文件,否则会异常。
10.5.4、属性
d:\programmfile\zwj.txt
1、 CreationTime:获取或者设置文件的创建时间。返回DateTime。
2、 LastWriteTime:最后一次的修改时间。返回DateTime。
3、 LastAcessTime:最后一次的访问时间。返回DateTime。
4、 DirectoryName:获取包含该文件的目录的完整路径的字符串:d:\programmfile
5、 FullName:获取包括文件名的完整路径:d:\programmfile\zwj.txt
6、 Name:获取文件名和扩展名:zwj.txt
7、 Extension:获取文件的扩展名:.txt
8、 Exists:指示文件是否存在,存在返回true,否则为false。
9、 IsReadOnly:获取或者设置当前的文件是否为只读的。是返回true,否则为false。
10、Length:返回文件的长度,以字节为单位。长整型。
11、Directory:获取包含该文件的目录的DirectoryInfo实例。
10.6、关于文件的总结
1、不论是创建文件还是读取文件,只要文件的路径只是一个文件名,而没有绝对的路径,那么文件名默认为当前目录下面。这个当前是可能在变化的,程序开始启动的时候,当前肯定是exe同一级目录下面,但是有时候程序启动之后,再进行某些操作的时候,比如导出到excle报表,选择了别的文件夹路径,那么这个当前路径就是新路径而非exe同一级目录了。
2、..\:这个表示当前目录的上一级目录。这个当前目录像上面一样也是可能变化的。
3、当对一个文件第一次进行写操作的时候,首先会把文件的内容清空。
4、如果要想找到一个固定的exe文件的路径:
Application.ExecutablePath:获取启动应用程序可执行文件的路径,包括可执行文件的名称:
E: \source\存储过程版\PVPT\MainMenu\bin\Debug\MainMenu.EXE
Application.StartupPath:获取启动应用程序可执行文件的路径,不包括可执行文件的名称:
E: \source\存储过程版\PVPT\MainMenu\bin\Debug(没\)
10.7、Directory
该类是一个与目录有关的类,是一个静态类,它里面包含了静态函数和静态属性。
1、 创建目录
Directory.CreateDirectory(string path);
按照path所指定的路径去创建目录、子目录,返回一个指向path的DirectoryInfo对象。这里是创建目录而非文件,不能通过"r:"创建一个逻辑盘,只能在现有的逻辑盘下面创建目录。重复创建已经存在的目录是不会发生异常的。任何新创建的目录名不能与该目录同一级目录下的文件名同名,否则就会报错。
2、 删除目录
Directory.Delete(string path);
这个函数是删除目录,这个目录必须为空目录,即里面不能有目录和文件。否则异常。目录不存在也会异常。
Directory.Delete(string path,bool recursive);
这个函数是删除目录,当recursive为true,那么可以删除非空目录,否则只能删除空目录。目录不存在也会异常。
3、 移动目录
VoidDirectory.Move(string sourceDirName,string destDirName)
将原目录的内容全部移到目标目录里面,然后将原目录删除。
4、 判断目录是否存在
Directory.Exists(string path);
存在返回true,否则返回false。
5、 得到目录的创建时间:DateTime Directory.GetCreationTime(string path);
6、 得到目录的最后一次访问时间:DateTime Directory.GetLastAccessTime(string path)
7、 得到目录的最后一次修改时间:DateTime Directory.GetLastWriteTime(string path)
8、 得到当前的执行程序所在的目录:string Directory.GetCurrentDirectory(string path);
9、string[] Directory.GetDirectories(string path);
获取指定目录中的子目录名称,只是获取指定目录的下一级,而非下两级或者下三级。返回的是包括目录名在内的完整的路径字符串数组。
10、string[] Directory.GetFiles(string path);
获取指定目录中的子文件名称,只是获取指定目录的下一级,而非下两级或者下三级。返回的是包括文件名在内的完整的路径字符串数组。
11、string Directory.GetDirectoryRoot(string path)
获取path执行的路径的根目录,卷信息,比如”d:\”,path可以是文件或者目录
12、string[] Directory.GetLogicalDrives();
得到本系统的逻辑盘,以字符串的形式返回。如:”d:\”
13、DirectoryInfo Directory.GetParent(string path);
14、 得到指定的path的父目录,返回DirectoryInfo对象,path可以是文件和目录。如果path是根目录,那么就返回null。
注意:目录最后不要加”\”
10.8、DirectoryInfo类
该类也是一个与目录有关的类,但是该类不是一个静态类,该类必须经过实例化之后才可以使用。
DirectoryInfo di =new DirectoryInfo(@"d:\Program Files");
10.8.1、属性
1、CreationTime:获取或者设置目录的创建时间。返回DateTime。
2、LastWriteTime:最后一次的修改时间。返回 DateTime。
3、LastAcessTime:最后一次的访问时间。返回 DateTime。
4、Exists:指示目录是否存在,存在返回true,否则为false。
5、FullName:获取目录的完整路径,返回string。
6、Extension:获取目录名的扩展名,返回string。
7、Name:不包含路径的目录名,即文件夹的名字,返回string。
8、Parent:获取父目录,如果当前目录是根目录,就返回null,否则返回DirectoryInfo。
9、Root:获取当前目录的根目录,返回DirectoryInfo。
10.8.2、方法
1、DirectoryInfo di.CreateSubdirectory(string path)
这个是在当前目录的下面创建子目录、子子目录,返回一个新的DirectoryInfo对象。比如path:a\b\c,a前面不能有\。
2、void di.Delete()
这个表示删除di指定的空目录,如果目录中有内容,那么会引发异常。
void di.Delete(bool)
如果目录不为空,那么true表示全部删除,false表示不删除。如果目录为空,不论true还是false都将直接删除。
3、DirectoryInfo [] di.GetDirectories();
返回当前目录的下一级所有子目录。如果没有,返回的数组长度为0.
4、FileInfo[] di.GetFiles();
返回当前目录的下一级所有子文件。如果没有,返回的数组长度为0.
10.9、Path
该类是一个与路径相关的类,是一个处理路径字符串的,它不会去识别文件或者目录,它只会去识别字符串,然后单纯的按照字符串来处理,它里面的函数全部是public static。
1、Path.ChangeExtension(string path,string extension);
这个函数是用来更新扩展名的,path为完整的路径,extension是含有签到句点的扩展名。如果path没有扩展名,那么就加上extension,有就直接更新。如果extension为null或者空字符串,那么会将path中的扩展名去掉。这个只是对字符串进行变换,对原文件不会有任何的影响。
2、Path.GetDirectoryName(string path);
path为文件或者目录的路径,这个是返回文件或者目录的上一级目录,即返回的是最后一个”\”符号之前的字符串,如果path为null或者为根目录,那么就返回null。
3、Path.GetExtension(stringpath);
返回指定路径的带前导句点的扩展名。如果没有扩展名,就返回长度为0的字符串。如果path为null就返回null。
4、Path.GetFileName(string path);
获取包括扩展名在内的文件名,如果是目录,也会当成文件处理。path如果为根目录则返回长度为0的字符串;如果为null则返回null。
1、Path.GetFileNameWithoutExtension(string path);
获取不包括扩展名在内的文件名,如果是目录,也会当成文件处理。path如果为根目录则返回长度为0的字符串;如果为null则返回null。
2、Path.GetFullPath(string path);
path为相对路径或者绝对路径,返回绝对路径。
3、Path.GetPathRoot(string path)
获取path的根目录信息,如果如果path为null,那么就返回null。
10.10、小结
注意:任何一个文件都有三个时间:
创建时间:这个文件的创建时间,如果把这个文件复制到另外一个路径下面,那么文件的创建时间就发生了变化,是复制时的时间;如果对这个文件改名,那么创建时间不会发生改变。
最后一次的修改时间:这个时间指的是最后一次修改文件内容的时间。如果把这个文件复制到另外一个路径下面,那么文件的最后一次修改时间就不会发生变化;如果对这个文件改名,那么最后一次修改时间也不会发生改变。只有修改内容才会发生变化。
最后一次的访问时间:是最后一次访问这个文件的时间,这个时间比较模糊。
如果用一个文件A去覆盖同名文件B,那么B被覆盖后,B的创建时间不变,最后一次的修改时间变成了A的最后一次修改时间。最后一次修改一个文件的时候,如果不保存,那么修改时间还是原来的时间。