添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
深情的西装  ·  genshin ...·  1 月前    · 
行走的烤红薯  ·  vue.js·  4 月前    · 
含蓄的大象  ·  从 express 到 midway | ...·  11 月前    · 

C#文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Di,有需要的朋友可以参考下。


文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory、DirectoryInfo、Path、Encoding)
10.1、FileStream 10.1.1、定义一个流对象

Streamfs =newFileStream(@"D:\FINISH.TXT",FileMode.Open,FileAccess.Read,FileShare.Read);

Stream是父类,FileStream是子类,父类是一个抽象类,子类才是实现类。

FileMode是一个枚举类型,它有很多值:

Open:表示该流对象应该打开现有文件,如果文件不存在,那么就会打开异常的。

CreateNew:表示创建新文件,如果文件存在,那么就会发生异常。

Create:表示创建新文件,如果文件存在,那么就会被改写(清空再写)。

OpenOrCreate:表示如果文件存在就打开,不存在就创建。

FileAccess:控制本流对文件的访问权限:读、写、读写。

FileShare:当前的流在对指定文件进行访问的时候,控制别的流对该文件的访问权限:读、写、读写、没有任何权限,默认情况下,外界是没有权限来访问该文件的,除非指定。

10.1.2、读取文件

Streamfs =newFileStream(@"D:\FINISH.TXT",FileMode.Open);

intlength = fs.Read(byte[] buffer,intoffset,intcount);

buffer:这个是字节数组,是用来存放读取的文件的。

offset:这个是buffer中的相对于起始索引0的偏移量,也就是从offset开始存放的。

count:计划从流文件中读取的字节数,count不要去超越buffer的长度。

返回值:该函数返回从文件中实际读取字节数。0<=返回值<= count

对于Read函数,只要流没有关闭它所指向的文件,那么第一次读取是从第一个字节开始的,第二次读取从第一次读取的最后一个字节的下一个开始,有seek会自动的将流当前指向的文件的位置往后移动,以后的读取依次类推。

读取文件的时候,fs有一个Length属性,表示它所指向的文件的字节大小,即文件的总长度。

10.1.3、写入文件

