文件是存储在磁盘中的具有特定名称和目录路径的数据集合,当我们使用程序对文件进行读取或写入时,程序会将文件以数据流(简称流)的形式读入内存中。我们可以将流看作是通过通信路径传递的字节序列,流主要分为输入流和输出流,输入流主要用于从文件读取数据(读操作),输出流主要用于向文件中写入数据(写操作)。
System.IO 命名空间中包含了各种用于文件操作的类,例如文件的创建、删除、读取、写入等等。如下表中所示:
I/O 类 | 描述 |
---|---|
BinaryReader | 从二进制流中读取原始数据 |
BinaryWriter | 以二进制格式写入原始数据 |
BufferedStream | 临时存储字节流 |
Directory | 对目录进行复制、移动、重命名、创建和删除等操作 |
DirectoryInfo | 用于对目录执行操作 |
DriveInfo | 获取驱动器的信息 |
File | 对文件进行操作 |
FileInfo | 用于对文件执行操作 |
FileStream | 用于文件中任何位置的读写 |
MemoryStream | 用于随机访问存储在内存中的数据流 |
Path | 对路径信息执行操作 |
StreamReader | 用于从字节流中读取字符 |
StreamWriter | 用于向一个流中写入字符 |
StringReader | 用于从字符串缓冲区读取数据 |
StringWriter | 用于向字符串缓冲区写入数据 |
FileStream 类在 System.IO 命名空间下,使用它可以读取、写入和关闭文件。创建 FileStream 类对象的语法格式如下所示:
FileStream <object_name> = new FileStream(<file_name>, <FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
参数说明如下:
object_name:创建的对象名称;
file_name:文件的路径(包含文件名在内);
FileMode:枚举类型,用来设定文件的打开方式,可选值如下:
Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件;
Create:创建一个新的文件,如果文件已存在,则将旧文件删除,然后创建新文件;
CreateNew:创建一个新的文件,如果文件已存在,则抛出异常;
Open:打开一个已有的文件,如果文件不存在,则抛出异常;
OpenOrCreate:打开一个已有的文件,如果文件不存在,则创建一个新的文件并打开;
Truncate:打开一个已有的文件,然后将文件清空(删除原有内容),如果文件不存在,则抛出异常。
FileAccess:枚举类型,用来设置文件的存取,可选值有 Read、ReadWrite 和 Write;
FileShare:枚举类型,用来设置文件的权限,可选值如下:
Inheritable:允许子进程继承文件句柄,Win32 不直接支持此功能;
None:在文件关闭前拒绝共享当前文件,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败;
Read:允许随后打开文件读取,如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求都将失败,需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
ReadWrite:允许随后打开文件读取或写入,如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求都将失败,需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
Write:允许随后打开文件写入,如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求都将失败,需要注意的是,即使指定了此标志,仍可能需要附加权限才能够访问该文件;
Delete:允许随后删除文件。
例如,我们创建一个 FileStream 对象 F 来读取一个名为 sample.txt 的文件,示例代码如下所示:
FileStream F = new FileStream(“sample.txt”, FileMode.Open, FileAccess.Read, FileShare.Read);
FileStream 类中的常用方法如下所示:
方法 | 描述 |
---|---|
Close() | 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄) |
CopyTo(Stream) | 从当前流中读取字节并将其写入到另一流中 |
Dispose() | 释放由 Stream 使用的所有资源 |
Equals(Object) | 判断指定对象是否等于当前对象 |
Finalize() | 确保垃圾回收器回收 FileStream 时释放资源并执行其他清理操作 |
Flush() | 清除此流的缓冲区,使得所有缓冲数据都写入到文件中 |
GetHashCode() | 默认哈希函数 |
GetType() | 获取当前实例的 Type |
Lock(Int64, Int64) | 防止其他进程读取或写入 FileStream |
Read(Byte[], Int32, Int32) | 从流中读取字节块并将该数据写入给定缓冲区中 |
ReadByte() | 从文件中读取一个字节,并将读取位置提升一个字节 |
ToString() | 返回表示当前对象的字符串 |
Unlock(Int64, Int64) | 允许其他进程访问以前锁定的某个文件的全部或部分 |
Write(Byte[], Int32, Int32) | 将字节块写入文件流 |
WriteByte(Byte) | 将一个字节写入文件流中的当前位置 |
【示例】使用 FileStream 类读取指定的文件:
using System;
using System.IO;
namespace c.biancheng.net
{
class Demo
{
static void Main(string[] args)
{
FileStream file = new FileStream("test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
for(int i = 0; i < 20; i++){
file.WriteByte((byte)i);
}
file.Position = 0;
for(int i = 0; i < 20; i++){
Console.Write(file.ReadByte() + " ");
}
file.Close();
Console.ReadKey();
}
}
}
运行结果:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
System.IO 命名空间下的 StreamReader 和 StreamWriter 类可以用于文本文件的数据读写。这些类继承自抽象基类 Stream,Stream 类提供了对文件流读写的功能。
StreamReader 类继承自抽象基类 TextReader,用来从文件中读取一系列字符,下表列出了 StreamReader 类中一些常用的方法:
方法 | 描述 |
---|---|
public override void Close() | 关闭 StreamReader 对象和基础流,并释放任何与之相关的系统资源 |
public override int Peek() | 返回下一个可用的字符,但不使用它 |
public override int Read() | 从输入流中读取下一个字符,并把字符位置往前移一个字符 |
如果想查阅完整的方法列表,可以访问官方API
【示例】使用 StreamReader 读取指定文件的内容,文件的内容如下所示:
薪薪代码
你好
C# 教程
示例代码如下:
using System;
using System.IO;
namespace c.biancheng.net
{
class Demo
{
static void Main(string[] args)
{
try{
// 创建 StreamReader 类的对象
StreamReader file = new StreamReader("test.txt");
string line;
// 从文件中读取内容
while((line = file.ReadLine()) != null){
Console.WriteLine(line);
}
}catch(Exception e){
// 展示出错信息
Console.WriteLine("无法读取文件");
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
}
}
运行上述代码即可输出文件中的内容。
StreamWriter 类同样继承自抽象类 TextWriter,用来向文件中写入一系列字符,下表列出了 StreamWriter 类中一些常用的方法:
方法 | 描述 |
---|---|
public override void Close() | 关闭当前的 StreamWriter 对象和基础流 |
public override void Flush() | 清理当前所有的缓冲区,使所有缓冲数据写入基础流 |
public virtual void Write(bool value) | 将布尔值的文本表示形式写入文本流 |
public override void Write(char value) | 将一个字符写入流 |
public virtual void Write(decimal value) | 将一个小数值的文本表示形式写入文本流 |
public virtual void Write(double value) | 将一个 8 字节浮点值的文本表示形式写入文本流 |
public virtual void Write(int value) | 将一个 4 字节有符号整数的文本表示形式写入文本流 |
public override void Write(string value) | 将一个字符串写入文本流 |
public virtual void WriteLine() | 将行结束符写入文本流 |
完整的方法列表请查阅官方API
【示例】向文件中写入指定内容。
using System;
using System.IO;
namespace c.biancheng.net
{
class Demo
{
static void Main(string[] args)
{
// 要写入文件中的数据
string[] str = new string[]{
"薪薪代码",
"你好",
"C# 教程"
};
// 创建 StreamWriter 类的对象
StreamWriter file = new StreamWriter("demo.txt");
// 将数组中的数据写入文件
foreach(string s in str){
file.WriteLine(s);
}
file.Close();
// 读取文件中的内容
string line = "";
StreamReader readfile = new StreamReader("demo.txt");
while((line = readfile.ReadLine()) != null){
Console.WriteLine(line);
}
readfile.Close();
Console.ReadKey();
}
}
}
运行结果如下:
薪薪代码
你好
C# 教程
C# 中的 BinaryReader 和 BinaryWriter 类可以用于二进制文件的读写。
BinaryReader 类用于从文件读取二进制数据,类中的常用方法如下所示:
方法 | 描述 |
---|---|
public override void Close() | 关闭 BinaryReader 对象和基础流 |
public virtual int Read() | 从基础流中读取字符,并根据所使用的编码和从流中读取的特定字符,将流的当前位置前移 |
public virtual bool ReadBoolean() | 从当前流中读取一个布尔值,并将流的当前位置前移一个字节 |
public virtual byte ReadByte() | 从当前流中读取下一个字节,并将流的当前位置前移一个字节 |
public virtual byte[] ReadBytes(int count) | 从当前流中读取指定数目的字节到一个字节数组中,并将流的当前位置前移指定数目的字节 |
public virtual char ReadChar() | 从当前流中读取下一个字节,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移 |
public virtual char[] ReadChars(int count) | 从当前流中读取指定数目的字符,并以字符数组的形式返回数据,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移 |
public virtual double ReadDouble() | 从当前流中读取一个 8 字节浮点值,并把流的当前位置前移八个字节 |
public virtual int ReadInt32() | 从当前流中读取一个 4 字节有符号整数,并把流的当前位置前移四个字节 |
public virtual string ReadString() | 从当前流中读取一个字符串,字符串以长度作为前缀,同时编码为一个七位的整数 |
完整的方法列表请查阅 官方API
BinaryWriter 类用于向文件写入二进制数据,类中的常用方法如下表所示:
方法 | 描述 |
---|---|
public override void Close() | 关闭 BinaryWriter 对象和基础流 |
public virtual void Flush() | 清理当前编写器的所有缓冲区,使得所有缓冲数据写入基础设备 |
public virtual long Seek(int offset,SeekOrigin origin) | 设置当前流中的位置 |
public virtual void Write(bool value) | 将一个字节的布尔值写入到当前流中,0 表示 false,1 表示 true |
public virtual void Write(byte value) | 将一个无符号字节写入到当前流中,并把流的位置前移一个字节 |
public virtual void Write(byte[] buffer) | 将一个字节数组写入到基础流中 |
public virtual void Write(char ch) | 将一个 Unicode 字符写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移 |
public virtual void Write(char[] chars) | 将一个字符数组写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移 |
public virtual void Write(double value) | 将一个 8 字节浮点值写入到当前流中,并把流位置前移八个字节 |
public virtual void Write(int value) | 将一个 4 字节有符号整数写入到当前流中,并把流位置前移四个字节 |
public virtual void Write(string value) | 将一个有长度前缀的字符串按 BinaryWriter 的当前编码写如到流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移 |
完整的方法列表请查阅官方API
【示例】下面通过示例演示二进制文件的读取和写入:
using System;
using System.IO;
namespace c.biancheng.net
{
class Demo
{
static void Main(string[] args)
{
BinaryWriter bw;
BinaryReader br;
int i = 520;
double d = 3.14159;
bool b = true;
string s = "薪薪代码";
// 创建文件
try{
bw = new BinaryWriter(new FileStream("mydata", FileMode.Create));
}catch (IOException e){
Console.WriteLine(e.Message + "\n 文件创建失败!");
return;
}
// 写入文件
try{
bw.Write(i);
bw.Write(d);
bw.Write(b);
bw.Write(s);
}catch (IOException e){
Console.WriteLine(e.Message + "\n 文件写入失败!");
}
bw.Close();
// 读取文件
try{
br = new BinaryReader(new FileStream("mydata", FileMode.Open));
}catch (IOException e){
Console.WriteLine(e.Message + "\n 文件打开失败!");
return;
}
try{
i = br.ReadInt32();
Console.WriteLine("Integer data: {0}", i);
d = br.ReadDouble();
Console.WriteLine("Double data: {0}", d);
b = br.ReadBoolean();
Console.WriteLine("Boolean data: {0}", b);
s = br.ReadString();
Console.WriteLine("String data: {0}", s);
}catch (IOException e){
Console.WriteLine(e.Message + "\n 文件读取失败!.");
}
br.Close();
Console.ReadKey();
}
}
}
运行结果:
Integer data: 520
Double data: 3.14159
Boolean data: True
String data:薪薪代码