文件处理技术

来源:互联网 发布:14款新帝豪安装软件 编辑:程序博客网 时间:2024/05/17 08:11

文件是在应用程序的实例之间存储数据的一种便利方式,也可以用于在应用程序之间传输数据。文件可以存储用户和应用程序配置,以便在下次运行应用程序时检索它们。定界的文本文件(例如用逗号分隔的文件)由许多旧系统使用;为了与这些旧系统进行交互,还需要了解如何处理定界数据。.NET Framework 提供的工具可以在应用程序中有效地使用文件。

一、流:

在.NET Framework 中进行的所有输入和输出工作都要用到流(stream)。流是序列化设备(serialdevice)的抽象表示。序列化设备可以以线性方式存储数据,并可以按同样的方式访问:一次访问一个字节。

此设备可以是磁盘文件、网络通道、内存位置或其他支持以线性方式读写的对象。把设备变成抽象的,就可以隐藏流的底层目标和源。这种抽象的级别支持代码重用,允许编写更通用的例程,因为不必担心数据传输方式的特性。因此,当应用程序从文件输入流、网络输入流或其他流中读取数据时,就可以转换并重用类似的代码。而且,使用文件流还可以忽略每种设备的物理机制,无需担心硬盘头或内存分配问题。

有两种类型的流:

l 1)输出流:当向某些外部目标写入数据时,就要用到输出流。这可以是物理磁盘文件、网络位置、打印机或另一个程序。理解流编程技术可以带来许多高级应用。

l 2)输入流:用于将数据读入程序可以访问的内存或变量中。到目前为止,我们使用的最常见的输入流形式是键盘。输入流可以来自任何源,在此主要关注读取磁盘文件。适用于读/写磁盘文件的概念也适用于大多数设备。

二、用于输入和输出的类:

System.IO 包含用于在文件中读写数据的类,必须在C#应用程序中引用此名称空间才能访问这些类,而无需完全限定类型名。

1.File类和Directory类:

File 和Directory 实用类提供了许多静态方法,用于处理文件和目录。这些方法可以移动文件、查询和更新特性,创建FileStream 对象。可以在类上调用静态方法,而无需创建它们的实例。

File 类的一些最常用的静态方法:

Copy() 将文件从源位置复制到目标位置

Create() 在指定的路径上创建文件

Delete() 删除文件

Open() 返回指定路径上的FileStream 对象

Move() 将指定的文件移动到新位置。可以在新位置为文件指定不同的名称

Directory 类的一些常用的静态方法:

CreateDirectory() 创建具有指定路径的目录

Delete() 删除指定的目录及其中的所有文件

GetDirectories() 返回表示指定目录下的目录名的string 对象数组

EnumerateDirectories() 与GetDirectories()类似,但返回IEnumerable<string>集合

GetFiles() 返回在指定目录中的文件名的string 对象数组

EnumerateFiles() 与GetFiles()类似,但返回文件名的IEnumerable<string>集合

GetFileSystemEntries() 返回在指定目录中的文件和目录名的string 对象数组

EnumerateFileSystemEntries() 与GetFileSystemEntries()类似,但返回文件和目录名的IEnumerable<string>集合

Move() 将指定的目录移到新位置。可以在新位置为文件夹指定一个新名称

2.FileInfo类:

FileInfo 类不像File 类,它不是静态的,没有静态方法,仅可用于实例化的对象。FileInfo 对象表示磁盘或网络位置上的文件。提供文件路径,就可以创建一个FileInfo 对象:

FileInfo aFile = new FileInfo(@"C:\Log.txt");

(还记得@的用法吗,字符串的前缀@表示这个字符串应逐个字符地解释,“\”解释为“\”,而不解释为转义字符。如果没有@前缀,就需要使用“\\”代替“\”,以免把这个字符解释为转义字符。)

FileInfo 类提供的许多方法类似于File 类的方法,但是因为File 是静态类,它需要一个字符串参数为每个方法调用指定文件位置。(具体的属性和方法参考官方API)

那么什么情况下用File什么情况下用FileInfo合适:

