读写文件(二进制文件、文本文件、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

);

 

原文地址:https://www.cnblogs.com/fyhui/p/2162000.html