文件的输入与输出
一个文件是一个存储在磁盘中带有指定名称和目录路径的数据集合。当打开文件进行读写时,它变成一个流(Stream)。
从根本上说,流是通过通信路径传递的字节序列。有两个主要的流:输入流 和 输出流。输入流用于从文件读取数据(读操作),输出流用于向文件写入数据(写操作)。
I/O 类
System.IO 命名空间有各种不同的类,用于执行各种文件操作,如创建和删除文件、读取或写入文件,关闭文件等。
下表列出了一些 System.IO 命名空间中常用的非抽象类:
I/O 类 | 描述 |
---|---|
BinaryReader | 从二进制流读取原始数据。 |
BinaryWriter | 以二进制格式写入原始数据。 |
BufferedStream | 字节流的临时存储。 |
Directory | 有助于操作目录结构。 |
DirectoryInfo | 用于对目录执行操作。 |
DriveInfo | 提供驱动器的信息。 |
File | 有助于处理文件。 |
FileInfo | 用于对文件执行操作。 |
FileStream | 用于文件中任何位置的读写。 |
MemoryStream | 用于随机访问存储在内存中的数据流。 |
Path | 对路径信息执行操作。 |
StreamReader | 用于从字节流中读取字符。 |
StreamWriter | 用于向一个流中写入字符。 |
StringReader | 用于读取字符串缓冲区。 |
StringWriter | 用于写入字符串缓冲区。 |
FileStream 类 (字节数组)
System.IO 命名空间中的 FileStream 类用于文件的读写与关闭。该类派生自抽象类 Stream。
您需要创建一个 FileStream 对象来创建一个新的文件,或打开一个已有的文件。创建 FileStream 对象的语法如下: FileStream <object_name> = new FileStream( <file_name>,<FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
例如,创建一个 FileStream 对象 F 来读取名为 sample.txt 的文件: FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
参数:
-
FileMode 枚举表示对这个文件的操作。FileMode 枚举的成员有:
-
Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件。
-
Create:创建一个新的文件。如果文件已存在,则删除旧文件,然后创建新文件。
-
CreateNew:指定操作系统应创建一个新的文件。如果文件已存在,则抛出异常。
-
Open:打开一个已有的文件。如果文件不存在,则抛出异常。
-
OpenOrCreate:指定操作系统应打开一个已有的文件。如果文件不存在,则用指定的名称创建一个新的文件打开。
-
Truncate:打开一个已有的文件,文件一旦打开,就将被截断为零字节大小。然后我们可以向文件写入全新的数据,但是保留文件的初始创建日期。如果文件不存在,则抛出异常。
-
-
FileAccess:枚举 表示对这个文件里面的数据进行的操作 ,FileAccess枚举的成员有:
-
Read:对文件的读访问。可从文件中读取数据。同 Write组合即构成读写访问权
-
Write:文件的写访问。可将数据写入文件。同 Read组合即构成读/写访问权
-
ReadWrite :读写
-
-
FileShare:FileShare 枚举的成员有:
-
Inheritable:允许文件句柄可由子进程继承。Win32 不直接支持此功能。
-
None:谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。
-
Read:允许随后打开文件读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
-
ReadWrite:允许随后打开文件读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
-
Write:允许随后打开文件写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
-
Delete:允许随后删除文件。
-
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _01_FileStream { internal class Program { static void Main(string[] args) { //读取文件 //1.创建一个FileStream对象(注意: 引入IO命名空间) //FileStream 实例化的时候,必须给构造函数传递参数,一般使用三个参数 //参数1:文件路径 //参数2:表示对这个文件的操作 //参数3:表示对这个文件里面的数据进行的操作 /* 路径基础知识: 相对路径: 相对于当前文件的路径,不完整的路径 \abc\aa\a.txt 绝对路径: 完整的路径, 从盘符开始 E:\AI视觉23班\C#编程\课件\0716_文件的输入与输出\01_FileStream\Program.cs 特殊符号: ./ 表示当前目录 ../ 表示上一层目录 ../../表示上上一层目录 */ //注意文件路径: //"" 创建的字符串 \ 表示转义 //技巧: @"" 创建的字符串的特点:里面写什么就是什么 // FileStream file = new FileStream(@"E:\1\吴亦凡.txt", FileMode.OpenOrCreate, FileAccess.Read); //2.创建字节数组,用于存放读到文件,用该数组的长度限定每次读取的文件的大小和数组的大小一致 // byte[] buffe = new byte[1024 * 1024 * 5];//每次读取5M的的内容到内存中,然后保存到字节数组 //3.调用读取的方法 //参数1:存放的字节数组 //参数2:开始往字节数组中存放的位置 //参数3:每次读取的字节大小 //返回值:本次实际读取到的有效的字节数,比如读取一个3.5m的文件,虽然给的是5m的空间,但是实际上也只反悔了3.5m //int r= file.Read(buffe,0,buffe.Length); //4.将字节数组中每一个元素,按照指定的编码格式解码成指定的格式(字符串) //参数1:需要解码的数组 //参数2:从数组中哪个字节开始解码 //参数3:解码的长度 //string str1 = Encoding.UTF8.GetString(buffe,0,r); //string str2 = Encoding.Default.GetString(buffe, 0, r); //5.关闭数据流 //file.Close(); //6.释放占用的资源 GC //file.Dispose(); // Console.WriteLine(str1); // Console.WriteLine(str2); //写入文件 //相对路径: 需要去bin/Debug目录去查看 FileStream file = new FileStream(@"吴亦凡.txt", FileMode.OpenOrCreate, FileAccess.Write); string str = "加拿大劣迹男艺人吴亦凡1"; byte [] buffer = Encoding.UTF8.GetBytes(str); file.Write(buffer, 0, buffer.Length); } } }
实例 BinaryWriter 和 BinaryReader
它涉及到二进制文件的读写。BinaryReader 和 BinaryWriter 类有助于完成二进制文件的读写。
BinaryReader 和 BinaryWriter 类用于二进制文件的读写。
BinaryReader 类
BinaryReader 类用于从文件读取二进制数据。一个 BinaryReader 对象通过向它的构造函数传递 FileStream 对象而被创建。
下表列出了 BinaryReader 类中一些常用的方法:
序号 | 方法 | 描述 |
---|---|---|
1 | public override void Close() | 关闭 BinaryReader 对象和基础流。 |
2 | public virtual int Read() | 从基础流中读取字符,并把流的当前位置往前移。 |
3 | public virtual bool ReadBoolean() | 从当前流中读取一个布尔值,并把流的当前位置往前移一个字节。 |
4 | public virtual byte ReadByte() | 从当前流中读取下一个字节,并把流的当前位置往前移一个字节。 |
5 | public virtual byte[] ReadBytes( int count ) | 从当前流中读取指定数目的字节到一个字节数组中,并把流的当前位置往前移指定数目的字节。 |
6 | public virtual char ReadChar() | 从当前流中读取下一个字节,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移。 |
7 | public virtual char[] ReadChars( int count ) | 从当前流中读取指定数目的字节,在一个字符数组中返回数组,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移。 |
8 | public virtual double ReadDouble() | 从当前流中读取一个 8 字节浮点值,并把流的当前位置往前移八个字节。 |
9 | public virtual int ReadInt32() | 从当前流中读取一个 4 字节有符号整数,并把流的当前位置往前移四个字节。 |
10 | public virtual string ReadString() | 从当前流中读取一个字符串。字符串以长度作为前缀,同时编码为一个七位的整数。 |
BinaryWriter 类
BinaryWriter 类用于向文件写入二进制数据。一个 BinaryWriter 对象通过向它的构造函数传递 FileStream 对象而被创建。
下表列出了 BinaryWriter 类中一些常用的方法:
序号 | 方法 | 描述 |
---|---|---|
1 | public override void Close() | 关闭 BinaryWriter 对象和基础流。 |
2 | public virtual void Flush() | 清理当前编写器的所有缓冲区,使得所有缓冲数据写入基础设备。 |
3 | public virtual long Seek( int offset, SeekOrigin origin ) | 设置当前流内的位置。 |
4 | public virtual void Write( bool value ) | 把一个单字节的布尔值写入到当前流中,0 表示 false,1 表示 true。 |
5 | public virtual void Write( byte value ) | 把一个无符号字节写入到当前流中,并把流的位置往前移一个字节。 |
6 | public virtual void Write( byte[] buffer ) | 把一个字节数组写入到基础流中。 |
7 | public virtual void Write( char ch ) | 把一个 Unicode 字符写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。 |
8 | public virtual void Write( char[] chars ) | 把一个字符数组写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。 |
9 | public virtual void Write( double value ) | 把一个 8 字节浮点值写入到当前流中,并把流位置往前移八个字节。 |
10 | public virtual void Write( int value ) | 把一个 4 字节有符号整数写入到当前流中,并把流位置往前移四个字节。 |
11 | public virtual void Write( string value ) | 把一个以长度为前缀的字符串写入到 BinaryWriter 的当前编码的流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _02__BinaryWriter_和_BinaryReader { internal class Program { static void Main(string[] args) { //FileStream file = new FileStream(@"test.txt", FileMode.Create, FileAccess.Write); 创建二进制写入流的实例 //BinaryWriter bw = new BinaryWriter(file, Encoding.UTF8); 向缓冲区写入内容 //bw.Write(true); //bw.Write(666); //bw.Write(666.66); //bw.Write(Encoding.UTF8.GetBytes("吴亦凡")); 清楚缓冲区的内容,将缓冲区的内容写入到文件中 //bw.Flush(); //关闭二进制流 // bw.Close(); //关闭文件流 //file.Close(); //FileStream file = new FileStream(@"test.txt", FileMode.Open, FileAccess.Read); //BinaryReader br = new BinaryReader(file); //Console.WriteLine(br.ReadBoolean()); //Console.WriteLine(br.ReadInt32()); byte[] data = new byte[file.Length]; while (br.Read(data, 0, data.Length) > 0) { //Console.WriteLine(Encoding.UTF8.GetString(data)); Console.WriteLine(new UTF8Encoding().GetString(data)); } //br.Close(); //file.Close(); } } }
实例 BufferedStream
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _03_BufferedStream { internal class Program { static void Main(string[] args) { //缓冲区是内存中的字节块,用于缓存数据,从而减少对操作系统调用的失败次数,缓冲区可以提高读取和写入的性能,但是不能同时进行两种操作 // BufferedStream 用于读写缓冲区 //BufferedStream 对象是包含了已经创建的现有的流对象而形成的 //BufferedStream bs = new BufferedStream(File.Create("text.txt")); 创建BufferedStream 对象之后 可以调用Rea()和Write() 方法 实现数据的读写 //byte[] info1 = new UTF8Encoding().GetBytes("fanfan"); //bs.Write(info1, 0, info1.Length); //byte[] info2 = new UTF8Encoding().GetBytes("xiangxiang"); //bs.Write(info2, 0, info2.Length); //byte[] info3 = new UTF8Encoding().GetBytes("罗志祥"); //bs.Write(info3, 0, info3.Length); //bs.Flush(); //bs.Close(); BufferedStream bs = new BufferedStream(File.OpenRead("text.txt")); byte[] buffer =new byte[bs.Length]; while (bs.Read(buffer,0,buffer.Length)>0) { Console.WriteLine(new UTF8Encoding().GetString(buffer)); } } } }
实例 Directory 类
Directory类用于在目录和子目录中进行创建移动等操作。此外,还可以访问和操作各种各样的目录属性,例如最后一次修改时间以及Windows访问控制列表
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _04_Directory { internal class Program { static void Main(string[] args) { //1.CreateDirectory() 创建文件夹 // Directory.CreateDirectory(@"吴亦凡"); DirectoryInfo info = Directory.CreateDirectory(@"E:\1\吴亦凡"); //可以Attributes来进件的文件进行属性的设置 FileAttributes枚举 ReadOnly 只读 Hidden 隐藏 //info.Attributes=FileAttributes.Hidden; //2.Delete() 删除 // 参数1: 删除的路径 // 参数2:true(默认值) 将整个文件删除,哪怕文件中有其他的文件,也会同时删除, false当文件夹为空的时候才可以删除 //Directory.Delete(@"E:\AI视觉23班\吴亦凡",false); //3.Move() 移动文件夹 // Directory.Move(@"E:\AI视觉23班\吴亦凡", @"E:\机器视觉16班\吴亦凡"); //4. GetDirectories() 获取文件夹下的所有的子文件夹 string [] strs1= Directory.GetDirectories(@"E:1\1\04_Directory"); foreach (string str in strs1) { Console.WriteLine(str); } //5.GetFiles() 获取文件夹下所有的子文件 string[] strs2 = Directory.GetFiles(@"E:1\1\04_Directory"); foreach (string str in strs2) { Console.WriteLine(str); } //6.判断目录是否存在 Console.WriteLine(Directory.Exists(@"E:1\1\04_Directory")); } } }
实例 File 类
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _05_File { internal class Program { static void Main(string[] args) { //1.Create() 用于在指定的路径中创建或者覆盖一个文件 // FileStream file = File.Create("1.txt"); //2.Delete() 删除 //File.Delete("1.txt"); //3. Copy() 复制 // File.Copy(@"E:1\1.tx","1.txt"); //4.Move() 移动 // File.Move(@"E:1\1.txt", "1.txt"); //5. 判断文件是否存在 //File.Exists(): // WriteAllBytes()和ReadAllBytes() 用于文件的读写 操作的是字节数据,返回文件内容的字节数字 File.WriteAllBytes(@"1.txt", new UTF8Encoding().GetBytes("吴亦凡")); byte[] buffer = File.ReadAllBytes(@"1.txt"); string str= new UTF8Encoding().GetString(buffer); Console.WriteLine(str); //------------------ //WriteAllLines() 和ReadAllLines() 用于文件的读写 操作的是所有的行,返回文件中所有行的字符串数组 string[] info = new string[] { "吴亦凡", "罗志祥", "李云迪" }; File.WriteAllLines("2.txt",info,new UTF8Encoding()); //File.ReadAllLines("2.txt",new UTF8Encoding()); string [] strs= File.ReadAllLines("2.txt",Encoding.UTF8); foreach (var item in strs) { Console.WriteLine(item); } //---------------------- File.WriteAllText("3.txt", "吴亦凡是加拿大劣迹那艺人", Encoding.UTF8); string ss= File.ReadAllText("3.txt", Encoding.UTF8); Console.WriteLine(ss); } } }
StreamReader 类
StreamReader 类继承自抽象基类 TextReader,表示阅读器读取一系列字符。
下表列出了 StreamReader 类中一些常用的方法:
序号 | 方法 | 描述 |
---|---|---|
1 | public override void Close() | 关闭 StreamReader 对象和基础流,并释放任何与读者相关的系统资源。 |
2 | public override int Peek() | 返回下一个可用的字符,但不使用它。 |
3 | public override int Read() | 从输入流中读取下一个字符,并把字符位置往前移一个字符。 |
static void Main(string[] args) { //Stream Reader StreamReader sr = new StreamReader(@"1.txt", Encoding.UTF8); string line = ""; while ((line=sr.ReadLine())!=null) { Console.WriteLine(line); } sr.Close(); }
StreamWriter 类
StreamWriter 类继承自抽象类 TextWriter,表示编写器写入一系列字符。
下表列出了 StreamWriter 类中一些常用的方法:
序号 | 方法 | 描述 |
---|---|---|
1 | public override void Close() | 关闭当前的 StreamWriter 对象和基础流。 |
2 | public override void Flush() | 清理当前编写器的所有缓冲区,使得所有缓冲数据写入基础流。 |
3 | public virtual void Write(bool value) | 把一个布尔值的文本表示形式写入到文本字符串或流。(继承自 TextWriter。) |
4 | public override void Write(char value) | 把一个字符写入到流。 |
5 | public virtual void Write(decimal value) | 把一个十进制值的文本表示形式写入到文本字符串或流。 |
6 | public virtual void Write(double value) | 把一个 8 字节浮点值的文本表示形式写入到文本字符串或流。 |
7 | public virtual void Write(int value) | 把一个 4 字节有符号整数的文本表示形式写入到文本字符串或流。 |
8 | public override void Write(string value) | 把一个字符串写入到流。 |
9 | public virtual void WriteLine() | 把行结束符写入到文本字符串或流。 |
//using的作用: //1.引入命名空间 //2.可以帮助我们完成Close的过程 static void Main(string[] args) { //using(obj) 会把obj在大括号之内使用完毕之后直接释放掉 using (StreamReader sr = new StreamReader(@"1.txt", Encoding.UTF8)) { string line = ""; while ((line = sr.ReadLine()) != null) { Console.WriteLine(line); } } Console.WriteLine("后续的代码1000"); }
中文乱码的情况
读取中文的时候会显示乱码,在读取文件内容的时候使用:
using (StreamReader sr = new StreamReader("C:/a.txt", Encoding.GetEncoding("GB2312")))
然后编译的时候会报错,无法编译。
报错的解决办法如下:
第一:
using System.Text;
第二:
在 .csproj 文件中应添加如下代码:
<ItemGroup> <PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" /> </ItemGroup
第三步:
在使用 System.Text.Encoding.GetEncoding ("GB2312") 之前,在代码中执行:
System.Text.Encoding.RegisterProvider (System.Text.CodePagesEncodingProvider.Instance);