欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NET Core C# 中级篇2-7 文件操作

程序员文章站 2022-08-02 10:57:25
.NET Core CSharp 中级篇2 7 本节内容为文件操作 简介 文件操作在我们C 里还是比较常见的,例如我们读取Excel、Txt文件的内容,在程序中,这些文件都是以流的方式读取进入我们内存中,本节内容会详细的讲解有关文件的操作的方法。 我们从最大的驱动器开始往文件这个最小的开始讲解 驱动 ......

.net core csharp 中级篇2-7

本节内容为文件操作

简介

文件操作在我们c#里还是比较常见的,例如我们读取excel、txt文件的内容,在程序中,这些文件都是以流的方式读取进入我们内存中,本节内容会详细的讲解有关文件的操作的方法。

我们从最大的驱动器开始往文件这个最小的开始讲解

驱动器读取

在windows操作系统中,存储介质统称为驱动器,硬盘由于可以划分为多个区域,每一个区域称为一个驱动器。.net提供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();

目录

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

.net提供了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("该目录已经存在");
}

文件

文件的操作主要是分为两个类,一个是file类,一个是fileinfo类。file和fileinfo类位于system.io命名空间,都可以用来实现创建、复制、移动、打开文件等操作。file类和fileinfo类与directory类和directoryinfo类的工作方式相似。file类是一个静态类,可直接调用其方法成员。fileinfo类不是静态类,需要先创建实例。

file类

file类是一个文件的基本操作类,提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建 filestream 对象。里面包含的大多都是实际操作文件的方法,我用一个列表表示它内部常用的方法

  • open(string path, filemode mode)+3重载 打开指定路径文件
  • create(string path)+3重载,在指定路径创建文件,可以指定缓冲区大小
  • copy(string sourcefilename, string destfilename),复制文件
  • delete(string path),删除文件
  • exists(),判断文件是否存在
  • move(string sourcefilename, string destfilename),移动文件
  • replace(string sourcefilename,string destinationfilename,
    string destinationbackupfilename),替换文件
  • appendalltext(string path, string contents)新建文件并添加文本
  • readalltext(string path, encoding encoding)+2重载,打开并读取文本内容(可以指定打开的编码格式)

这些方法的使用也是非常简单,例如:

string path = @"e:\test.txt";
//以路径为参数创建文件
file.create(path);

更多的使用你最好自己去尝试,我们这几节的内容都是一些常用的类和方法的实际运用,并没有过多的知识点,你只需要按着这里的操作一直尝试即可。

fileinfo类

fileinfo类也可以对文件进行操作,文件信息类fileinfo与file类不同,它虽然也提供类创建、复制、删除、移动和打开文件的方法,并且帮助创建filestream对象,但是它提供的仅仅是实例方法他是我们最常用的文件操作类。

它里面含有的属性有:

  • name 提取文件名
  • directory 所属目录
  • exists 是否存在(继承自父类filesysteminfo)
  • extension 文件扩展名
  • length 文件长度
  • isreadonly 是否为只读

常用的方法和file类类似,这里添加几个之前没有讲过的

  • encrypt() 加密文件
  • decrypt() 解密文件
  • copyto() 复制到新文件
  • moveto() 移动文件

与文件类file和文件夹类directory相比,文件信息类fileinfo和文件夹信息类directoryinfo具有其大部分功能。

  • file类和directory类适合对不同的对象进行单一的处理。此种特殊情况下,静态方法的调用速度比较快,不用进行实例化。
  • fileinfo类和directoryinfo类适合用于对同一文件或文件夹进行多种操作的情况。此种情况下,实例化后的对象不需要每次都寻找文件,可以直接对该文件进行操作。

文件流

文件流对我们而言是一个陌生的概念,事实上,你仔细思考一下,我们是如何通过file类和fileinfo类读取文件中的内容呢?它其实就是以文件流的形式进行读写。流包括以下基本操作:

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

在c#中,所有的流操作都继承于stream类,stream类的主要属性有

  • canread(是否支持读取)
  • canseek(是否支持查找)
  • cantimeout(是否可以超时)
  • canwrite(是否支持写入)
  • length(流的长度)
  • position(获取或设置当前流中的位置)
  • readtimeout(获取或设置读取操作的超时时间)
  • writetimeout(获取或设置写操作的超时时间)

主要方法有

  • beginread(开始异步读操作)
  • beginwrite(开始异步写操作)
  • close(关闭当前流)
  • endread(结束异步读操作)
  • endwrite(结束异步写操作)
  • flush(清除流的所有缓冲区并把缓冲数据写入基础设备)
  • read(读取字节序列)
  • readbyte(读取一个字节)
  • seek(设置查找位置)
  • write(写入字节序列)
  • writebyte(写入一个字节)。

filestream、memorystream和bufferedstream类

文件流类filestream以流的形式读、写、打开、关闭文件。另外,它还可以用来操作诸如:管道、标准输入/输出等其他与文件相关的操作系统句柄。

内存流memorystream类用来在内存中创建流,以暂时保持数据,因此有了它就无须在硬盘上创建临时文件。它将数据封装为无符号的字节序列,可以直接进行读、写、查找操作。

缓冲流bufferedstream类表示把流先添加到缓冲区,再进行数据的读/写操作。缓冲区是存储区中用来缓存数据的字节块。使用缓冲区可以减少访问数据时对操作系统的调用次数,增强系统的读/写功能。

注意,filestream类也有缓冲功能,在创建filestream类的实例时,只需要指定缓冲区的大小即可。

示例

//要写入文件的字符数组
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!");

streamreader和streamwriter类

流读取器streamreader类用来以一种特定的编码(如:utf-8)从字节流中读取字符,流写入器streamwriter类用来以一种特定的编码(如:utf-8)向流中写入字符。streamreader和streamwriter类一般用来操作文本文件。

示例

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);
         }
  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);
}

binaryreader和binarywriter类

binaryreader类用特定的编码将基元数据类型读作二进制。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();


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();

reference

《c# 编程兵书》第11章 张志强 胡君 编著

如果我的文章帮助了您,请您在github.netcoreguide项目帮我点一个star,在博客园中点一个关注和推荐。

github

bilibili主页

warrenryan'sblog