IO文件操作

简介

简单总结下IO文件读写的几种方式

  1. File类适合对不同的对象进行单一的处理。此种特殊情况下,静态方法的调用速度比较快,不用进行实例化
  2. FileInfo类适合用于对同一文件进行多种操作的情况。此种情况下,实例化后的对象不需要每次都寻找文件,可以直接对该文件进行操作
  3. File和FileInfo适合用于对文件的创建、删除、属性获取等操作
  4. FileStream适合处理非文本文件,不适合操作用字符数据构成的文本文件。FileStream类提供了对文件的低级而复杂的操作,因此能够实现更多高级的功能。
  5. StreamReader && StreamWriter适合处理对文本文件的读写操作,效率高一些
  6. BinaryReader && BinaryWriter适合处理二进制格式文件的读写操作

两个方式

  1. using
    • 实现对资源的释放,即使异常也会释放(dispose)
    • using不用dispose
  2. try…catch
    • 实现对异常的捕获处理

1. DriveInfo 驱动器

在Windows操作系统中,存储介质统称为驱动器,硬盘由于可以划分为多个区域,每一个区域称为一个驱动器。.NET Framework提供DriveInfo类和 DriveType枚举型,以方便在程序中直接使用驱动器。DriveInfo类的常用字段成员有DriveFormat(文件系统格式,如NTFS或FAT32)、DriveType(驱动器类型)、Name(驱动器名)、TotalSize(总空间)、TotalFreeSpace(获得驱动器可用空间)。常用的方法成员有GetDrives(获得可用驱动器列表)。

DriveType枚举型的枚举值有CDRom(光驱)、Fixed(硬盘)、Network(网络驱动器)和Removeable(软盘或U盘)等。例如,以下代码可以输出每一个硬盘驱动器的剩余空间信息。

DriveInfo[] drivers = DriveInfo.GetDrives();
foreach(DriveInfo driver in drivers)
{
    if(driver.DriveType == DriveType.Fixed && driver.DriveFormat == "NTFS")
    {
        Console.WriteLine("在{0}驱动器上还有{1}字节的剩余空间。", driver.Name, driver.AvailableFreeSpace);
    }
}
Console.ReadLine();

2. Directory && DirectoryInfo 目录

为了方便检索文件,需要在驱动器中先创建目录,然后把文件保存到这个目录中。在Windows操作系统中,目录又称文件夹。每个驱动器都有一个根目录,使用”\”表示,如”C:\”表示C驱动器的根目录。创建在根目录中的目录称为一级子目录。在一级子目录中创建的目录称为二级子目录,依此类推。文件系统的目录结构是一种树形结构。

.NET Framework提供了Directory类和DirectoryInfo类,以方便在程序中直接操作目录。

Directory类的常用方法成员有CreateDirectory(创建新目录)、Delete(删除目录)、Exists(判断目录是否存在)、Move(移动目录)、GetFiles(获得目录的文件列表)、GetDirectories(获得子目录列表)等。

DirectoryInfo类的常用字段成员有Name(提取目录名)、Exists(判断目录是否存在)、Parent(父目录)、Root(根目录)、MoveTo(移动目录)、GetFiles(获得目录的文件列表)、GetDirectories(获得子目录列表)等。例如,以下代码分别展现了Directory类和DirectoryInfo类的基本方法。

Directory.CreateDirectory(@"d:\C#程序设计");
if(Directory.Exists(@"d:\C#程序设计"))
{
    Console.WriteLine("创建成功");
}
Directory.Delete(@"d:\C#程序设计");
if (!Directory.Exists(@"d:\C#程序设计"))
{
    Console.WriteLine("删除成功");
}

DirectoryInfo dir = new DirectoryInfo(@"d:\C#程序设计");
if (!dir.Exists)
{
    dir.Create();
}
else
{
    Console.WriteLine("该目录已经存在");
}

3. File && FileInfo 文件

.NET Framework提供了File类和FileInfo类,以方便在程序中直接操作文件。File和FileInfo类位于System.IO命名空间,都可以用来实现创建、复制、移动、打开文件等操作。File类和FileInfo类与Directory类和DirectoryInfo类的工作方式相似。File类是一个静态类,可直接调用其方法成员。FileInfo类不是静态类,需要先创建实例。

  1. File
