第二章
输入/输出 (I/O)
在本章,你将学习.NET Framework中的输入输出是如何工作的。I/O基本工作是访问系统文件和文件目录,读写流工作,使用系统流和使用独立存储。
本章中的考试目标:
■使用系统类(引用System.IO命名空间)访问文件和文件夹。
?File类和FileInfo类
?Directory类和DirectoryInfo类
?DriveInfo类和DriveType枚举
?FileSystemInfo类和FileSystemWatcher类
?Path类
?ErrorEventArgs类和ErrorEventHandler委托
?RenamedEventArgs 类 和 RenamedEventHandler 委托
■管理字节流和使用Stream类。(引用System.IO 命名空间)
? FileStream 类
? Stream 类(不读和写入类是一个单独的目标)
? MemoryStream 类
? BufferedStream 类
■ .NET Framework数据应用使用Reader 和 Writer 类(引用System.IO命名空间)
? StringReader 类 和 StringWriter 类
? TextReader 类 和 TextWriter 类
? StreamReader 类 和 StreamWriter 类
? BinaryReader 类 和 BinaryWriter 类
■ 压缩或解压缩流信息在.NET Framework 应用程序中的 (参阅 System.IO.Compression 命名空间),并提高应用程序的安全性通过使用独立的存储的数据。
? IsolatedStorageFile 类
? IsolatedStorageFileStream 类
? DeflateStream 类
? GZipStream 类
开始之前
若要完成本章中的重点,您应熟悉 Microsoft Visual Basic 或 C#,应熟悉下列任务:
■在 Microsoft Visual Studio 使用 Visual Basic 或 C# 中创建一个控制台应用程序。
■将系统类库的引用添加到项目。
■创建文本文件。
第一课:文件系统导航
在开发人员日常工作中,最常见的任务之一是使用文件系统。此任务包括导航和收集有关驱动器、文件夹信息文件以及等待对文件系统中发生的更改。
课时20分钟
什么是文件系统类
System.IO 命名空间内是一组用于定位和操作文件、 目录和驱动器的类。文件系统类分为两种类型的类: 信息类和实用工具类。大多数信息性类派生自 FileSystemInfo 基类。这些类公开的所有系统信息文件系统对象 — 特别,文件、 目录和驱动器。 这些类名为 FileInfo 和 DirectoryInfo。
在另外 DriveInfo 类表示一个驱动器到文件系统中但虽然仍是一个信息性类,但它不从派生 FileSystemInfo 类因为它不共享行为常见各种 (例如可以删除文件和文件夹,但不是驱动器)。
实用工具类提供静态方法 (或共享的 Visual Basic) 执行某些操作文件系统对象如文件、 目录和文件系统路径。 这些实用工具类包括文件、 Directory 和 Path 类。
FileSystemInfo 类
FileSystemInfo 类提供所有信息性文件系统的基本功能类。 表 2-1 显示了最重要的 FileSystemInfo 属性。
Attributes:获取或设置当前文件或目录的属性信息。
CreationTime:获取或设置创建当前文件或目录时间。
Exists:确定文件或目录是否存在。
Extension:获取扩展部分文件或目录的字符串表示形式。
FullName:获取文件或目录的全部路径。
LastAccessTime: 获取访问文件或文件夹的最后时间。
LastWriteTime: 获取文件和文件夹最后写入的时间。
Name:获取对文件或目录中简单名称。 对于一个文件,这是在目录内的名称。一个目录的在目录层次结构中这是最后的目录名称。
FileSystemInfo 中的方法
Delete:在文件系统中删除文件或目录
Refresh:使用从文件系统最新信息更新在类中的数据
FileInfo 类
FileInfo 类提供访问和处理单个文件在文件系统中的基本功能
表 2-3 显示最重要的 FileInfo 属性。
Directory 获取表示此文件存储在该目录的目录信息对象
DirectoryName 获取此文件存储在该目录的名称
IsReadOnly 获取或设置该标志指示文件是否可以修改或删除
Length 获取该文件的长度
Table 2-4 FileInfo 类的方法
AppendText 创建新的流录入将允许将文本追加到该文件。 有关更多信息,请参阅第 2 课。
CopyTo 拷贝文件到其它目录
Create 创建一个基于当前文件信息的文件。
CreateText 创建新的 StreamWriter 和一个新的文件写入文本。 有关更多信息,请参阅第 2 课。
Decrypt 解密由当前用户加密的文件。
Encrypt 加密文件,以便只有当前的用户可以解密该文件。
MoveTo 将该文件移动到其它地方。
Open 打开具有特定权限的文件 (读、 读写等)。
OpenRead 打开具有只读权限的文件
OpenText 打开该文件并返回 StreamReader 文件中允许读的文本
Replace 替换当前 FileInfo 对象中信息的文件。
如何获取有关文件的信息
若要获取有关特定文件的信息,请按照此过程操作:
■通过使用文件路径创建一个新的 FileInfo 对象。
■访问 FileInfo 对象的属性。
例如您可以检查文件是否存在通过调用 FileInfo 对象 的现存属性,如以下代码所示:
// C#
FileInfo ourFile = new FileInfo(@"c:/boot.ini ");
if (ourFile.Exists)
{
Console.WriteLine("Filename : {0}", ourFile.Name);
Console.WriteLine("Path : {0}", ourFile.FullName);
}
OpenWrite 打开具有只写访问权限的文件。
如何拷贝文件
除了访问有关文件的数据,FileInfo 对象还允许在该文件上执行的操作。 再次,一旦一个有效 FileInfo 获取对象,您要做的所有调用您文件的拷贝操作下面的代码示例演示 CopyTo 方法:
// C#
FileInfo ourFile = new FileInfo(@"c:/boot.ini");
ourFile.CopyTo(@"c:/boot.bak");
相同的过程用于移动和创建文件。 后一个有效的 FileInfo 对象可以访问其属性并调用其任何的方法。
DirectoryInfo 类
DirectoryInfo 类提供访问和处理单个目录在文件系统中的基本功能。 表 2-5 显示了最重要的 DirectoryInfo属性。
Parent: 获取的目录层次结构中当前目录的父目录的 DirectoryInfo 对象
Root:作为获取目录根路径的字符串部分
Table 2-6 DirectoryInfo 方法
Create 创建当前 DirectoryInfo 对象所述目录
CreateSubdirectory为当前目录目录层次结构中的一个子目录创建一个新的目录
GetDirectories 检索表示当前目录的子目录的 DirectoryInfo 对象的数组
GetFiles 检索表示当前目录中的所有文件的 FileInfo 对象的数组
GetFileSystemInfos 检索表示文件和在当前目录中的子目录 FileSystemInfo 对象的数组
MoveTo 将当前目录移动到新位置
如何枚举目录中的文件
访问目录中的文件是很相似访问文件信息。 下面的步骤说明如何枚举目录中的文件:
1.通过使用到目录路径创建一个有效的 DirectoryInfo 对象。
2.调用 GetFiles 方法以枚举目录中的文件。
下面的代码示例演示如何完成此任务:
// C#
DirectoryInfo ourDir = new DirectoryInfo(@"c:/windows");
Console.WriteLine("Directory: {0}", ourDir.FullName);
foreach (FileInfo file in ourDir.GetFiles())
{
Console.WriteLine("File: {0}", file.Name);
}
通过使用 GetFiles 方法,DirectoryInfo 对象,您都能够枚举内单个目录的文件。
DriveInfo 类
DriveInfo 类提供访问和处理单个目录在文件系统中的基本功能。 表 2-7 显示最重要的 DriveInfo 属性。
AvailableFreeSpace:获取该驱动器上的可用空间量。 在空间容量上可能不同从返回的容量 TotalFreeSpace (稍后此表所述),取决于磁盘配额。
DriveFormat:获得驱动器的格式,像NTFS或FAT32
DriveType: 枚举的形式获取驱动器的类型
IsReady:获取指示是否已准备好进行访问该驱动器的状态。
Name: 获取驱动器的名称
RootDirectory:获取表示该驱动器的根目录的 DirectoryInfo 对象。
TotalFreeSpace:获取驱动器上累积空闲空间。
TotalSize:获取启动器总的空间容量。
VolumeLabel:获取或设置驱动器的标签。 它可能设置只能在不是只读的驱动器上。
表 2-8 显示了最重要的 DriveInfo 方法。
GetDrives:静态方法 (或共享的一个在 Visual Basic 中),返回当前系统上的所有驱动器。
DriveType 枚举
DriveType 枚举提供可能类型的可以由一个 DriveInfo 对象代表的驱动器。 表 2-9 显示了该 DriveType 成员枚举
CDRom:一个光盘驱动器。 它可以是光盘、 DVD,等等。
Fixed:固定的磁盘。
Network:网络映射驱动器。
NoRootDirectory:不具有一个根目录的驱动器。
Ram:RAM驱动器
Removable:具有可移动媒体的驱动器。
Unknown:不能确定该驱动器。
如何枚举驱动器
您按照此过程,在系统中访问该驱动器:
1.调用 DriveInfo 类的静态 GetDrives 方法 。
2.遍历返回的 GetDrives DriveInfo 对象的数组。
// C#
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo drive in drives)
{
Console.WriteLine("Drive: {0}", drive.Name);
Console.WriteLine("Type: {0}", drive.DriveType);
}
您可以看到 DriveInfo 对象 GetDrives 方法大大简化了系统中枚举驱动器的过程。
注意光驱驱动器.
所有类型的光驱 (光盘、 CD / R、 DVD、 DVD / R和等等) 被都标记为 DriveInfo.CDRom。
Path 类
Path 类提供用于操作文件系统路径的方法。 表 2-10 显示了最重要的路径方法。
表 2-10 静态Path方法
ChangeExtension:采用一个路径并返回的文件名的新路径扩展更改。 (请注意,只路径字符串更改,不实际文件扩展名)。
Combine:结合两个兼容路径字符串。
GetDirectoryName:返回指定路径中的目录的名称。
GetExtension:返回在指定的文件扩展名的名称路径。
GetFileName:返回指定路径中的文件的名称。
GetFileNameWithoutExtension:返回不带扩展名的文件名,指定的路径。
GetFullPath:返回指定的路径的完整路径。 此方法可用于解决相对路径。
GetPathRoot:返回指定目录的根目录
GetRandomFileName:生成一个随机文件名。
GetTempFileName:在文件系统中生成一个临时文件并返回该文件,完整路径。
GetTempPath:到临时文件目录以返回该路径,当前用户或系统。
HasExtension:指示指定的路径的文件名称是否有一个扩展名。
IsPathRooted:指示指定的路径是否包括一个根目录目录。
如何更改文件扩展名
Path 类允许您询问和分析的文件系统路径各个部分。而不是编写自己的字符串分析代码。Path 类允许您回答有关文件系统路径的最常见问题。例如如果您要获取和更改的文件扩展名,你可以这样与 Path 类,下面的代码段中所示:
// C#
string ourPath = @"c:/boot.ini";
Console.WriteLine(ourPath);
Console.WriteLine("Ext: {0}", Path.GetExtension(ourPath));
Console.WriteLine("Change Path: {0}",
Path.ChangeExtension(ourPath, "bak"));
在Path类使用GetExtension方法,你可以获得当前系统文件的扩展名。但是改变路径的原有扩展名你可以使用Path类的ChangeExtension方法。
FileSystemWatcher 类
FileSystemWatcher 类提供用于监视的更改的文件系统目录的方法。
表2-11 FilleSystemWatcher 属性
EnableRaisingEvents: 获取或设置是否监视对象应引发事件。通常,它用于打开和关闭查看一个目录或文件。
Filter:获取或设置文件筛选器使用来确定哪个文件更改为监视。 一个空白的筛选器指示“ 所有文件 ”。
IncludeSubdirectories:获取或设置观看一个目录是否包括子目录或仅在路径属性中指定的目录的指标。
NotifyFilter:获取或设置的监视的更改类型。 默认情况下,通知 (创建、 删除、 重命名的文件和修改) 的所有更改。
Path:获取或设置监视该目录的路径
表2-12 FileSystemWatcher 方法
WaitForChanged:观看一个目录的更改,返回一个包含的所有更改结构的同步方法。
表2-13 FileSystemWatcher 事件
Changed :在更改文件或目录时发生。
Created :在创建文件或目录时发生。
Deleted:在删除文件或目录时发生。
Renamed:在重命名文件或目录时发生。
如何监视目录中的更改
监视目录的更改,按下面的步骤
1.创建一个新的FileSystemWatcher对象,在路径属性中指定该目录。
2.注册一个创建和删除事件。
3.通过将 EnableRaisingEvents 设置为 true 启用事件。
// C#
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"c:/";
// Register for events
watcher.Created +=new FileSystemEventHandler(watcher_Changed);
watcher.Deleted += new FileSystemEventHandler(watcher_Changed);
// Start Watching
watcher.EnableRaisingEvents = true;
// Event Handler
static void watcher_Changed(object sender,FileSystemEventArgs e)
{
Console.WriteLine("Directory changed({0}): {1}",
e.ChangeType,
e.FullPath);
}
事件处理程序只报告在 FullPath 对象发送到该事件处理程序中找到每个更改。
使用添加和更改事件外,,还可以监视系统为重命名的文件。 若要监视目录中的重命名的文件,您可以按照此过程:
1.创建了一个在路径属性中指定目录新 FileSystemWatcher 对象。
2.注册一个Renamed事件。
3.当EnableRaisingEvents为真时触发该事件。
请看一下代码
// C#
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"c:/";
// Register for events
watcher.Renamed +=new RenamedEventHandler(watcher_Renamed);
// Start Watching
watcher.EnableRaisingEvents = true;
// Event Handler
static void watcher_Renamed(object sender,RenamedEventArgs e)
{
Console.WriteLine("Renamed from {0} to {1}",
e.OldFullPath,
e.FullPath);
}
监视文件系统时, 您可以获得更多更改信息,FileSystemWatcher 可以处理。 当太多的事件的发生,FileSystemWatcher 会引发该错误事件。 要捕获错误事件,请按照这些步骤操作:
1.创建了一个在路径属性中指定目录新 FileSystemWatcher 对象。
2。注册出错事件。
3.设置当EnableRaisingEvents为真时触发该事件。
一下代码所示
// C#
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"c:/";
// Register for events
watcher.Error +=new ErrorEventHandler(watcher_Error);
// Start Watching
watcher.EnableRaisingEvents = true;
// Event Handler
static void watcher_Error(object sender,
ErrorEventArgs e)
{
Console.WriteLine("Error: {0}",
e.GetException());
}
实验室: 枚举文件和监视的更改
本次实验,您将枚举文件夹的文件,然后观看任何文件是否已更改。
附带 CD 上有本次实验源代码
1: 枚举文件夹中的文件
您将枚举中一个特定的驱动器的所有文件。
1.创建一个新的控制台应用程序命名为ShowFilesDemo。
2.在新的工程中添加对System.IO命名空间的引用。
3.添加一个新方法采用一个名为 ShowDirectory 的 DirectoryInfo 对象。
在您新的方法内循环的每个目录中文件并一次性在一个控制台中显示。 您的代码可能如下所示:
static void ShowDirectory(DirectoryInfo dir)
{
// Show Each File
foreach (FileInfo file in dir.GetFiles())
{
Console.WriteLine("File: {0}", file.FullName);
}
}
5.在该 ShowDirectory 方法循环访问每个子目录,并调用 ShowDirectory 方法。 这样将调用 ShowDirectory 递归查找每个目录的的所有文件。 此代码可能如下所示:
foreach (DirectoryInfo subDir in dir.GetDirectories())
{
ShowDirectory(subDir);
}
6.在 Main 方法编写代码以创建一个用于 Windows 目录的 DirectoryInfo 对象的新实例并调用新 ShowDirectory 方法使用它。 下面的代码会工作,例如:
// C#
DirectoryInfo dir = new DirectoryInfo(Environment.SystemDirectory);
ShowDirectory(dir);
7.生成项目和解决任何错误。 验证控制台应用程序成功列出系统目录 (Environment.SystemDirectory) 中的所有文件。
2: 在文件系统中监视的更改
在本练习,您将观看文件系统中.ini 扩展名结尾的所有文件的更改。
1.创建一个新的控制台应用程序命名为FileWatchingDemo。
2.在这个新文件中引用System.IO命名空间。
3.创建指定系统目录,FileSystemWatcher 类的新的实例。例如您可以使用以下代码:
// C#
FileSystemWatcher watcher =new FileSystemWatcher(Environment.SystemDirectory);
4.修改的文件系统观察器只查找.ini 文件、 搜索所有子目录,并仅接受更改属性的文件属性更改或如果文件大小更改。 您的代码可能类似于:
// C#
watcher.Filter = "*.ini";
watcher.IncludeSubdirectories = true;
watcher.NotifyFilter =
NotifyFilters.Attributes | NotifyFilters.Size;
5.以查看所做的更改,添加为您监视对象的 Changed 事件处理程序。
例如您可以使用以下代码:
// C#
watcher.Changed +=new FileSystemEventHandler(watcher_Changed);
6.接下来,您需要 Changed 事件将调用该方法。 此方法内写出到控制台更改文件的名称。 您的代码可能如下所示:
// C#
static void watcher_Changed(object sender,FileSystemEventArgs e)
{
Console.WriteLine("Changed: {0}", e.FullPath);
}
7.将 EnablingRaisingEvents 属性设置为 true,告诉监视对象以启动引发事件。
8.生成项目和解决任何错误。 验证控制台应用程序成功报告或时属性的任何.ini 文件更改文件的大小更改。
本课摘要
FileInfo、 DirectoryInfo 和 DriveInfo 类可用于枚举和检查文件系统对象的属性。
Path 类可用于询问文件系统路径,应使用的而不是手动分析该字符串。
FileSystemWatcher 类可用于监视文件系统的更改如添加、 删除和重命名。
第二课 文件的读写
文件的读写是从事设计工作在常见的的任务之一。作为一个.NET 开发人员,您需要知道如何读取和写入文件。 .NET Framework 方便地执行这些任务。
本课程后您将能够:
■ 打开一个文件,并阅读其内容。
■ 创建一个内存中数据流。
■ 写入和关闭文件。
本课大约需要20分钟
了解数据流
在.NET Framework 中,数据流是一种处理顺序和随机访问数据的常见方式。数据流是应用于框架不同部分。他们开头抽象类 是提供基本接口和实现中的所有数据流的框架。
表 2-14 及 15 表 2-分别载列的一些属性和方法的 Stream 类
表2-14 Stream 属性
CanRead:确定数据流是否支持读取。
CanSeek:确定数据流是否支持查找。
CanTimeout:确定数据流是否能超时。
CanWrite:确定数据流是否可以写入。
Length:获取数据流长度(字节)。
Position:获取或设置用于确定其中数据流中当前位置虚拟的游标。 位置值不能大于数据流的长度值。
ReadTimeout:获取或者设置数据流读操作超时。
WriteTimeout:获取或者设置数据流写操作超时。
Close:关闭流并释放与之关联的所有资源。
Flush:清除任何缓冲区中的数据流,并强制更改写入基础的系统或设备。
Read:执行顺序读取指定数目的字节从当前位置并更新位置到末尾的读操作完成后。
ReadByte:执行读取一个字节,并提出一个更新位置。 与调用 Read 读取单个字节相同。
Seek:设置数据流中的位置。
SetLength:指定流的长度。 如果新的长度小于旧的长度且将展开流,如果相反,将截断流。
Write:将信息写入到流的字节数和更新以反映新的写位置当前位置。
WriteByte:将一个字节写入到流,并更新位置。与调用 Write 与单个字节相同。
在.NET Framework 中的所有其他流类从 Stream 类派生。 这些派生的类包括:
■ FileStream (System.IO)
■ MemoryStream (System.IO)
■ CryptoStream (System.Security)
■ NetworkStream (System.Net)
■ GZipStream (System.Compression)
这些流有一个常见的基类原因是,使用数据流来处理数据是常见方法。学习一般使用流可以将这种知识应用于任何类型的流。 例如您可以编写一个简单方法转储到控制台流的内容如下所示:
// C#
static void DumpStream(Stream theStream)
{
// Move the stream's position to the beginning
theStream.Position = 0;
// Go through entire stream and show the contents
while (theStream.Position != theStream.Length)
{
Console.WriteLine("{0:x2}", theStream.ReadByte());
}
}
此代码不能照顾什么样的流发送 ; 它可以处理任何流,相同的方式。 同样,将一些信息追加到流可以在完成一个常见的方式在此示例中所示:
// C#
static void AppendToStream(Stream theStream,byte[] data)
{
// Move the Position to the end
theStream.Position = theStream.Length;
// Append some bytes
theStream.Write(data, 0, data.Length);
}
什么类方便读取和写入数据?大量的类参与在读取和写入文件的过程中。大多数操作从 File 类开始。此类公开静态方法 (或共享的方法在 Visual Basic 中),允许打开和创建文件。 File 类可以执行多种类型的操作:
■ 原子操作读取或写入文件的所有内容。
■ 操作创建或打开文件进行读取。
■ 操作创建或打开文件进行写入。
■ 简单文件操作 (File.Exists、 File.Delete,等)。
当打开或创建一个文件时,File 类可以返回几种类型的对象。 最基本的是 FileStream 对象。 这是一个简单的流的类,但它在文件系统中表示一个文件。在另外 File 类还具有返回StreamReaders 和 StreamWriters 的方法。这些类包装 FileStream 以支持顺序读取和写入流。
File 类支持的简单文件操作都是相同的 FileInfo 类第 1 课中讨论的。
除了,这些类 MemoryStream 类是一个专门的流,用于操作内存中的数据。 此类通常用于在优化的内存中创建流对象。
File 类
File 类提供以打开用于读取和写入文件流的基本功能。 表 2-16 显示最重要的文件共享静态/方法。
AppendAllText:将指定的字符串追加到一个现有的文件或者创建文件,如果不存在。
AppendText:打开一个文件 (如果不存在创建新文件) 并返回准备让文本追加到该文件的 StreamWriter。
Copy:将文件复制到新文件。 新的文件必须不存在复制才会成功。
Create:创建一个新文件并返回一个 FileStream 对象。
CreateText:创建或打开一个文件并返回 StreamWriter 对象这是准备写入它的文本。
Move:将文件从一个位置移动到另一个位置。
Open:打开现有文件并返回一个 FileStream 对象。
OpenRead:打开现有文件并返回一个只读 FileStream 对象。
OpenText:打开现有文件并返回一个 StreamReader 对象。
OpenWrite:打开现有文件进行写操作并返回 StreamWriter 对象。
ReadAllBytes:开一个文件,读取到一个字节数组的内容并关闭该文件在一个原子操作中。
ReadAllLines:打开一个文件,读取到的字符串 (每行) 的数组的内容并关闭该文件在一个原子操作中。
ReadAllText:打开一个文件,读取它的内容读入一个字符串并关闭该文件在一个原子操作中。
WriteAllBytes:打开文件、 将字节数组的内容写入到它 (覆盖任何现有数据) 并关闭该文件在一个原子操作中。
WriteAllLines:打开文件、 字符串数组的内容写入它 (覆盖任何现有数据) 并关闭该文件在一个原子操作中。
WriteAllText:打开文件、 将一个字符串的内容写入到它 (覆盖任何现有数据) 并关闭该文件在一个原子操作中。
Directory 类
如那样与文件类.NET Framework 支持 Directory 类提供了一个共享静态/界面用于操作和在文件系统中创建目录。Directory 类提供以打开用于读取和写入文件流的基本功能。 表 2-17 显示了最重要的目录共享静态 /方法。
CreateDirectory:在提供的路径中创建所有目录。
Delete:删除指定的目录.
Exists:确定是否在文件系统中存在一个目录.
GetCreationTime:返回创建时间和目录的日期。
GetCurrentDirectory:返回用于当前工作的 DirectoryInfo 对象应用程序目录。
GetDirectories:获取子目录名称的列表中指定目录。
GetDirectoryRoot:返回指定目录卷或根信息。
GetFiles:返回目录中文件的名称。
GetFileSystemEntries:返回指定的目录中子目录和文件列表。
GetLastAccessTime:返回上次访问指定的目录的时间
GetLastWriteTime:返回上次写入指定的目录的时间。
GetLogicalDrives:在当前系统中获取的驱动器的列表,作为字符串使用 “ C:/ ” 模式。
GetParent:获取的指定的目录的父目录
Move:将一个文件或目录 (以及其内容) 移动到指定的位置。
SetCreationTime:设置特定目录的创建的时间。
SetCurrentDirectory:设置指定为当前工作目录是应用程序的目录。
SetLastAccessTime:设置的上次访问一个目录。
SetLastWriteTime:设置的上次写入一个目录。
FileAccess 枚举
FileAccess 枚举提供用来确定所需打开文件时,权利的成员。 表 2-18 显示 FileAccess 成员。
Read:指定打开文件,与只读访问。
Write:指定打开文件,要写入。 无法读取该文件,只追加到。
ReadWrite:指定完全访问的文件的读取或写入。 等同于组合 Read 和 Write 的值。
FileMode 枚举
FileMode 枚举提供指定如何文件打开或创建的成员。 表 2-19 显示大部分 FileMode 委员。
Append:打开一个文件并将指针中 FileStream 移动到文件末尾。 可以只能与 FileAccess.Write 一起使用。
Create:创建一个新文件。 如果文件已经存在则将其覆盖。
CreateNew:创建一个新文件。 如果文件已经存在引发异常。
Open:打开现有文件。 如果该文件没有引发异常。
OpenOrCreate:打开现有文件。 如果该文件没有就创建一个新文件。
Truncate:打开现有文件,但清空现有的文件,以便它长度零字节。
FileStream 类
FileStream 类提供以打开用于读取和写入文件流的基本功能。 表 2-20 和表 2-21分别显示最重要的 FileStream 属性和方法。
CanRead:确定流是否支持读取。 (从流类继承)
CanSeek:确定流是否支持要求。 (从流类继承)
CanTimeout:确定流是否可以超时。 (从流类继承)
CanWrite:确定是否可以写入流。 (从流类继承)
Handle:获取流的基础文件句柄。
Length:获取流的长度 (以字节为单位)。 (从流类继承)
Name:获取文件的名字。
Position:获取或设置用于确定其中流中当前位置虚拟的游标。 位置值不能大于流的长度。 (从流继承类)。
ReadTimeout:获取或设置读取操作的流超时。(从流类继承)
WriteTimeout:获取或设置写入操作的流超时。(从流类继承)
表 2-21 FileStream 方法
Close:关闭流并释放任何关联的资源。 (从流类继承)
Flush:清除任何缓冲区流中的,并强制更改写入基础的系统或设备。 (从流类继承)
Lock:防止其他进程更改的全部或部分,文件。
Read:执行顺序读取指定数目的字节从当前位置并更新该位置,读操作完成后结束。 (从流类继承)
ReadByte:执行读取一个字节,并提出一个更新位置。 与调用 Read 读取单个字节相同。 (从流类继承)
Seek:设置将流内的位置。 (从继承,流类)。
SetLength:指定流的长度。 如果新的长度小于旧的长度且将展开流,如果相反,将截断流。 (从流类继承)
Unlock:允许其他进程更改基础文件的全部或部分
Write:将信息写入到流的字节数和更新以反映新的写位置当前位置。 (从流类继承)
WriteByte:将一个字节写入到流,并更新位置。与相同调用 Write 与单个字节。 (从流类继承)
StreamReader 类
StreamReader类提供基本功能从 Stream 派生类中读取数据。 表 2-22 和表 2-23 显示最重要的 StreamReader 属性和方法,分别。
表 2-22 StreamReader 属性
BaseStream:获取基础流读取
CurrentEncoding:获取当前编码用于基础流
EndOfStream:确定是否读取到流的最后
表 2-23 StreamReader 方法
Close:关闭读取器和基础流
Peek:在流中返回下一个字符,而不移动流的当前位置
Read:在流中读取下一个字符
ReadBlock:在流中读取下一个块的字符。
ReadLine:在流中读取下一行的字符。
ReadToEnd:读取所有字符,直到结束。
从文件里如何都
打开一个文件是很常见的操作。最简单形式打开文件涉及要求 File 类通过指定文件路径打开流。打开要读取其内容文件时, 您使用 FileMode.Open 枚举成员指定现有文件,以及 FileAccess.Read 获取该文件的只读访问,如此代码示例所示:
// C#
FileStream theFile =
File.Open(@"C:/boot.ini", FileMode.Open, FileAccess.Read);
File.Open方法将返回一个FileStream对象。文件流是只是一个流,因此您可以通过调用读取或 ReadByte Stream 类的方法来查看内容。但是,以便更好地读取文件,I/O 系统支持方便阅读及写作的 StreamReader 和流录入类。用于读取文件,您可以只是创建新 StreamReader 封装,FileStream,如下所示:
// C#
StreamReader rdr = new StreamReader(theFile);
Console.Write(rdr.ReadToEnd());
rdr.Close();
theFile.Close();
StreamReader 类旨在作为字符串,而不是一系列的字节读取流。
如果您要做读出整个文件,File 类支持读取文件中通过调用其 ReadAllText 方法隐藏流和读取器实现的所有详细信息的单个方法调用:
// C#
Console.WriteLine(File.ReadAllText(@"C:/boot.ini"));
因此,如果可以获取所有您需要与为什么会使用这些其他方法的 File 类的 ReadAllText 方法?通常原因是您不需要整个文本文件。 此方法是非常有用,如果要搜索的特定一段文本。例如在此的代码段提取掉由行和测试匹配,一个字符串的行数据,如果您认为您不需要加载整个字符串到内存:
// C#
StreamReader rdr = File.OpenText(@"C:/boot.ini");
// Search through the stream until we reach the end
while (!rdr.EndOfStream)
{
string line = rdr.ReadLine();
if (line.Contains("boot"))
{
// If we find the word boot, we notify
// the user and stop reading the file.
Console.WriteLine("Found boot:");
Console.WriteLine(line);
break;
}
}
// Clean Up
rdr.Close();
使用此方法扫描文件时尤其有用打开非常大的文件。
StreamWriter类
StreamWriter 类提供从 Stream 派生类中读取数据的基本功能。 表 2-24 和表 2-25 显示最重要的 StreamWriter 属性和方法,分别。
表 2-24 StreamWriter 属性
AutoFlush:获取或设置一个指示器,显示是否每次调用 Write 方法应刷新到基础流的更改。
BaseStream:获取基础流读取读取器。
Encoding:获取用于基础流当前编码。
NewLine:获取或设置一个字符串,包含行结束符字符串。通常使用在只有在您需要更改字符串终止的个别的行。
表 2-25 StreamWriter 方法
Close:关闭编写器和基础流
Write:写入流
WriteLine:将数据写入到流跟终止的个别行字符串
如何向文件写入
您可以写入文件之前您必须打开文件进行写入。此过程是类似于打开一个文件进行读取。例如您可以打开一个文件进行写入如下所示。
// C#
FileStream theFile = File.Create(@"c:/somefile.txt");
与用于打开一个文件进行读取的该代码不同此代码实际上与 FileStream 对象准备将写入创建一个新的文件。与 FileStream 对象在手,您可以编写到流直接,如果您希望。更多但是,您将要使用 StreamWriter 对象将数据写入新文件,此代码所示:
// C#
StreamWriter writer = new StreamWriter(theFile);
writer.WriteLine("Hello");
writer.Close();
theFile.Close();
您可以使用 StreamWriter 文本直接写入新文件。这种模式非常类似用于读取文件模式。此外,示较早前进行读取,File 类支持创建 StreamWriter 对象直接与 CreateText 方法:
// C#
StreamWriter writer = File.CreateText(@"c:/somefile.txt");
writer.WriteLine("Hello");
writer.Close();
File 类还支持将字符串写入一个新的文件,如下所示,WriteAllText 方法:
// C#
File.WriteAllText(@"c:/somefile.txt", "Hello");
此过程非常简单,但也有时候您需要向现有文件写入时。写入到现有文件是类似除了为您如何实际打开该文件。若要打开以写入文件,您使用 File 类的 Open 方法,但指定要写入流,则返回此示例所示:
// C#
FileStream theFile = null;
theFile = File.Open(@"c:/somefile.txt",
FileMode.Open,
FileAccess.Write);
文件类具有 OpenWrite 方法是实现的快捷方式并简化打开现有文件进行写入。而不是调用 Open 方法及 File 类指定要写的方式打开,您可以只使用如下代码:
// C#
theFile = File.OpenWrite(@"c:/somefile.txt");
仅仅在此文件存在时这些代码才能工作哦。在很多场合将要或者打开现有的文件或创建一个新的。可惜,OpenWrite 方法将打开只是现有的文件。如果你不确定该文件是否存在,你可以编写代码来测试。但幸运的是,您可以使用 Open 方法 File 类来指定要打开或创建一个文件,如下所示:
// C#
theFile = File.Open(@"c:/somefile.txt",
FileMode.OpenOrCreate,
FileAccess.Write);
FileMode.OpenOrCreate 枚举值,可以避免编写过程代码来处理您是否处理一个新的或现有的文件的问题。
清楚读和写
如前面部分所示 StreamReader StreamWriter 并使其易于写入和读取文本流的类。这是读取和编写器类的目的。StreamReader 类 (的 Visual Basic 中,MustInherit 关键字) 从抽象的 TextReader 类派生。从抽象的 TextWriter 类不奇怪派生,StreamWriter。 这些抽象类的所有基于文本的读和写代表基本接口。例如有是称为 StringReader 和 StringWriter 的其他文本阅读器和编写器对。这些类旨在写入和从内存中字符串读取。例如要使用 StringReader 字符串读取您使用了代码如下所示:
// C#
string s = @"Hello all This is a multi-line text string";
StringReader rdr = new StringReader(s);
// See if there are more characters
while (rdr.Peek() != -1)
{
string line = rdr.ReadLine();
Console.WriteLine(line);
}
相反,您编写一个字符串的有效的方式使用 StringWriter。 StringWriter 使用一个 StringBuilder,因此是非常有效,在创建过大的字符串。 您使用它像这样:
// C#
StringWriter writer = new StringWriter();
writer.WriteLine("Hello all");
writer.WriteLine("This is a multi-line");
writer.WriteLine("text string");
Console.WriteLine(writer.ToString());
但因为您不需要始终写入文本数据,.NET Framework 命名空间还支持两个类写入二进制数据。 BinaryReader 和 BinaryWriter 类可用于处理获取至流的二进制数据。例如要创建一个新文件来存储二进制数据您可以使用 BinaryWriter 类将各种类型的数据写入流像这样:
// C#
FileStream newFile = File.Create(@"c:/somefile.bin");
BinaryWriter writer = new BinaryWriter(newFile);
long number = 100;
byte[] bytes = new byte[] { 10, 20, 50, 100 };
string s = "hunger";
writer.Write(number);
writer.Write(bytes);
writer.Write(s);
writer.Close();
如果您已经编写数据与该 BinaryWriter,您可以使用该 BinaryReader 以相同的顺序获取数据。您将为每个 BinaryWriter.Write 或 WriteLine 的调用
需要调用适当的 BinaryReader.Read 方法。 例如下面的代码将读取代码刚才所示:
// C#
FileStream newFile = File.Open(@"c:/somefile.bin", FileMode.Open);
BinaryReader reader = new BinaryReader(newFile);
long number = reader.ReadInt64();
byte[] bytes = reader.ReadBytes(4);
string s = reader.ReadString();
reader.Close();
Console.WriteLine(number);
foreach (byte b in bytes)
{
Console.Write("[{0}]", b);
}
Console.WriteLine();
Console.WriteLine(s);
MemoryStream 类
MemoryStream 类提供用于创建内存中流基本的功能。
表 2-26 和表 2-27 显示最重要 MemoryStream 属性和方法,分别。
表 2-26 MemoryStream 属性
CanRead:确定流是否支持读取。 (从流类继承)
CanSeek:确定流是否支持要求。 (从流类继承)
CanTimeout:确定流是否可以超时。 (从流类继承)
CanWrite:确定流是否支持写入。(从流类继承)
Capacity:获取或设置分配流的字节数。
Length:获取流的长度 (以字节为单位)。 (从流类继承)
Position:获取或设置用于确定其中流中当前位置虚拟的游标。 位置值不能大于流的长度。 (从流类继承)
ReadTimeout:获取或设置读取操作的流的超时。 (从流类继承)
WriteTimeout:获取或设置写操作的流的超时。 (从流类继承)
表 2-27 MemoryStream 方法
Close:关闭流并释放与之关联的所有资源。(从流类继承)
Flush:清除任何缓冲区流中的,并强制更改写入基础的系统或设备。 (从流类继承)
GetBuffer:检索用于创建流的无符号字节的数组。
Read:执行顺序读取指定数目的字节从当前位置并更新位置到末尾的读操作完成后。 (从流类继承)
ReadByte:执行读取一个字节,并提出一个更新位置。 与调用 Read 读取单个字节相同。(从流类继承)
Seek:设置流内的位置。 (从流类继承)
SetLength:指定流的长度。 如果新的长度小于旧的长度且将展开流,如果相反,此方法将截断流。 (从流类继承)
ToArray:整个流写入的字节数组。
Write:将信息写入到流的字节数和更新以反映新的写位置当前位置。(从流类继承)
WriteByte:将一个字节写入到流,并更新位置。 此方法是调用写入到与单个字节相同。 (从流类继承)
WriteTo:将 MemoryStream 写入到另一个流。
如何使用 MemoryStream
正如您所见的数据的流使用是为任何开发人员的重要技能。
可惜,通常需要将之前您真正需要将其存储某处 (类似文件中) 创建一个流。 MemoryStream 类具有工作,帮助您在内存中创建流。 创建的内存流是这么简单创建的 MemoryStream 类的新实例:
// C#
MemoryStream memStrm = new MemoryStream();
您可以使用 StreamWriter 一样使用 FileStream 类较早前向您新 MemoryStream 写入数据:
// C#
StreamWriter writer = new StreamWriter(memStrm);
writer.WriteLine("Hello");
writer.WriteLine("Goodbye");
现在,您已经数据 MemoryStream 对象中,您做什么的? MemoryStream 类设计器只是将流存储在内存中,这仅仅是临时的。因此,类支持编写流直接以
另一个流或将数据复制到其他存储。内存流的一个常见用途是限制的时间内打开文件并写入流 (因为的锁定文件)因此继续此运行示例可以看出 MemoryStream 写入一个 FileStream,如下所示:
// C#
// Force the writer to push the data into the
// underlying stream
writer.Flush();
// Create a file stream
FileStream theFile = File.Create(@"c:/inmemory.txt");
// Write the entire Memory stream to the file
memStrm.WriteTo(theFile);
// Clean up
writer.Close();
theFile.Close();
memStrm.Close();
您可以看到代码执行这些任务:
1.它告诉 StreamWriter 将其更改刷新到基础流 (在本例 MemoryStream)。
2.创建新的文件。
3.它告诉 MemoryStream 对象本身写入 FileStream 对象。
此过程允许您 MemoryStream 时间密集工作然后打开该文件、 刷新数据,并快速关闭该文件。
BufferedStream 类
BufferedStream 类提供基本的功能来包装来提高性能的流由缓冲读取和写入通过流。表 2-28 和表 2-29 分别显示最重要 BufferedStream 属性和方法。
表 2-28 BufferedStream 属性
CanRead:确定流是否支持读取。 (从流类继承)
CanSeek:确定流是否支持要求。 (从流类继承)
CanTimeout:确定流是否可以超时。 (继承从 Stream 类)。
CanWrite:确定是否可以写入流。 (从流类继承)
Length:获取流的长度 (以字节为单位)。 (从流类继承)
Position:获取或设置用于确定其中流中当前位置虚拟的游标。 位置值不能大于流的长度。 (从流类继承)
ReadTimeout:获取或设置读取操作的流的超时。 (从流类继承)
WriteTimeout:获取或设置写操作的流的超时。(从流类继承)
表 2-29 BufferedStream 方法
Close:关闭流并释放任何关联的资源与它。 (从流类继承)
Flush:清除任何缓冲区流中的,并强制更改写入基础的系统或设备。 (从流类继承)
Read:执行顺序读取指定数目的字节从当前位置并更新该位置,读操作完成后结束。 (从流类继承)
ReadByte:执行读取单个字节并提出一个更新位置。 与调用 Read 读取单个字节相同。 (从流类继承)
Seek:设置流内的位置。 (从继承,流类)。
SetLength:指定流的长度。 如果新的长度小于旧的长度且将展开流,如果相反,此方法将截断流。 (从流类继承)
Write:将信息写入到流的字节数和更新以反映新的写位置当前位置。(从流类继承)
WriteByte:将一个字节写入到流,并更新位置。此方法是调用写入到与单个字节相同。(从流类继承)
如何使用 BufferedStream
有时您想使用一个流,方便,但直接写出到流的数据执行不是很好。这种情况是其中您可以使用 Buffered Stream 类。该 BufferedStream 包装,以便写入发生在一个缓冲区的另一个流对象并仅当刷新缓冲区并数据其实获取推入基础流。若要 BufferedStream 请按照下列步骤操作:
1.创建了一个使用 File 类指定一个新的文件新 FileStream 对象。
2.创建指定文件流作为基础流新一个缓冲的流。
3.使用 StreamWriter 数据写入缓冲流
下面的代码段演示了此过程:
// C#
FileStream newFile = File.Create(@"c:/test.txt");
BufferedStream buffered = new BufferedStream(newFile);
StreamWriter writer = new StreamWriter(buffered);
writer.WriteLine("Some data");
writer.Close();
实验室: 读取和写入文件
在本实验室您将创建一个新的文件、 写入一些数据和关闭文件。 然后重新打开文件,读取该数据并在控制台中显示的数据。如果您遇到完成工作的问题,已完成的项目可用代码文件夹中附带 CD 上。
步骤 1: 写入新文件
在本练习将创建一个新文件并插入一些文本。
1.创建一个新的控制台应用程序,命名为FileDemo。
2.添加对System.IO空间的引用。
3.在Main方法中,从的 Create 方法创建一个新的 StreamWriter,文件类。
4.到流编写器使用 WriteLine 方法编写一些行。
5.关闭 StreamWriter。 该代码可能类似完成您:
// C#
static void Main(string[] args)
{
StreamWriter writer = File.CreateText(@"c:/newfile.txt");
writer.WriteLine("This is my new file");
writer.WriteLine("Do you like its format?");
writer.Close();
}
6.生成项目和解决任何错误。 验证控制台应用程序通过手动检查该文件在文件系统中创建该文件。
步骤 2: 读取文件
在本练习将打开您在步骤1 中创建该文件并在控制台中显示内容。
1.打开在步骤1创建 FileDemo项目
2.在 Main 方法中关闭 StreamWriter 类后打开文件使用 File 类 OpenText 方法来创建一个新的 StreamReader 对象。
3.创建一个名为内容的新字符串并调用 ReadToEnd 方法获取文件的整个内容 StreamReader 类。
4.关闭 StreamReader 对象。
5.写入字符串控制台。 您的代码可能如下所示:
// C#
StreamReader reader = File.OpenText(@"c:/newfile.txt");
string contents = reader.ReadToEnd();
reader.Close();
Console.WriteLine(contents);
6.生成该项目和解决任何错误。 验证控制台应用程序在控制台窗口中成功显示文件的内容。
本课摘要
File 类可用于打开文件、 创建新的文件、 方式,读取整个文件和甚至写入文件。
FileStream 类在文件系统中表示一个文件,并允许读取和写入 (取决于如何它创建)。
StreamReader 和 StreamWriter 类,用于简化写入到流的字符串。
MemoryStream 是一个专门的流在内存和支持将流保存到其他流中创建内容。
第三课:压缩流
现在,您了解如何使用流的基础知识,您即可了解新的会在某些类型的项目中使用的重要流类型。通常在现实世界项目中您会发现很有用保存通过压缩数据的空间或带宽。 .NET Framework 支持可以压缩数据的两个新流类。
在本课您将学习到
压缩流与 GZipStream 和 DeflateStream 类。
解压缩与 GZipStream 和 DeflateStream 类的流。
本课大约10分钟
引入压缩流
在 I/O 在.NET Framework 内系统,有两种压缩数据的方法: GZIP 和 DEFLATE。 这两种压缩方法是行业标准也是免费的专利保护的压缩算法。 因此,您可以自由地没有任何知识产权关注自己应用程序中使用这些压缩方法之一。
注意压缩大小限制
这两种压缩方法仅限于未压缩的数据压缩高达 4GB。
这些压缩方法是由.NET Framework 公开为两种类型的支持压缩和解压缩流。 GZipStream 和 DeflateStream 类中实现这些流。
使用 DEFLATE 或 GZIP注意事项?
GZipStream 和 DeflateStream 类的压缩数据使用相同的算法。 唯一的区别是 GZIP specification 允许标头包含可能会有所帮助解压缩具有广泛使用的 gzip 工具的文件的额外信息。 如果您仅在您自己的系统内压缩数据用于,DeflateStream 是略小因为缺乏标头信息,但如果您打算分发到通过 GZIP,解压缩文件改用 GZipStream。
GZipStream类
GZipStream 是允许数据通过使用 GZIP 压缩方法的另一个流压缩一个类。表
2-30 及表 2-31 分别显示最重要 GZipStream 属性和方法。
表 2-30 GZipStream 属性
BaseStream:获取基础流。
CanRead:确定流是否支持读取时解压缩文件。 (从流类继承)
CanSeek:确定流是否支持要求。 (从流类继承)
CanTimeout:确定流是否可以超时。 (继承从 Stream 类)。
CanWrite:确定是否可以写入流。 (从流类继承)
Length:不要使用。 将引发 NotSupportedException异常。 (继承从
Stream 类)。
Position:不要使用。 将引发 NotSupportedException异常。 (继承
从 Stream 类)。
ReadTimeout:获取或设置读取操作的流超时。 (从流类继承)
WriteTimeout:获取或设置写操作的流超时。(从流类继承)
表 2-31 GZipStream 方法
Close:关闭流并释放任何与它关联的资源。 (从流类继承)
Flush:清除任何缓冲区流中的,并强制更改写入基础的系统或设备。 (从流类
继承)
Read:执行顺序读取指定数目的字节从当前位置并更新该位置,读操作完成后结
束。 (从流类继承)
ReadByte:执行读取一个字节,并提出一个更新位置。 此方法等同于调用
Read 读取单个字节。 (从流类继承)
Seek:不要使用。 将引发 NotSupportedException异常。 (继承从 Stream
类)。
SetLength:不要使用。 将引发 NotSupportedException异常。 (继承从
Stream 类)。
Write:将信息写入到流的字节数和更新以反映新的写位置当前位置。(从流类
继承)
WriteByte:将一个字节写入到流,并更新位置。此方法是调用写入到与单个字
节相同。(从流类继承)
DeflateStream 类
DeflateStream 是允许的数据通过使用 DEFLATE 压缩方法的另一个流压缩一个
类。 表 2-32 和表 2-33 分别显示最重要 DeflateStream 属性和方法。
表 2-32 DeflateStream 属性
BaseStream:获取基础流
CanRead:确定流是否支持读取。(从流类继承)
CanSeek:确定流是否支持要求。(从流类继承)
CanTimeout:确定流是否可以超时。 (继承从 Stream 类)
CanWrite:确定是否可以写入流。 (从流类继承)
Length:不要使用。 将引发 NotSupportedException异常。(继承从 Stream
类)。
Position:不要使用。 将引发 NotSupportedException异常。(继承从
Stream 类)。
ReadTimeout:获取或设置读取操作的流超时。(从流类继承)
WriteTimeout:获取或设置写操作的流超时。(从流类继承)
表 2-33 DeflateStream 方法
Close:关闭流并释放任何关联的资源
Flush:清除任何缓冲区流中的,并强制更改写入基础的系统或设备。 (从流类
继承)
Read:执行顺序读取指定数目的字节从当前位置并更新该位置,读操作完成后结
束。 (从流类继承)
ReadByte:执行读取一个字节,并提出一个更新位置。 此方法等同于调用
Read 读取单个字节。 (从流类继承)
Seek:不要使用。 将引发 NotSupportedException异常。(继承从 Stream
类)。
SetLength:不要使用。 将引发 NotSupportedException异常。(继承从
Stream 类)。
Write:将信息写入到流的字节数和更新当前位置以反映新写位置。 (从
Stream 类的继承)
WriteByte:将一个字节写入到流,并更新位置。此方法是调用写入到与单个字
节相同。(从流类继承)
如何压缩数据的压缩流
压缩流和上一课的流有一点不同。写入资源 (例如一个文件为 FileStream 或
MemoryStream 的内存流),而不是写入另一个流。压缩流用来参与任何流等数
据,但将写入数据时它推它到另一个流压缩或解压缩的格式。
以下段落提供一个典型的例子:在文件系统中压缩文件和编写新压缩文件的版本
。首先您需要打开要压缩文件和要写入的文件:
// C#
FileStream sourceFile = File.OpenRead(inFilename);
FileStream destFile = File.Create(outFilename);
压缩流需要压缩流包装传出 (或目标) 流。 压缩构造函数中执行此任务流如
下所示:
// C#
GZipStream compStream =
new GZipStream(destFile, CompressionMode.Compress);
此语句告诉压缩流压缩数据,将其推送到目标流。构造函数采用一个
CompressionMode 值,指定是否流将用来压缩或解压缩。在这种情况下要压缩
,流,因此使用 CompressionMode.Compress。 一旦创建压缩流,它是只是源
从流读取数据,压缩流中如下所示:
// C#
int theByte = sourceFile.ReadByte();
while (theByte != -1)
{
compStream.WriteByte((byte)theByte);
theByte = sourceFile.ReadByte();
}
此代码流数据一个字节一次从源文件 (sourceFile) 到压缩流 (compStream)。
注意你不能写入目标文件(destFile)。因为你需要写入的是压缩流,目标文件所
要写入的是源文件的压缩版本。
刚才所示,流代码并不特定于 GZIP 压缩方法。如果我们改变了要改用该
DeflateStream 流兴建代码的其余部分不会在所有更改。所需是您创建一个
DeflateStream相反,如下所示 (注意该签名是相同的 GZipStream):
// C#
DeflateStream compStream =
new DeflateStream(destFile, CompressionMode.Compress);
如何解压缩数据压缩流
解压缩使用相同的程序设计作为压缩,只是流处理略有不同。例如您仍创建源和
目标文件像之前:
// C#
FileStream sourceFile = File.OpenRead(inFilename);
FileStream destFile = File.Create(outFilename);
在这个个例子中,源文件是已经被压缩的文件,目标文件是源文件解压缩之后写
入的文件。当你创建了压缩流,你可以使用两种方法:因为这是作为压缩的数据
存在,而您指定您是 CompressionMode.Decompress 包装源文件解压缩包装的
流。
// C#
GZipStream compStream =
new GZipStream(sourceFile, CompressionMode.Compress);
在另外需要更改处理从压缩流而不是从源文件中读取和写入出该文件直接而不是
通过压缩流文件方式:
// C#
int theByte = compStream.ReadByte();
while (theByte != -1)
{
destFile.WriteByte((byte)theByte);
theByte = compStream.ReadByte();
}
或者(压缩或解压缩) 压缩流是为了包装流包含 (或将包含) 压缩的数据。 是
否读取或写入压缩的数据都完全取决于是否压缩或解压缩。
实验:压缩和解压缩的现有文件
本次实验中,你将创建一个控制台应用程序,读取一个文件从文件系统,并将它
压缩后写道新的文件里。如果您遇到问题,已完成的项目在代码文件夹中附带
CD 上。
步骤1:压缩一个现有的文件
在这里,你将压缩一个现有的文件到一个新的压缩文件。
1.创建一个新的控制台应用项目命名为CompressionDemo。
2.在新项目中添加对System.IO 和 System.IO.Compression空间的引用。
3.创建一个静态方法,命名为CompressFile,它有两个文本变量:inFilename
和 outFilename。 方法签名应类似下面这样:
// C#
static void CompressFile(string inFilename,
string outFilename)
{
}
4.此方法体内,打开一个FileStream对象(命名sourceFile)通过打
开,inFilename 中指定该文件。
5.创建一个新的FileStream对象(命名destFile)被创建的新文件制定
为outFilename。
5.创建一个新的GZipStream对象(命名compStream),指定该 destFile 作为
要将该压缩的数据写入流。此外指定会压缩流。 您的代码可能如下所示:
// C#
GZipStream compStream =
new GZipStream(destFile, CompressionMode.Compress);
7.流到压缩源代码文件中数据一次流一个字节。
您的代码可能如下所示:
// C#
int theByte = sourceFile.ReadByte();
while (theByte != -1)
{
compStream.WriteByte((byte)theByte);
theByte = sourceFile.ReadByte();
}
8.在退出该方法之前关闭所有流。
9.在新的控制台项目 Main 方法调用 CompressFile 方法与现有文件及新文件
名称 (通常结束与源文件调用可能类似于.gz)。
// C#
CompressFile(@"c:/boot.ini", @"c:/boot.ini.gz");
10.生成项目和解决任何错误。 验证控制台应用程序通过手动检查压缩的文件中
创建新的压缩的文件,文件系统。 该文件应理解为在文本编辑器 (如
NotePad) 中的无用。
步骤2:解压缩到新的文件
这回,你将打开一个文件,你在步骤1创建的和解压到新的文件。
1.打开CompressionDemo项目
2.创建一个新的静态方法命名为UncompressFile,有两个分本变量分别
是inFileName 和outFileName方法签名应如下所示:
// C#
static void UncompressFile(string inFilename,string outFilename)
{
}
3.在此方法体内,打开一个FileStream对象(命名为sourceFile)被打开的文
件路径是变量inFilename,这将压缩的文件是步骤1。
4.创建新的FileStream对象(命名为destFile)被创建新的文件指向变
量outFilename。
5.创建一个新 GZipStream 对象 (名为 compStream),作为流读取压缩的数
据从指定该 sourceFile。 此外指定这是一个
解压缩流。 您的代码可能如下所示:
// C#
GZipStream compStream =
new GZipStream(sourceFile, CompressionMode.Decompress);
6.流到目标压缩文件中数据文件一次一个字节。 您的代码可能如下所示:
// C#
int theByte = compStream.ReadByte();
while (theByte != -1)
{
destFile.WriteByte((byte)theByte);
theByte = compStream.ReadByte();
}
7.退出该方法之前关闭所有流。
8.在新的控制台项目 Main 方法调用 UncompressFile 方法并将其传递在步骤
1 中创建压缩文件的文件名,将接收未压缩的数据文件的名称。 调用可能如下
所示:
// C#
DecompressFile(@"c:/boot.ini.gz", @"c:/boot.ini.test");
9.生成项目和解决任何错误。 验证控制台应用程序通过打开带有 NotePad 创
建新的未压缩的文件。 比较文件的原始文件,看看他们是否相同的内容。
第四课使用独立的存储
由于我们正知道越来越多相关知识,但是程序完全不受计算机的约束不是一个好主意。对于大多数用户来说目前是一个更好的世界,但是间谍软件、 恶意软件和病毒出现告诉我们在有限沙箱中的工作是安全的。可惜,许多程序仍需要保存某种有关自己的状态数据。执行此操作,作为在缓存中存储数据的方法是无害的。要保存数据的应用程序的需要对管理员和用户使用更多限制的安全设置,.NET Framework 支持独立存储的概念。
本课程后您将能够:
■ 通过使用 IsolatedStorageFile 类访问存储程序数据的独立的存储。
■ 创建文件和独立存储通过使用 IsolatedStorageFileStream 类中的文件夹。
■ 访问不同存储在独立存储在每个用户和每台计算机上使用 IsolatedStorageFile 类。
本课大约需要15分钟
什么是独立存储
在运行代码是使用有限的权限将有效避免病毒和间谍软件的侵扰。.NET Framework 有多种机制处理以最少特权用户身份运行。因为大多数应用程序要处理存储其状态的某些永久的方式 (不采用数据库或其他手段),它最好有一个地方来存储是安全的使用而无需测试应用程序是否将数据保存到硬盘驱动器的足够权限的信息。该解决方案是旨在提供什么是独立的存储。
通过使用独立的存储来保存数据,您将可以安全做到安全访问而无需求助于使文件系统中授予对特定文件或文件夹的访问权限的用户存储的信息。
注意 .net2.0
有新类型的应用程序是部署和安装从网页调用 “ 单击-一次应用程序 ” 或 “ 智能客户端应用程序 ”。 这些新类型的应用程序是为了跨公司或企业解决应用程序的部署。
更多信息单击-一次应用程序
关于更的的单击一次应用程序的信息请访问http://msdn2.microsoft.com/en-us/
library/142dbbz4.aspx.
IsolatedStorageFile 类
IsolatedStorageFile 类提供在独立存储中创建文件和文件夹的基本功能。 表 2-34 显示最重要的 IsolatedStorageFile 静态 / 共享方法。
表 2-34 IsolatedStorageFile 静态/共享 方法
GetMachineStoreForApplication:检索用于调用的计算机级别存储在单击-当应用程序
GetMachineStoreForAssembly:检索一个计算机级别存储为调用程序集
GetMachineStoreForDomain:检索一个计算机级别存储应用域在当前程序集调用内。
GetStore:检索存储基于 IsolatedStorage 范围枚举器
GetUserStoreForApplication:为单击检索一个用户级存储-当应用程序的调用
GetUserStoreForAssembly:检索一个用户级存储为程序集的调用
GetUserStoreForDomain:检索一个用户级存储为调用当前程序集内应用域
表 2-35 IsolatedStorageFile 属性
ApplicationIdentity:独立的存储单击-当应用程序标识的范围,
AssemblyIdentity:范围独立的存储的程序集标识
CurrentSize:此独立存储中存储数据的当前大小
DomainIdentity:标识的范围,独立的域存储
MaximumSize:此独立存储最大存储大小
Scope:描述此独立存储范围的 IsolatedStorageScope 枚举值
表 2-36 IsolatedStorageFile 方法
Close:关闭的一个存储实例
CreateDirectory:创建一个存储中的目录
DeleteDirectory:删除一个存储中的目录
DeleteFile:删除存储中的文件
GetDirectoryNames:获取存储中的目录名称匹配文件掩码的列表
GetFileNames:获取存储中的文件名称匹配文件掩码的列表
Remove:从当前系统中删除整个存储库
如何创建一个存储
您可以在独立存储中保存数据之前您必须确定如何范围所需在存储区中的数据。对于大多数应用程序将要选择两种方法之一:
Assembly/Machine:此方法创建要保持是特定于调用程序集和本地计算机的信息存储。 此方法可用于创建应用程序级数据。
Assembly/User:此方法创建要保持是特定于调用程序集和当前用户的信息存储。 此方法可用于创建用户级数据。
创建一个程序集/计算机级存储被通过调用 IsolatedStorageFile 类 GetMachineStoreForAssembly 方法,如下所示:
// C#
IsolatedStorageFile machineStorage =
IsolatedStorageFile.GetMachineStoreForAssembly();
是否的主要可执行文件在 Microsoft Windows 窗体项目或动态链接库 (DLL) 的一个更大一部分中,此独立的存储存储是项目的特定于项目的调用它,该程序集。
建一个程序集/用户级存储类似,但该方法被命名为 GetUser-StoreForAssembly,此示例所示:
// C#
IsolatedStorageFile userStorage =
IsolatedStorageFile.GetUserStoreForAssembly();
存储在这种情况下被限于特定的用户执行该程序集。 要指定用于存储用户需要将使用模拟 (涵盖是在第 12 章)。
注意 Application-level 存储
为单击-当部署应用程序独立存储还支持支持一个计算机级别存储和一个用户级存储一个应用程序级存储。 应用程序级别存储只在单击内的工作-一应用程序因为执行的程序集具有自己证据,可能或不可能对本地应用程序有效。
IsolatedStorageFileStream 类
IsolatedStorageFileStream 类封装流,用于在独立存储中创建文件。此类派生 FileStream 阶层因此其用法创建后与 FileStream 类几乎相同。
表 2-37 IsolatedStorageFileStream 属性
CanRead:确定流是否支持读取。 (从流类继承)
CanSeek:确定流是否支持要求。 (从流类继承)
CanTimeout:确定流是否可以超时。 (继承从 Stream 类)。
CanWrite:确定流是否支持写入。 (从流类继承)
Handle:获取流的基础文件句柄。 (从 FileStream 类继承)
Length:获取流的长度 (以字节为单位)。 (从流类继承)
Name:获取文件的名称。 (从 FileStream 继承类)。
Position:获取或设置用于确定其中流中当前位置虚拟的游标。 位置值不能大于流的长度。 (从流类继承)
ReadTimeout:获取或设置读取操作的流的超时。 (从流类继承)
WriteTimeout:获取或设置写操作的流的超时。(从流类继承)
表 2-38 IsolatedStorageFileStream 方法
Close:关闭流并释放与之关联的所有资源。 (从流类继承)
Flush:清除任何缓冲区中的流,并强制更改写入基础的系统或设备。 (从流类继承)
Lock:防止其他进程更改所有或文件的一部分。(从 FileStream 类继承)
Read:执行顺序读取指定数目的字节从当前位置并更新位置到末尾的读操作完成后。 (从流类继承)
ReadByte:执行读取一个字节,并提出一个更新位置。 此方法等同于调用 Read 读取单个字节。 (从流类继承)
Seek:设置将流内的位置。 (从流类继承)
SetLength:指定流的长度。 如果新的长度小于旧的长度且将展开流,如果相反,将截断流。 (从流类继承)
Unlock:允许其他进程更改基础文件的全部或部分。 (从 FileStream 类继承)
Write:将信息写入到流的字节数和更新当前位置以反映新写位置。 (从 Stream 类的继承)
WriteByte:将一个字节写入到流,并更新位置。 此方法是调用写入到与单个字节相同。 (从流类继承)
在独立存储中读取和写入数据
创建内独立存储的数据就像任何其他数据写入文件系统,异常必须使用 solatedStorageFileStream 类。通过创建类的新实例、 指定相对文件的名称以及包括指定的存储其内包括一个存储对象创建一个新的 IsolatedStorageFileStream 对象。 下面的代码段提供了一个示例:
// C#
IsolatedStorageFile userStore =
IsolatedStorageFile.GetUserStoreForAssembly();
IsolatedStorageFileStream userStream =
new IsolatedStorageFileStream("UserSettings.set",
FileMode.Create,
userStore);
创建一个存储后, 可以通过指定要在打开或创建该文件和您创建的存储对象中使用 FileMode 文件名创建文件流。后 IsolatedStorageFileStream 类的实例与其工作是
与使用任何文件流 (像我们在第 2 课中) 相同。 这是因为
IsolatedStorageFileStream 派生自 FileStream。 下面的代码段提供了一个示例:
// C#
StreamWriter userWriter = new StreamWriter(userStream);
userWriter.WriteLine("User Prefs");
userWriter.Close();
在此示例使用可以标准的 StreamWriter 对象将数据写入到您流。再次之后 userStream 对象, 与其工作是在文件系统中使用的任何文件相同的。准备读取数据后是这么简单创建流对象通过打开文件,而不是创建它,如下所示:
// C#
IsolatedStorageFileStream userStream =
new IsolatedStorageFileStream("UserSettings.set",
FileMode.Open,
userStore);
通过打开,只需更改,FileMode,您可以打开文件,而不是创建一个新的。与该应用程序编程接口 (API 为任意存储在文件系统中的文件,) 不同文件的独立存储 API 不支持检查存在的一个文件中像 File.Exists 直接执行。相反,您需要存储要求的与特定文件掩码匹配的文件列表。 如果找到可以打开该文件,此示例所示:
// C#
string[] files = userStore.GetFileNames("UserSettings.set");
if (files.Length == 0)
{
Console.WriteLine("No data saved for this user");
}
else
{
// ...
}
您可以使用 GetFileNames 方法的 IsolatedStorageFile 类获取的与您的文件名称匹配的文件的列表 (或其他文件掩码如 *.set)。 此替换是足够测试是否存在文件的尝试读取、 删除之前, 或替换文件。
如何在独立存储中使用目录
您并不限于将数据存储为只是一套独立存储中的文件 ;而且,还允许您创建目录存储数据。 在目录中创建文件之前,您必须调用该 IsolatedStorageFile 类的 CreateDirectory 方法,如下所示
// C#
userStore.CreateDirectory("SomeDir");
IsolatedStorageFileStream userStream = new
IsolatedStorageFileStream(@"SomeDir/UserSettings.set",
FileMode.Create, userStore);
在此示例您创建目录,然后再尝试该目录中创建一个新文件。 如果您没有首先创建该目录,您将获得一个路径分析异常。
目录都视为多文件,若要测试其存在,则必须使用一个返回与文件掩码匹配的字符串数组方法。 IsolatedStorageFile 类的 GetDirectory 名称方法允许您尝试创建它之前查找现有的文件:
// C#
string[] directories =
userStore.GetDirectoryNames("SomeDir");
if (directories.Length == 0)
{
userStore.CreateDirectory("SomeDir");
}
通过获取目录的名称匹配您的姓名,您可以测试以查看是否目录存在,并且只有它不不存在的时候在创建它。
IsolatedStorageFilePermission 类
IsolatedStorageFilePermission 类封装可授予代码,以允许它访问独立存储区权限。 表 2-39 显示最重要 IsolatedStorageFilePermission 属性。
表 2-39 IsolatedStorageFilePermission 属性
UsageAllowed:获取或设置的允许使用类型。
UserQuota:获取或设置的允许每个用户的存储整体大小。
允许独立的存储
一个程序集 (或应用程序) 可以使之前使用的独立存储它必须授予权限,这样做。若要确保您使用的任何代码便足够的权限需要将要求该权限。 可以通过批注类或具有 IsolatedStorageFilePermission,方法来完成此任务在这里看到:
// C#
[IsolatedStorageFilePermission(SecurityAction.Demand)]
class Program
{
// ...
}
IsolatedStorageFilePermission 用于确保要使用此类中的独立存储的任何调用将会成功。 如果您的代码不具有访问独立的存储权限,包括此属性将允许管理员可以更好地了解哪些程序集需要此权限,让他们如果需要添加该权限。
此权限还支持多个属性可用于修改如何独立的存储用于此示例所示:
// C#
[IsolatedStorageFilePermission(SecurityAction.Demand,
UserQuota=1024,
UsageAllowed=IsolatedStorageContainment.AssemblyIsolationByUser)]
class Program
{
// ...
}
添加 UserQuota 和 UsageAllowed 介绍到安全系统此代码打算如何使用独立的存储。
==========================135