Streamfs =newFileStream(@"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(inta);

这个是将32位的整数(我们看到的是十进制的整数,32位是指在计算机中以二进制存放的时候,占有32个bit位)转换成为长度为4的字节数组:32位整数表示的是二进制的32个bit位,正好对应着4个字节,在字节中,从低八位到高八位加起来正好也是32位,最低位是二的零次方,然后是二的一次方,依次类推,所以转换的时候,首先将十进制的32位整数按照二进制转换成32个bit位,然后按照八位进行分割,变成四个字节,分别存放到buffer中,整数的低八位存放在buffer[0],最高的八位存放在buffer[3]中,编译调试的时候,看到的每一个字节的数字又是单个字节从二进制转换成十进制的值。

inta =BitConverter.ToInt32(byte[] buffer,intstartIndex)

这个是将buffer中的,从startIndex开始的四个字节,按照从低八位到高八位的顺序转换成为32位的整数值,startIndex是低八位,startIndex + 3是高八位。

10.2.2、64位double与字节的相互转换

byte[] buffer =BitConverter.GetBytes(doublea);

这个是将64位的double转换成为长度为8的字节数组,double的低八位存放在buffer[0],最高的八位存放在buffer[7]中。

doublea =BitConverter. ToDouble(byte[] buffer,intstartIndex)

这个是将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、写文本文件

StreamWritersw =newStreamWriter(@"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、读文本文件

StreamReadersr =newStreamReader(@"D:\test.txt",Encoding.Default);

stringstr = sr.ReadLine();

这个函数是读取文本文件中的某一行,并将该行后面的\r\n删除掉,返回字符串,如果该行后面没有\r\n,那么就直接返回该行。读取总是从上一次读取之后再读取,如果读完了所有的行,再次读取就会返回null了。

stringstr = sr.ReadToEnd();

读取整个文本文件的,以字符串的形式返回。

注意:最后操作完成后要关闭流。文件如果不存在,那么就会在定义的时候异常。

10.4、File

该类是一个与文件有关的类,是一个静态类,它里面的函数是静态函数。主要提供了对文件的创建、删除、移动、打开文件的静态方法。

10.4.1、文件拷贝

File.Copy(stringsourceFileName,stringdestFileName)

两个参数包含完整的路径和文件名,目标路径中不能有与destFileName同名文件,否则会异常。

File.Copy(stringsourceFileName,stringdestFileName,booloverwrite)

前两个参数包含完整的路径和文件名,最后一个参数指示如果在目标路径中有同名文件,是否覆盖这个文件。

10.4.2、判断文件是否存在

File.Exists(stringpath);

boolisExist =File.Exists(@"c:\zwj");

如果path指定的文件还存在,那么就返回true,否则返回false

10.4.3、删除文件

File.Delete(stringpath);

删除path指定的文件。如果存在就删除,不存在也不会引发异常。

10.4.4、文件移动

File.Move(stringsourceFileName,stringdestFileName)

两个参数包含完整的路径和文件名,目标路径中不能有与destFileName同名文件,否则会异常。

10.4.5、创建文件

File.Create(stringpath);

如果文件不存在,那么就创建;如果存在,且为可写,那么就覆盖;如果存在不可写,那么就会发生异常。

默认情况下,新创建的文件是可读写的。

10.4.6、与文件有关的几个时间

File.GetCreationTime(stringpath);

这个函数是获取文件的创建时间,返回DateTime。

File.GetLastAccessTime(stringpath);

这个函数是获取最后一次访问文件的时间,返回DateTime。

File.GetLastWriteTime(stringpath);

这个函数是获取文件的最后一次的修改时间,返回DateTime。

10.5、FileInfo类

该类也是一个与文件有关的类,但是该类不是一个静态类,该类必须经过实例化之后才可以使用。

FileInfofi =newFileInfo(stringfileName);

10.5.1、复制

fi.CopyTo(stringdestFileName)

目标路径中不能有与destFileName同名文件,否则会异常。

fi.CopyTo(stringdestFileName,booloverwrite)

最后一个参数指示如果在目标路径中有同名文件,是否覆盖这个文件。

注意:以上两个函数会返回FileInfo对象,这个对象是指向destFileName的。

10.5.2、删除

fi.Delete();

永久删除文件,文件不存在也不会发生异常。

10.5.3、移动

fi.MoveTo(stringdestFileName)

目标路径中不能有与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(stringpath);

按照path所指定的路径去创建目录、子目录,返回一个指向path的DirectoryInfo对象。这里是创建目录而非文件,不能通过"r:"创建一个逻辑盘,只能在现有的逻辑盘下面创建目录。重复创建已经存在的目录是不会发生异常的。任何新创建的目录名不能与该目录同一级目录下的文件名同名,否则就会报错。

2、 删除目录

Directory.Delete(stringpath);

这个函数是删除目录,这个目录必须为空目录,即里面不能有目录和文件。否则异常。目录不存在也会异常。

Directory.Delete(stringpath,boolrecursive);

这个函数是删除目录,当recursive为true,那么可以删除非空目录,否则只能删除空目录。目录不存在也会异常。

3、 移动目录

VoidDirectory.Move(stringsourceDirName,stringdestDirName)

将原目录的内容全部移到目标目录里面,然后将原目录删除。

4、 判断目录是否存在

Directory.Exists(stringpath);

存在返回true,否则返回false。

5、 得到目录的创建时间:DateTime Directory.GetCreationTime(stringpath);

6、 得到目录的最后一次访问时间:DateTime Directory.GetLastAccessTime(stringpath)

7、 得到目录的最后一次修改时间:DateTime Directory.GetLastWriteTime(stringpath)

8、 得到当前的执行程序所在的目录:stringDirectory.GetCurrentDirectory(stringpath);

9、string[]Directory.GetDirectories(stringpath);

获取指定目录中的子目录名称,只是获取指定目录的下一级,而非下两级或者下三级。返回的是包括目录名在内的完整的路径字符串数组。

10、string[]Directory.GetFiles(stringpath);

获取指定目录中的子文件名称,只是获取指定目录的下一级,而非下两级或者下三级。返回的是包括文件名在内的完整的路径字符串数组。

11、stringDirectory.GetDirectoryRoot(stringpath)

获取path执行的路径的根目录,卷信息,比如”d:\”,path可以是文件或者目录

12、string[]Directory.GetLogicalDrives();

得到本系统的逻辑盘,以字符串的形式返回。如:”d:\”

13、DirectoryInfoDirectory.GetParent(stringpath);

14、 得到指定的path的父目录,返回DirectoryInfo对象,path可以是文件和目录。如果path是根目录,那么就返回null。

注意:目录最后不要加”\”

10.8、DirectoryInfo类

该类也是一个与目录有关的类,但是该类不是一个静态类,该类必须经过实例化之后才可以使用。

DirectoryInfodi =newDirectoryInfo(@"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、DirectoryInfodi.CreateSubdirectory(stringpath)

这个是在当前目录的下面创建子目录、子子目录,返回一个新的DirectoryInfo对象。比如path:a\b\c,a前面不能有\。

2、voiddi.Delete()

这个表示删除di指定的空目录,如果目录中有内容,那么会引发异常。

voiddi.Delete(bool)

如果目录不为空,那么true表示全部删除,false表示不删除。如果目录为空,不论true还是false都将直接删除。

3、DirectoryInfo []di.GetDirectories();

返回当前目录的下一级所有子目录。如果没有,返回的数组长度为0.

4、FileInfo[]di.GetFiles();

返回当前目录的下一级所有子文件。如果没有,返回的数组长度为0.

10.9、Path

该类是一个与路径相关的类,是一个处理路径字符串的,它不会去识别文件或者目录,它只会去识别字符串,然后单纯的按照字符串来处理,它里面的函数全部是public static。

1、Path.ChangeExtension(stringpath,stringextension);

这个函数是用来更新扩展名的,path为完整的路径,extension是含有签到句点的扩展名。如果path没有扩展名,那么就加上extension,有就直接更新。如果extension为null或者空字符串,那么会将path中的扩展名去掉。这个只是对字符串进行变换,对原文件不会有任何的影响。

2、Path.GetDirectoryName(stringpath);

path为文件或者目录的路径,这个是返回文件或者目录的上一级目录,即返回的是最后一个”\”符号之前的字符串,如果path为null或者为根目录,那么就返回null。

3、Path.GetExtension(stringpath);

返回指定路径的带前导句点的扩展名。如果没有扩展名,就返回长度为0的字符串。如果path为null就返回null。

4、Path.GetFileName(stringpath);

获取包括扩展名在内的文件名,如果是目录,也会当成文件处理。path如果为根目录则返回长度为0的字符串;如果为null则返回null。

1、Path.GetFileNameWithoutExtension(stringpath);

获取不包括扩展名在内的文件名,如果是目录,也会当成文件处理。path如果为根目录则返回长度为0的字符串;如果为null则返回null。

2、Path.GetFullPath(stringpath);

path为相对路径或者绝对路径,返回绝对路径。

3、Path.GetPathRoot(stringpath)

获取path的根目录信息,如果如果path为null,那么就返回null。

10.10、小结

注意:任何一个文件都有三个时间:

创建时间:这个文件的创建时间,如果把这个文件复制到另外一个路径下面,那么文件的创建时间就发生了变化,是复制时的时间;如果对这个文件改名,那么创建时间不会发生改变。

最后一次的修改时间:这个时间指的是最后一次修改文件内容的时间。如果把这个文件复制到另外一个路径下面,那么文件的最后一次修改时间就不会发生变化;如果对这个文件改名,那么最后一次修改时间也不会发生改变。只有修改内容才会发生变化。

最后一次的访问时间:是最后一次访问这个文件的时间,这个时间比较模糊。

如果用一个文件A去覆盖同名文件B,那么B被覆盖后,B的创建时间不变,最后一次的修改时间变成了A的最后一次修改时间。最后一次修改一个文件的时候,如果不保存,那么修改时间还是原来的时间。