常用API 介绍
Open() 打开文件
Copy() 复制文件
Delete() 删除文件
Exists() 判断文件是否存在
Move() 移动文件
Replace() 替换文件
AppendAllText() 新建文件并添加文本
ReadAllText() 打开并读取文本内容
  1. FileInfo
    文件信息类FileInfo与File类不同,它虽然也提供类创建、复制、删除、移动和打开文件的方法,并且帮助创建FileStream对象,但是它提供的仅仅是实例方法
常用API 介绍
Name 提取文件名
Directory 所属目录
Exists 是否存在
Extension 文件扩展名
Length 文件长度
IsReadOnly 是否为只读
Open() 打开文件
Create() 创建文件
CopyTo() 复制到新文件
Delete() 删除文件
MoveTo() 移动文件
Replace() 替换文件
EnCrypt() 加密文件
Decrypt() 解密文件
4. 文件流概述

在.NET Framework中,文件和流是有区别的。文件是存储在磁盘上的数据集,它具有名称和相应的路径。当打开一个文件并对其进行读/写时,该文件就称为流(stream)。但是,流不仅仅是指打开的磁盘文件,还可以是网络数据。.Net Framework允许在内存中创建流。此外,在控制台应用程序中,键盘输入和文本显示都是流。流包括以下基本操作:

  • 读取(read):把数据从流传输到某种数据结构中,如输出到字符数组中。
  • 写入(write):把数据从某种数据结构传输到流中,如把字节数组中的数据传输到流中。
  • 定位(seek):在流中查找或重新定位当前位置。
5. FileStream 文件流类

文件流类FileStream公开了以文件为主的Stream,既支持同步读/写操作,也支持异步读/写操作,FileStream类的特点是操作字节和字节数组。这种方式不适合操作用字符数据构成的文本文件,适合处理非文本文件。FileStream类提供了对文件的低级而复杂的操作,因此能够实现更多高级的功能。

读操作:
  1. 创建流对象
  2. 定位流位置
  3. 读取到字节数组
  4. 编码,转换到字符或字符串
//要写入文件的字符数组
char[] m_cDataWrite = new char[100];
//包含要写入该流的数据的缓冲区
byte[] m_bDataWrite = new byte[100];
 
try
{
    //创建d:\file.txt的FileStream对象
    FileStream m_FileStream = new FileStream(@"d:\file.txt", FileMode.Open);
    //设置流当前位置为文件开始位置
    m_FileStream.Seek(0, SeekOrigin.Begin);
    //将文件的内容存到字节数组中(缓存)
    m_FileStream.Read(m_bDataWrite, 0, 100);               
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
}
 
//通过UTF-8编码方法将字符数组转换成字符数组
Decoder m_Dec = Encoding.UTF8.GetDecoder();
m_Dec.GetChars(m_bDataWrite, 0, m_bDataWrite.Length, m_cDataWrite, 0);
Console.WriteLine("Read from file Succeed!");
Console.WriteLine(m_cDataWrite);
写操作:
  1. 创建流对象
  2. 需要写入的字符数组
  3. 编码,转换到字节数组
  4. 设置流位置
  5. 写入,刷新
//要写入文件的字符数组
char[] m_cDataWrite = new char[100];
//包含要写入该流的数据的缓冲区
byte[] m_bDataWrite = new byte[100];           
           
try
{
    //创建d:\file.txt的FileStream对象
    FileStream m_FileStream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate);
    //将要写入的字符串转换成字符数组
    m_cDataWrite = "test filestream".ToCharArray();
 
    //通过UTF-8编码方法将字符数组转成字节数组
    Encoder m_Enc = Encoding.UTF8.GetEncoder();
    m_Enc.GetBytes(m_cDataWrite, 0, m_cDataWrite.Length, m_bDataWrite, 0, true);
 
    //设置流当前位置为文件开始位置
    m_FileStream.Seek(0, SeekOrigin.Begin);
    //将字节数组中的内容写入文件
    m_FileStream.Write(m_bDataWrite, 0, m_bDataWrite.Length);
    if (m_FileStream != null)
    {
        //清除此流的缓冲区,使得所有缓冲的数据都写入到文件中
        m_FileStream.Flush();
        m_FileStream.Close();
    }
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
}
Console.WriteLine("Write to File Succeed!");

6. StreamWriter && StreamReader