1)如果仅进行单一方法调用,则可以使用静态File 类上的方法。在此,单一调用要快一些,因为.NET Framework 不必实例化新对象,再调用方法。

2)如果应用程序在文件上执行几种操作,则实例化FileInfo 对象并使用其方法就更好一些。

这节省时间,因为对象已在文件系统上引用正确的文件,而静态类必须每次都寻找文件。

3)FileInfo 类也提供了与底层文件相关的属性,其中一些属性可以用来更新文件,其中很多属性都继承于FileSystemInfo,所以可应用于File 和Directory 类。

FileInfo 对象本身不表示流。要读写文件,必须创建Stream 对象。FileInfo 对象提供了几个返回实例化Stream 对象的方法来帮助做到这点。

3.DirectoryInfo类:

DirectoryInfo 类的作用类似于FileInfo 类,它是一个实例化的对象,表示计算机上的单一目录。同FileInfo 类一样,在Directory 和DirectoryInfo 之间可以复制许多方法调用。选择使用File 或FileInfo方法的规则也适用于DirectoryInfo 方法:

l 1)如果进行单一调用,就使用静态Directory 类。

l 2)如果进行一系列调用,则使用实例化的DirectoryInfo 对象。

4.FileStream对象:

FileStream对象,也称为文件流对象,用于为文件的读写操作提供通道。在文件读写操作中,首先要实例化一个FileStream类对象。

FileStream 对象表示在磁盘或网络路径上指向文件的流。这个类提供了在文件中读写字节的方法,但经常使用StreamReader 或StreamWriter 执行这些功能。这是因为FileStream 类操作的是字节和字节数组,而Stream 类操作的是字符数据。字符数据易于使用,但是有些操作,如随机文件访问(访问文件中间某点的数据),就必须由FileStream 执行。

有几种方法可以创建FileStream 对象。构造函数具有许多不同的重载版本(FileSteam类的构造函数提供了十几种重载),最简单的构造函数仅有两个参数,即文件名和FileMode 枚举值。

FileStream aFile = new FileStream(filename, FileMode.<Member>);

FileMode 枚举包含几个成员,指定了如何打开或创建文件。另一个常用的构造函数如下:

FileStream aFile = new FileStream(filename, FileMode.<Member>, FileAccess.<Member>);

第三个参数是FileAccess 枚举的一个成员,它指定了流的作用。FileAccess 枚举的成员如下:

Read 打开文件,用于只读

Write 打开文件,用于只写

ReadWrite 打开文件,用于读写

FileMode:创建模式。例如创建一个新文件还是打开一个现有的文件。如果打开一个现有的文件,写入操作是覆盖文件原来的内容,还是添加到文件的末尾。

File 和FileInfo 类都提供了OpenRead()和OpenWrite()方法,更易于创建FileStream 对象。前者打开了只读访问的文件,后者只允许写入文件。这些都提供了快捷方式,因此不FileStream 构造函数的参数形式提供前面所有的信息。例如,下面的代码行打开了用于只读访问的Data.txt 文件:

FileStream aFile = File.OpenRead("Data.txt");

下面的代码执行同样的功能:

FileInfo aFileInfo = new FileInfo("Data.txt");

FileStream aFile = aFileInfo.OpenRead();

介绍三个主要的方法:

1.文件位置:

FileStream 类维护内部文件指针,该指针指向文件中进行下一次读写操作的位置。在大多数情况下,当打开文件时,它就指向文件的开始位置,但是可以修改此指针。这允许应用程序在文件的任何位置读写,随机访问文件,或直接跳到文件的特定位置上。当处理大型文件时,这非常省时,因为马上可以找到正确的位置。

实现此功能的方法是Seek()方法,它有两个参数:第一个参数规定文件指针移动距离(以字节为单位)。第二个参数规定开始计算的起始位置,用SeekOrigin 枚举的一个值表示。SeekOrigin 枚举包含3 个值:Begin、Current 和End。

例如,下面的代码行将文件指针移动到文件的第8 个字节,其起始位置就是文件的第1 个字节:

aFile.Seek(8, SeekOrigin.Begin);

