zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C# 之 按字节读写文件

2023-09-11 14:20:51 时间

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 OpenTruncate会抛出异常,
如果文件存在 CreateNew会抛出异常;
CreateOpenOrCreate: 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获取流的长度,以字节为单位。[只读]
属性IsAsyncFileStream是异步打开的还是同步打开的。[只读]
属性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’,因为它正在被另一个进程使用) 。如下图:

1211

PS:
当我们使用完了一个流之后,一定要调用fs.Close();方法去关闭流,关闭流会释放与它相关联的资源,允许其他应用程序为同一个文件设置流。这个操作也会刷新缓冲区。