应用FileStream类需要许多额外的数据类型转换操作,十分影响效率。StreamWriter类允许直接将字符和字符串写入文件。下面演示其用法:

读操作
try
{
    //以绝对路径方式构造新的StreamReader对象
    StreamReader m_SR = new StreamReader(@"d:\file.txt");
 
    //用ReadToEnd方法将d:\file.txt中的数据全部读入到字符串m_Data中,并关闭StreamReader
    string m_Data = m_SR.ReadToEnd();
    m_SR.Close();
    Console.WriteLine(m_Data);
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
}
写操作
try
{
    //保留文件现有数据,以追加写入的方式打开d:\file.txt文件
    StreamWriter m_SW = new StreamWriter(@"d:\file.txt", true);
    //向文件写入新字符串,并关闭StreamWriter
    m_SW.WriteLine("Another File Operation Method");
    m_SW.Close();               
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
}

7. BinaryReader && BinaryWriter

BinaryReader类是和BinaryWriter类相对应的二进制数据读取类。它用特定的编码将基元数据类型(如:字符串类型)读作二进制值

读操作
FileStream m_FS = new FileStream(@"d:\data.dat", FileMode.Open, FileAccess.Read);
//通过文件流创建相应的BinaryReader
BinaryReader m_BR = new BinaryReader(m_FS);
//从d:\data.dat中读取数据
for(int i = 0; i < 11; i++)
{
    Console.WriteLine(m_BR.ReadInt32());
}
 
m_BR.Close();
m_FS.Close();
 
Console.ReadLine();
写操作

BinaryWriter类将基础数据(如:字符串)以二进制形式写入文件流中,并支持用特定的编码写入

FileStream m_FS = new FileStream(@"d:\data.dat", FileMode.Create);
//通过文件流创建相应的BinaryWriter
BinaryWriter m_BW = new BinaryWriter(m_FS);
for(int i = 0; i < 11; i++)
{
    //向d:\data.dat中写入数据
    m_BW.Write((int)i);
}
 
m_BW.Close();
m_FS.Close();

8. 综合应用
创建日志文件

日志文件的作用是记录程序运行事件。通常使用文本文件保存数据。日志文件需要程序自动创建,并在指定的事件发生时,使用特定的格式把事件的相关数据记录到日志文件中。

  • 创建FileStream类实例时,能够通过该类构造函数的参数,指定打开文件的方式和读/写访问的方式。通过指定打开方式,实现日志文件的自动创建。
  • 使用StreamWriter类实例写入文件时,因为部分数据可能由于系统缓慢而未能及时写入,所以在所有的写入操作完成后,需要调用Flush方法将缓冲区的文件内容更新到日志文件中。
  • 使用StreamWriter类实例写入文件时,写入的方式与Console类似,可以使用WriteLine向文件中写入一行文本数据。
const string _FILENAME = @"..\..\logfile.txt";
static void Main()
{
    //从指定的目录以打开或者创建的形式读取日志文件
    using (FileStream fs = new FileStream(_FILENAME, FileMode.OpenOrCreate, FileAccess.Write))
    {
        //创建日志文件的写入流
        StreamWriter sw = new StreamWriter(fs);
        //向日志文件写入日志信息
        Log("日志文件创建成功", sw);
        //关闭日志文件写入流
        sw.Close();
        Console.WriteLine("日志文件已创建");
    }
 
    //读取并显示日志文件
    using (StreamReader sr = new StreamReader(_FILENAME, Encoding.UTF8))
    {
        string strContent = sr.ReadToEnd();
        sr.Close();
        Console.WriteLine(strContent);
    }
 
    Console.ReadLine();
}
 
static void Log(String message, TextWriter tw)
{
    tw.Write("Log Entry:");
    tw.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
    tw.WriteLine(" :");
    tw.WriteLine(" :{0}", message);
            tw.WriteLine("----------------------------------");
            //将缓冲区中的内容更新到日志文件中
   tw.Flush();
}
对日志文件的读/写操作

日志文件的读/写和文本文件的读/写方法基本相同,日志文件除了使用StreamReader类和StreamWriter类的实例进行读/写外,还有一些记录事件的要求。例如,在写入数据时使用追加的方式、控制日志文件的大小等。

  • 使用FileInfo类实例获取日志文件的大小,实现当日志文件的大小超出指定范围时清空日志数据的功能。并使用该类实例的OpenWrite方法,创建FileStream类实例进行写入文件的操作,实现日志文件的自动创建功能。
  • 使用StreamWriter类中定义的Seek方法,将写入位置移动到文件末尾,实现将数据以追加方式写入日志文件的功能。
  • 使用StreamReader类中定义的Peek方法,判断读取器是否已经读到日志文件的末尾。