下面的代码行将指针从当前位置开始向前移动2 个字节。如果在上面的代码行之后执行下面的代码,文件指针就指向文件的第10 个字节:

aFile.Seek(2, SeekOrigin.Current);

注意读写文件时,文件指针会随之改变。在读取了10 个字节之后,文件指针就指向被读取的第10 个字节之后的字节。也可以规定反向查找位置,这可以与SeekOrigin.End 枚举值一起使用,查找靠近文件末端的位置。下面的代码会查找文件中倒数第5 个字节:

aFile.Seek(-5, SeekOrigin.End);

2.读取数据:

使用 FileStream 类读取数据不像使用StreamReader 类读取数据那样容易。这是因为FileStream 类只能处理原始字节(raw byte)。处理原始字节的功能使FileStream 类可以用于任何数据文件,而不仅仅是文本文件。通过读取字节数据,FileStream 对象可以用于读取诸如图像和声音的文件。这种灵活性的代价是,不能使用FileStream 类将数据直接读入字符串,而使用StreamReader类却可以这样处理。但是有几种转换类可以很容易地将字节数组转换为字符数组,或者将字符数组转换为字节数组。

FileStream.Read()方法是从FileStream 对象所指向的文件中访问数据的主要手段。这个方法从文件中读取数据,再把数据写入一个字节数组。它有三个参数:第一个参数是传入的字节数组,用来接受FileStream 对象中的数据。第二个参数是字节数组中开始写入数据的位置:它通常是0,表示从数组开端向文件中写入数据。最后一个参数指定从文件中读出多少字节。

eg:

static void Main(string[] args)

{

byte[] byData = new byte[200];

char[] charData = new Char[200];

try

{

FileStream aFile = new FileStream("../../Program.cs", FileMode.Open);

aFile.Seek(113, SeekOrigin.Begin);

aFile.Read(byData, 0, 200);

}

//文件I/O 涉及到的所有操作都可以抛出IOException 类型的异常。所有产品代码都必须包含错误处理,尤其是处理文件系统时更是如此。

catch (IOException e)

{

Console.WriteLine("An IO exception has been thrown!");

Console.WriteLine(e.ToString());

Console.ReadKey();

return;

}

//从文件中存储了字节数组后,就需要将其转换为字符数组,以便在控制台显示它。为此,使用System.Text 名称空间的Decoder 类。此类用于将原始字节转换为更有用的项,比如字符

Decoder d = Encoding.UTF8.GetDecoder();

d.GetChars(byData, 0, byData.Length, charData, 0);

Console.WriteLine(charData);

Console.ReadKey();

}

这些代码基于UTF-8 编码模式创建了Decoder 对象。这就是Unicode 编码模式。然后调用GetChars()方法,此方法提取字节数组,将它转换为字符数组。完成之后,就可以将字符数组输出到控制台。

3.写入数据:

向随机访问文件中写入数据的过程与从中读取数据非常类似。首先需要创建一个字节数组;最简单的办法是首先构建要写入文件的字符数组。然后使用Encoder 对象将其转换为字节数组,其用法非常类似于Decoder 对象。

Encoder e = Encoding.UTF8.GetEncoder();

e.GetBytes(charData, 0, charData.Length, byData, 0, true);

在GetBytes()方法中可以完成这些工作,它可以将字符数组转换为字节数组,并将字符数组作为第一个参数(本例中的charData),将该数组中起始位置的下标作为第二个参数(0 表示数组的开头)。第三个参数是要转换的字符数量(charData.Length,charData 数组中的元素个数)。第四个参数是在其中放入数据的字节数组(byData),第五个参数是在字节数组中开始写入位置的索引(0 表示byData 数组的开头)。最后一个参数决定在结束后Encoder 对象是否应该更新其状态,即Encoder 对象是否仍然保留它原来在字节数组中的内存位置。这有助于以后调用Encoder 对象,但是当只进行单一调用时,这就没有什么意义。最后对Encoder 的调用必须将此参数设置为true,以清空其内存,释放对象,用于垃圾回收。

原创粉丝点击