C# 之 按字节读写文件
1.FileStream类
用于实现文件读写的类都是Stream和Reader/Writer的派生类,如FileStream类、StreamReader类、StreamWriter类、BinaryReader类和BinaryWriter类等。
FileStream类对文件系统上的文件进行读取、写入、打开和关闭操作,并对其他与文件相关的操作系统句柄进行操作,如管道、标准输入和标准输出。
FileStream还可以指定读写操作是同步还是异步。
2.常用构造函数:
//参数
//path :路径当前FileStream对象将访问的文件的相对或绝对路径
//mode :决定如何打开或创建文件的常量。 [下文有 FileMode 枚举源码]
public FileStream(string path, FileMode mode);
//参数 : FileAccess : 设置文件读取权限的
//[enum FileAccess {Read = 1,Write = 2,ReadWrite = 3}]
public FileStream(string path, FileMode mode, FileAccess access);
//参数 : share : 设置文件共享模式 [下文有 FileShare 枚举源码]
public FileStream(string path, FileMode mode, FileAccess access, FileShare share);
//参数 : bufferSize: 值大于0,表示缓冲区大小。默认缓冲区大小是4096。
public FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize);
//参数 : useAsync: 是否使用异步
public FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync);
FileMode枚举
//指定操作系统应该如何打开文件。
public enum FileMode
{
// 创建新的文件,如果该文件已经存在,则输入System.IO。IOException异常抛出。
CreateNew = 1,
//指定操作系统应该创建一个新文件。如果文件已经存在时,将被覆盖。
//不存在,请使用System.IO.FileMode.CreateNew;否则,使用System.IO.FileMode.Truncate。
//如果该文件已经存在,但是一个隐藏文件,则System.UnauthorizedAccessException抛出异常。
Create = 2,
//指定操作系统应打开现有文件 如果文件不存在,FileNotFoundException异常抛出。
Open = 3,
//指定操作系统应打开一个存在的文件;否则,创建一个新文件
OpenOrCreate = 4,
//指定操作系统应打开现有文件。当文件打开时,应将其截断以使其大小为零字节。
Truncate = 5,
//如果文件存在,则打开该文件并寻找该文件的末尾,或创建一个新的文件。
Append = 6
}
PS:
如果文件不存在 Append Open和Truncate会抛出异常,
如果文件存在 CreateNew会抛出异常;
Create 和 OpenOrCreate: Create会删除现有的文件,新建一个空的文件,OpenOrCreate会判断当前是否有文件,没有的话才会创建;
FileShare枚举
//包含用于控制访问其他System.IO的类型的常量。
//FileStream对象可以有相同的文件。
[Flags]
public enum FileShare
{
//谢绝共享当前文件。任何打开文件的请求(通过这个过程)或其他进程)将失败,直到文件关闭。
None = 0,
//允许随后打开文件进行读取。如果没有指定这个标志,任何打开文件读取的请求(由这个进程或其他进程)将失败,直到文件关闭。
//但是,即使指定了这个标志,访问该文件可能仍然需要其他权限。
Read = 1,
//允许随后打开文件以便写入。如果没有指定这个标志,任何打开写入文件的请求(由该进程或其他进程)将失败,直到文件关闭。
//但是,即使指定了这个标志,访问该文件可能仍然需要其他权限。
Write = 2,
//允许随后打开文件进行读写。如果这个标志是未指定,任何打开文件进行读写(通过此进程)的请求或其他进程)将失败,直到文件关闭。
//然而,即使这样属性指定时,可能仍然需要其他权限来访问文件。
ReadWrite = 3,
//允许后续删除文件。
Delete = 4,
//使文件句柄可被子进程继承。Win32不直接支持这一点。
Inheritable = 16
}
3.常用属性和方法:
成员类型 | 成员名 | 注释 |
---|---|---|
属性 | Length | 获取流的长度,以字节为单位。[只读] |
属性 | IsAsync | FileStream是异步打开的还是同步打开的。[只读] |
属性 | CanWrite | 返回一个值,该值指示当前流是否支持写入。[只读] |
属性 | CanSeek | 返回一个值,该值指示当前流是否支持查找。[只读] |
属性 | CanRead | 返回一个值,该值指示当前流是否支持读取。[只读] |
属性 | CanRead | 获取或设置此流的当前位置。 |
😃 | 😃 | 😃 |
方法 | BeginRead() | 开始异步读。 |
方法 | BeginWrite() | 开始异步写。 |
方法 | Close() | 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。 |
方法 | CopyTo(Stream) | 从当前流中读取所有字节并将其写入到目标流中。 |
方法 | EndRead() | 等待挂起的异步读取完成。 |
方法 | EndWrite() | 结束异步写入,在 I/O 操作完成之前一直阻塞。 |
方法 | Flush() | 清除此流的缓冲区,使得所有缓冲的数据都写入到文件中。 |
方法 | Lock() | 防止其他进程更改 FileStream。 |
方法 | Read() | 从流中读取字节块并将该数据写入给定缓冲区中。 |
方法 | ReadByte() | 从文件中读取一个字节,并将读取位置提升一个字节。 |
方法 | Seek() | 将该流的当前位置设置为给定值。 |
方法 | SetLength() | 将该流的长度设置为给定值。 |
方法 | Unlock() | 允许其他进程访问以前锁定的某个文件的全部或部分。 |
方法 | Write() | 使用从缓冲区读取的数据将字节块写入该流。 |
方法 | WriteByte() | 将一个字节写入文件流的当前位置。 |
4.使用示例:
using System;
using System.IO;
using System.Text;
namespace CSharpDemo
{
class Programma
{
static void Main(string[] args)
{
string path = @"E:\MyTest.txt";
if (File.Exists(path)) // 校验文件是否存在
{
File.Delete(path);
}
// 创建并写入文件
using (FileStream fs_write = File.Create(path))
{
byte[] info = new UTF8Encoding(true).GetBytes("123");
fs_write.Write(info, 0, info.Length);
byte[] info1 = new UTF8Encoding(true).GetBytes("456789");
fs_write.Write(info1, 0, info1.Length);
}
// 读取文件
using (FileStream fs_read = File.OpenRead(path))
{
byte[] byteArr = new byte[1024];
UTF8Encoding coding = new UTF8Encoding(true);
while (fs_read.Read(byteArr, 0, byteArr.Length) > 0)
{
Console.WriteLine(coding.GetString(byteArr));
}
}
Console.ReadKey();
}
}
}
using 语句作用: 执行语句,然后释放该资源;
若不使用using的形式写,则需要手动释放资源,使用 Dispose()或Close()方法;否则会抛异常 ("进程无法访问文件E:\MyTest.txt’,因为它正在被另一个进程使用) 。如下图:
PS:
当我们使用完了一个流之后,一定要调用fs.Close();方法去关闭流,关闭流会释放与它相关联的资源,允许其他应用程序为同一个文件设置流。这个操作也会刷新缓冲区。