//表示日志文件路径及文件名称的字符串
const string FILENAME = @"..\..\logfile.txt";
static void Main(string[] args)
{
    //写入日志信息
    WriteLogFile(FILENAME, "日志信息一");
    //读取日志文件
    Console.WriteLine(ReadLogFile(FILENAME));
    Console.ReadLine();
}
 
static string ReadLogFile(string FileNameWithPath)
{
    //从指定的目录以打开或创建的形式读取日志文件
    FileStream fs = new FileStream(FileNameWithPath, FileMode.OpenOrCreate, FileAccess.Read);
    //定义输出字符串
    StringBuilder output = new StringBuilder();
    //初始化该字符串的长度为0
    output.Length = 0;
    //为上面创建的文件流创建读取数据流
    StreamReader read = new StreamReader(fs);
    //设置当前流的起始位置为文件流的起始点
    read.BaseStream.Seek(0, SeekOrigin.Begin);
    //读取文件
    while(read.Peek() > -1)
    {
        //取文件的一行内容并换行
        output.Append(read.ReadLine() + "\n");
    }
    //关闭释放读数据流
    read.Close();
    //返回读到的日志文件内容
    return output.ToString();
}
 
static void WriteLogFile(string FileNameWithPath, string Message)
{
    //定义文件信息对象
    FileInfo finfo = new FileInfo(FileNameWithPath);
    //判断文件是否存在以及是否大于2K
    if(finfo.Exists && finfo.Length > 2048)
    {
        //删除该文件
        finfo.Delete();
    }
    //创建只写文件流
    using(FileStream fs = finfo.OpenWrite())
    {
        //根据上面创建的文件流创建写数据流
        StreamWriter w = new StreamWriter(fs);
        //设置写数据流的起始位置为文件流的末尾
        w.BaseStream.Seek(0, SeekOrigin.End);
        //写入"Log Entry:"
        w.Write("Log Entry:");
        //写入系统的当前时间并换行
        w.Write("{0} {1} \r\n", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
        //写入日志内容并换行
        w.Write(Message + "\r\n");
        //写入-------------------------并换行
        w.Write("----------------------\r\n");
        //清空缓冲区内容,并把缓冲区内容写入基础流
        w.Flush();
        w.Close();
    }
}
复制文件

静态File类中提供了许多操作文件的方法,使用Copy方法复制文件是比较常见的一种操作,调用Copy方法时,可以使用overwrite参数指定是否覆盖文件。

  • 使用静态类File的Exists方法判断文件是否存在。
  • 使用静态类File的Copy方法实现复制文件的功能,当文件存在时,通过指定override参数覆盖原有文件。
  • 复制文件是系统操作,为了保证程序的稳定性,在复制文件的过程中需要捕获并处理异常。
//源文件路径及文件名
const string SOURCEFILENAME = @"..\..\myfile.txt";
//目标文件路径及文件名
const string DESTINATIONFILENAME = @"..\..\result.txt";
static void Main(string[] args)
{
    try
    {
        //判断源文件是否存在
        if(!File.Exists(SOURCEFILENAME))
        {
            Console.WriteLine("找不到源文件");
        }
        else if (File.Exists(DESTINATIONFILENAME))
        {
            Console.Write("目标文件已经存在,是否覆盖?(Y/N)");
            if(Console.ReadKey(false).Key == ConsoleKey.Y)
            {
                //覆盖文件
                File.Copy(SOURCEFILENAME, DESTINATIONFILENAME, true);
                Console.WriteLine("复制文件完成");
            }
            else
            {
                Console.WriteLine("取消复制文件");
            }
        }
        else
        {
            //直接复制
            File.Copy(SOURCEFILENAME, DESTINATIONFILENAME);
            Console.WriteLine("复制文件完成");
        }
    }
    catch (Exception)
    {
        Console.WriteLine("复制文件失败");
    }
    Console.ReadLine();
}

C# 文件操作(摘抄) - wangzhiliang - 博客园 (cnblogs.com)

你可能感兴趣的:(IO文件操作)