• 读写文件(二进制文件、文本文件、ini文件)


     读写文件(二进制文件、文本文件、ini文件)

    1.      文件和流

    文件(file)和流(stream)即有区别又有联系。文件是在各种媒质上(可移动磁盘、硬盘、CD 等)永久存储的数据的有序集合。它是一种进行数据读写操作的基本对象。通常情况下,文件按照树状目录进行组织,每个文件都有文件名、文件所在路径、创建时间、访问权限等属性。

    1)        流是字节序列的抽象概念,如文件、输入输出设备、内部进程通信管道或者TCP/IP套接字等均可以看成流。流提供一种向后备存储器写入字节和从后备存储器读取字节的方式。

    2)        除了和磁盘文件直接相关的文件流以外,还有多种其它类型的流,如分布在网络中、内存中和磁带中的流,分别称为网络流、内存流和磁带流。

    3)        所有表示流的类都是从抽象基类Stream继承的。

    流的操作有三类:

    A.        读取:从流中读取数据到变量中。

    B.        写入:把变量中的数据写入到流中。

    C.        定位:重新设置流的当前位置,以便随机读写。

    File类的静态方法主要是用于创建FileStream类。一个FileStream类的实例实际上代表一个磁盘文件,使用FileStream类对文件系统上的文件进行读取、写入、打开和关闭操作,并对其它与文件相关的操作系统句柄进行操作,如管道、标准输入和标准输出。读写操作可以指定为同步或异步操作。FileStream对输入输出进行缓冲,从而提高了系统的性能。

    1 与流相关类层次结构

    对于文件的读写,最常用的类如下:

     

    A.        FileStream(文件流):这个类主要用于在二进制文件中读写二进制数据——也可以读写任何文件。

    B.        StreamReader(流读取器)和StreamWriter(流写入器):这两个类是专门用于读写文本文件的。

    C.        BinaryReaderBinaryWrite:这两个类本身不执行流,而是提供其他对象的包装器以及对二进制数据进行额外的格式化。

    2.      文件的基本操作

    2.1.   二进制文件

    2.1.1.       打开

    读写二进制数据通常使用FileStream类。要构造其实例,需要以下4条信息:

    A.        要访问的文件。

    B.        表示如何打开文件的模式——指定在文件不存在时是否创建该文件,并确定是保留还是改写现有文件的内容

    C.        表示访问文件的方式——对文件执行的操作(只读、只写或者读写)。

    D.       共享访问——其它线程所具有的对该文件的访问类型(独占文件、共享读或者共享写)。

    打开指定路径上的FileStream,可以使用File类的Open方法或OpenRead方法或OpenText方法。

    其中Open打开文件的方式有三种,如下表所示:

    名称

    说明 

    File.Open (String, FileMode)

    打开指定路径上的 FileStream,具有读/写访问权限。

    File.Open (String, FileMode, FileAccess)

    以指定的模式和访问权限打开指定路径上的 FileStream

    File.Open (String, FileMode, FileAccess,

    FileShare)

    打开指定路径上的 FileStream,具有指定的读、写或读/写访问模式以及指定的共享选项。

    FileStream(String, FileMode, FileAccess)

    等各种FileStream构造函数

    FileStream构造函数与file.Open打开效果一致。

           FileAccess默认值为FileAccess.ReadWriteFileShare默认值为FileShare.Read

    文件操作方式说明.Net2.0 SDK定义)

    public enum FileMode    // 指定操作系统打开文件的方式

    {

    // 指定操作系统应创建新文件。此操作需要FileIOPermissionAccess.Write权限如果文件已存在,

          / / 则将引发System.IO.IOException      

        CreateNew = 1,

    // 指定操作系统应创建新文件。如果文件已存在,它将被改写。这要求FileIOPermissionAccess.Write权限。

    // System.IO.FileMode.Create等效于这样的请求:如果文件不存在,则使用 FileMode.CreateNew

    // 否则使用FileMode.Truncate

        Create = 2,

    // 指定操作系统应打开现有文件。打开文件的能力取决于 System.IO.FileAccess 所指定的值。

    // 如果该文件不存在,则引发 System.IO.FileNotFoundException

        Open = 3,

    // 指定操作系统应打开文件(如果文件存在);否则,应创建新文件。如果用 FileAccess.Read 打开文件,

    // 则需要 System.Security.Permissions.FileIOPermissionAccess.Read。如果文件访问为FileAccess.Write

    // FileAccess.ReadWrite,则需要 System.Security.Permissions.FileIOPermissionAccess.Write。如果文件访问为

              // FileAccess.Append,则需要 System.Security.Permissions.FileIOPermissionAccess.Append

        OpenOrCreate = 4,

    // 指定操作系统应打开现有文件。文件一旦打开,就将被截断为零字节大小。此操作需要

    // FileIOPermissionAccess.Write。试图从使用Truncate 打开的文件中进行读取将导致异常

        Truncate = 5,

    // 打开现有文件并查找到文件尾,或创建新文件。FileMode.Append 只能同 FileAccess.Write 一起使用。

    // 任何读尝试都将失败并引发System.ArgumentException

        Append = 6,

    }

        public enum FileAccess         // 定义用于控制对文件的读访问、写访问或读/写访问的常数

        {

            // 对文件的读访问。可从文件中读取数据。同 Write 组合即构成读写访问权

            Read = 1,

            // 文件的写访问。可将数据写入文件。同 Read 组合即构成读/写访问权

            Write = 2,

            // 对文件的读访问和写访问。可从文件读取数据和将数据写入文件

            ReadWrite = 3,

    }

    public enum FileShare    // 包含用于控制其他 System.IO.FileStream 对象对同一文件可以具有的访问类型的常数

    {

            // 谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败

        None = 0,

            // 允许随后打开文件读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程

         // 或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件

        Read = 1,

            // 允许随后打开文件写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程

          // 或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件

        Write = 2,

            //允许随后打开文件读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请

          //求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件

        ReadWrite = 3,

            // 允许随后删除文件

        Delete = 4,

            // 使文件句柄可由子进程继承。Win32 不直接支持此功能

        Inheritable = 16,

    }

    2.1.2.       移动

    // 摘要: 将该流的当前位置设置为给定值。

    // offset: 相对于 origin 的点,从此处开始查找。

    // origin: 使用 System.IO.SeekOrigin 类型的值,将开始位置、结束位置或当前位置指定为 origin 的参考点。

    // 返回结果: 流中的新位置。

    public override long Seek(long offset, SeekOrigin origin);       

    public enum SeekOrigin        // 提供表示流中的参考点以供进行查找的字段

    {

    Begin = 0,             // 指定流的开头

    Current = 1,           // 指定流内的当前位置

    End = 2,                // 指定流的结尾

    }

    2.1.3.      

    // 摘要: 从文件中读取一个字节,并将读取位置提升一个字节。

    // 返回结果: 转换为 int 的字节,或者如果从流的末尾读取则为 -1

    public override int ReadByte();

    // 摘要: 从流中读取字节块并将该数据写入给定缓冲区中。

    // offset: rray 中的字节偏移量,从此处开始读取。

    // array: 当此方法返回时,包含指定的字节数组,数组中 offset (offset + count - 1) 之间的值被从当前源中读取的           // 字节替count: 最多读取的字节数。

    // 返回结果: 读入 buffer 中的总字节数。如果当前的字节数没有所请求那么多,则总字节数可能小于所请求的字节

    // 数;或者如果已到达流的末尾,则为零。

    public override int Read(byte[] array, int offset, int count);

    2.1.4.      

    // 摘要: 将一个字节写入文件流的当前位置

    // value: 要写入流的字节

    public override void WriteByte(byte value);

    // 使用从缓冲区读取的数据将字节块写入该流

    // offset:  array 中的从零开始的字节偏移量,从此处开始将字节复制到当前流

    // array: 包含要写入该流的数据的缓冲区

    // count: 要写入当前流的最大字节数

    public override void Write(byte[] array, int offset, int count);

    2.1.5.       关闭

    // 释放由Stream使用的所有资源

    public void Stream.Dispose ();

    // 关闭当前流并释放与之关联的所有资源

    public void Stream.Close();

    // 释放由FileStream占用的非托管资源,还可以另外再释放托管资源

    // disposing: true则释放托管资源和非托管资源;为fals 则仅释放非托管资源

    protected override void FileStream.Dispose(bool disposing)

    2.2.        文本文件

    理论上,可以使用FileStream类读写显示文本文件。通常使用StreamReaderStreamWrite类更方便的读写文本,因为它们执行的方法可以根据流的内容,自动检测出停止读取文本较方便的位置。特别是:

    A.       可以一次读写一行文本(StreamReader.ReadLine()StreamWriter.WriteLine())

    B.       支持文本文件中使用的各种编码方式。

    2.2.1.       StreamReader

    读文本文件一般使用StreamReader,构造实例可通过完整文件名、stream系列对象,可指定编码

    格式。默认XX编码格式。

    名称

    说明 

    StreamReader(string path)

    为指定的文件名初始化 StreamReader 类的新实例。

    StreamReader(Stream stream)

    为指定的流初始化 StreamReader 类的新实例

    StreamReader(string path,

    Encoding encoding)

    用指定的字符编码,为指定的文件名初始化 StreamReader 类的一个新实例。

    StreamReader(Stream stream,

    Encoding encoding)

    用指定的字符编码为指定的流初始化 StreamReader 类的一个新实例。

           Encoding包含静态属性:

    ü         ASCII

    ü         Unicode

    ü         UTF7

    ü         UTF8

    ü         UTF32

    ü         BigEndianUnicode

    ü         Default

    a> 从一个FileInfo实例中获得StreamReader:

           FileInfo info = new FileInfo(@”C:\ReadMe.txt”);

           StreamReader sr = info.OpenText();     //创建使用 UTF8 编码、从现有文本文件中进行读取StreamReader

    b>       从一个FileStream实例创建StreamReader:

    FileStream fs = new FileStream(@“C:\ReadMe.txt”,FileMode.Open,FileAccess.Read, FileShare.None)

    StreamReader sr = new StreamReader(fs);

     

    // 摘要: 从当前流中读取一行字符并将数据作为字符串返回。

    // 返回结果: 输入流中的下一行;如果到达了输入流的末尾,则为 null

    public override string ReadLine();

    // 摘要: 从流的当前位置到末尾读取流。

    // 返回结果: 字符串形式的流的其余部分(从当前位置到末尾)。如果当前位置位于流的末尾,则返回空字符串 ("")

    public override string ReadToEnd();

    // 摘要: 读取输入流中的下一个字符并使该字符的位置提升一个字符。

    // 返回结果: 输入流中表示为 System.Int32 对象的下一个字符。如果不再有可用的字符,则为 -1

    public override int Read();

    // 摘要: 返回下一个可用的字符,但不使用它。

    // 返回结果: 下一个要读取的字符,或者如果没有更多的可用字符或此流不支持查找,则为 -1

    public override int Peek();

    // 摘要: index 开始,从当前流中将最多的 count 个字符读入 buffer

             // count: 最多读取的字符数。

            // buffer: 此方法返回时,包含指定的字符数组,该数组的 index (index + count - 1) 之间的值由从当前源中读取的

    // 字符替换。

            // index: 开始写入的 buffer 的索引。

           // 返回结果: 已读取的字符数,或者如果已到达流的末尾并且未读取任何数据,则为 0。该数小于或等于 count 参数,

    // 具体取决于流中是否有可用的数据。

    public override int Read(char[] buffer, int index, int count);

     

    // 摘要: 关闭 System.IO.StreamReader 对象和基础流,并释放与读取器关联的所有系统资源。

        public override void Close();

    2.2.2.       StreamWriter

    写文本文件一般使用StreamWriter,构造实例可通过完整文件名、stream系列对象,可指定编码

    格式。

    a> 直接构造StreamWriter:

           StreamWriter sw = new StreamWriter(@”C:\ReadMe.txt”);       //默认使用 UTF8 编码

             StreamWriter sw = new StreamWriter(@”C:\ReadMe.txt”, true, Encoding.ASCII);  

    b> 从一个FileStream实例中获得StreamWriter:

           FileStream fs = new FileStream(@”C:\R.txt”,FileMode.CreateNew,FileAccess.Write, FileShare.Read);

           StreamWriter sw = new StreamWriter(fs);

    c> 从一个FileInfo实例中获得StreamReader,创建一个新文件,并开始写数据:

           FileInfo info = new FileInfo(@”C:\ReadMe.txt”);

           StreamWriter sw = infoCreateText();    //创建使用 UTF8 编码、从现有文本文件中进行读取StreamReader

     

    // 摘要: 用指定的编码及默认缓冲区大小,为指定的流初始化 System.IO.StreamWriter 类的新实例。

             // encoding:  要使用的字符编码。

    // stream: 要写入的流。

    public StreamWriter(Stream stream, Encoding encoding);

    // 摘要: 使用默认编码和缓冲区大小,为指定路径上的指定文件初始化 System.IO.StreamWriter 类的新实例。如果该

    // 文件存在,则可以将其改写或向其追加。如果该文件不存在,则此构造函数将创建一个新文件。

    // append: 确定是否将数据追加到文件。如果该文件存在,并且 append false,则该文件被改写。如果该文件存在,

    // 并且 append true,则数据被追加到该文件中。否则,将创建新文件。

    // path: 要写入的完整文件路径。

    public StreamWriter(string path, bool append);

    public StreamWriter(Stream stream, Encoding encoding, int bufferSize);

    StreamWriter(string path, bool append, Encoding encoding);

    public StreamWriter(string path, bool append, Encoding encoding, int bufferSize);

     

    // 摘要: 将字符写入流。

    // value: 要写入文本流中的字符。

    public override void Write(char value);

    // 摘要: 将字符数组写入流。

    // buffer:  包含要写入的数据的字符数组。如果 buffer null,则不写入任何内容。

    public override void Write(char[] buffer)

    public override void Write(string value);

    public override void Write(char[] buffer, int index, int count);

     

    // 摘要: 关闭当前的 StreamWriter 对象和基础流。

    public override void Close();

     

    2.3.        Ini文件

    操作ini文件,需要特殊的winApi,下面介绍:

    // replaces the keys and values for the specified section in an initialization file.
    // If the function succeeds, the return value is nonzero.
    [DllImport("kernel32")]
    public static extern bool WritePrivateProfileSection(
           LPCTSTR lpAppName,            // [in] section name
           LPCTSTR lpString,                // [in] data
           LPCTSTR lpFileName             // [in] file name
    );
    // retrieves all the keys and values for the specified section of an initialization file.
    // return the number of characters copied to the buffer, not including the terminating null character

    [DllImport("kernel32", CharSet = CharSet.Unicode)]

    public static extern int GetPrivateProfileSection(
                  LPCTSTR lpAppName,     // [in] section name
           LPTSTR lpReturnedString,   // [out] return buffer
           DWORD nSize,                       // [in] size of return buffer
           LPCTSTR lpFileName       // [in] initialization file name
            );

    // retrieves the names of all sections in an initialization file.

    // return the number of characters copied to the specified buffer, not including the terminating null character

           [DllImport("kernel32", CharSet = CharSet.Unicode)]
        public static extern int GetPrivateProfileSectionNames(
                   LPTSTR lpszReturnBuffer,        // [out]return buffer
                  DWORD nSize,              // [in]size of return buffer
                  LPCTSTR lpFileName         // [in] initialization file name
            );

    // copies a string into the specified section of an initialization file.

    // If the function successfully copies the string to the initialization file, the return value is nonzero.

    [DllImport("Kernel32", CharSet = CharSet.Unicode)]

        public static extern bool WritePrivateProfileString (
                  LPCTSTR lpAppName,      // [in] section name
                  LPCTSTR lpKeyName,      // [in] key name
           LPCTSTR lpString,        // [in] string to add
                  LPCTSTR lpFileName       // [in] initialization file

    );

    // retrieves a string from the specified section in an initialization file

    // The return value is the number of characters copied to the buffer, not including the terminating null character.

    [DllImport("kernel32", CharSet = CharSet.Unicode)]

    public static extern int GetPrivateProfileString (

      LPCTSTR lpAppName,             // [in] section name

      LPCTSTR lpKeyName,             // [in] key name

      LPCTSTR lpDefault,                 // [in] default string

      LPTSTR lpReturnedString,             // [out] destination buffer

      DWORD nSize,                    // [in] size of destination buffer

      LPCTSTR lpFileName               // [in] initialization file name

    );

    // retrieves an integer associated with a key in the specified section of an initialization file.

    // The return value is the integer equivalent of the string following the specified key name in the specified initialization file.

    [DllImport("kernel32", CharSet = CharSet.Unicode)]

    public static extern int GetPrivateProfileInt(

    LPCTSTR lpAppName,              // [in] section name

    LPCTSTR lpKeyName,              // [in] key name

    INT nDefault,                        // [in] return value if key name not found

    LPCTSTR lpFileName                // initialization file name

    );

     

  • 相关阅读:
    关于中间件(Middleware)的理解
    强类型约束的中间件(IMiddleware)
    常规中间件(Conventional Middleware) 之 自定义中间件
    常规中间件(Conventional Middleware) 之 内联中间件(in-line middleware)
    git 遴选(cherry-pick)
    sql转linq
    python知识体系
    when 的使用
    关于联表查询时NULL值的处理
    $project 选择要显示的字段
  • 原文地址:https://www.cnblogs.com/fyhui/p/2162000.html
Copyright © 2020-2023  润新知