基本的文件 I/O

抽象基类 Stream 支持读取和写入字节。 Stream 集成了异步支持。 其默认实现根据其相应的异步方法来定义同步读取和写入,反之亦然。

所有表示流的类都是从 Stream 类继承的。 Stream 类及其派生类提供数据源和储存库的一般视图,使程序员不必了解操作系统和基础设备的具体细节。

流涉及三个基本操作:

  • 可以从流读取。 读取是从流到数据结构(如字节数组)的数据传输。

  • 可以向流写入。 写入是从数据源到流的数据传输。

  • 流可以支持查找。 查找是对流内的当前位置进行的查询和修改。

根据基础数据源或储存库,流可能只支持这些功能中的一部分。 例如,NetworkStreams 不支持查找。 Stream 及其派生类的 CanReadCanWriteCanSeek 属性决定了不同流所支持的操作。

有关通用 I/O 任务的列表,请参见通用 I/O 任务

注意

Visual Basic 用户可以选择使用由 Microsoft.VisualBasic.FileIO.FileSystem 类提供的方法和属性执行文件 I/O 操作。

用于文件 I/O 的类

Directory 提供创建、移动和枚举目录和子目录的静态方法。 DirectoryInfo 类提供实例方法。

DirectoryInfo 提供创建、移动和枚举目录和子目录的实例方法。 Directory 类提供静态方法。

DriveInfo 提供访问有关驱动器的信息的实例方法。

File 提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建 FileStreamFileInfo 类提供实例方法。

FileInfo 提供用于创建、复制、删除、移动和打开文件的实例方法,并协助创建 FileStreamFile 类提供静态方法。

FileStream 支持通过其 Seek 方法随机访问文件。 默认情况下,FileStream 以同步方式打开文件,但它也支持异步操作。 File 包含静态方法,而 FileInfo 包含实例方法。

FileSystemInfoFileInfoDirectoryInfo 的抽象基类。

Path 提供以跨平台的方式处理目录字符串的方法和属性。

DeflateStream 提供使用 Deflate 算法压缩和解压缩流的方法和属性。

GZipStream 提供压缩和解压缩流的方法和属性。 默认情况下,此类使用与 DeflateStream 类相同的算法,但可以扩展到使用其他压缩格式。

SerialPort 提供控制串行端口文件资源的方法和属性。

FileFileInfoDriveInfoPathDirectoryDirectoryInfo 是密封(在 Microsoft Visual Basic 中为 NotInheritable)类。 可以创建这些类的新实例,但它们不能有派生类。

用于从流读取和写入流的类

BinaryReaderBinaryWriterStreams 中读取和写入编码的字符串和基元数据类型。

StreamReader 通过使用 Encoding 进行字符和字节的转换,从 Streams 中读取字符。 StreamReader 具有一个构造函数,该构造函数根据是否存在专用于 Encodingpreamble(例如一个字节顺序标记)来尝试确定给定 Stream 的正确 Encoding 是什么。

StreamWriter 通过使用 Encoding 将字符转换为字节,向 Streams 写入字符。

StringReaderStrings 中读取字符。 StringReader 允许您用相同的 API 来处理 Strings,因此您的输出可以是 String 或以任何编码表示的 Stream

StringWriterStrings 写入字符。 StringWriter 允许您用相同的 API 来处理 Strings,因此您的输出可以是 String 或以任何编码表示的 Stream

TextReaderStreamReaderStringReader 的抽象基类。 抽象 Stream 类的实现用于字节输入和输出,而 TextReader 的实现用于 Unicode 字符输出。

TextWriterStreamWriterStringWriter 的抽象基类。 抽象 Stream 类的实现用于字节输入和输出,而 TextWriter 的实现用于 Unicode 字符输出。

通用 I/O 流类

BufferedStream 是向另一个 Stream(例如 NetworkStream)添加缓冲的 Stream。 (FileStream 内部已具有缓冲,MemoryStream 不需要缓冲。)BufferedStream 可以围绕某些类型的流来构成以提高读写性能。 缓冲区是内存中的字节块,用于缓存数据,从而减少对操作系统的调用次数。

CryptoStream 将数据流链接到加密转换。 虽然 CryptoStream 是从 Stream 派生的,但它不属于 System.IO 命名空间,而是在 System.Security.Cryptography 命名空间中。

MemoryStream 是一个非缓冲的流,可以在内存中直接访问它的封装数据。 该流没有后备存储,可用作临时缓冲区。

NetworkStream 表示网络连接上的 Stream。 虽然 NetworkStream 是从 Stream 派生的,但它不属于 System.IO 命名空间,而是在 System.Net.Sockets 命名空间中。

I/O 和安全性

当在 System.IO 命名空间中使用类时,要使访问被允许,则必须满足诸如访问控制列表 (ACL) 等操作系统安全性要求。 此要求是在所有 FileIOPermission 要求之外的要求。

注意

可以以编程方式管理 ACL。 有关更多信息,请参见如何:添加或移除访问控制列表项ACL 技术概述

警告

Internet 和 Intranet 的默认安全策略不允许访问文件。 因此,如果您在编写将通过 Internet 下载的代码,则不要使用常规的非独立存储 I/O 类。 请改用独立存储

警告

当文件或网络流打开时,只有在构造流时才执行安全检查。 因此,在将这些流分发给受信度较低的代码或应用程序域时,请格外小心。

 

如何:复制目录

此示例演示如何使用 I/O 类从一个位置向另一个位置复制目录。 在此示例中,用户可以指定是否同时复制子目录。 如果复制子目录,则此示例中的方法将通过对每个后续子目录调用其自身的方法来递归复制它们,直到再也没有子目录可复制为止。

示例

using System;
using System.IO; class DirectoryCopyExample
{
static void Main()
{
DirectoryCopy(".", @".\temp", true);
} private static void DirectoryCopy(
string sourceDirName, string destDirName, bool copySubDirs)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories(); // If the source directory does not exist, throw an exception.
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
} // If the destination directory does not exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
} // Get the file contents of the directory to copy.
FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files)
{
// Create the path to the new copy of the file.
string temppath = Path.Combine(destDirName, file.Name); // Copy the file.
file.CopyTo(temppath, false);
} // If copySubDirs is true, copy the subdirectories.
if (copySubDirs)
{ foreach (DirectoryInfo subdir in dirs)
{
// Create the subdirectory.
string temppath = Path.Combine(destDirName, subdir.Name); // Copy the subdirectories.
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
 

如何:创建目录列表

下面的代码示例演示如何使用 I/O 类来创建目录中具有“.exe”扩展名的所有文件的列表。

示例

using System;
using System.IO; public class DirectoryLister
{
public static void Main(String[] args)
{
string path = Environment.CurrentDirectory;
if (args.Length > 0)
{
if (Directory.Exists(args[0]))
{
path = args[0];
}
else
{
Console.WriteLine("{0} not found; using current directory:",
args[0]);
}
}
DirectoryInfo dir = new DirectoryInfo(path);
foreach (FileInfo f in dir.GetFiles("*.exe"))
{
string name = f.Name;
long size = f.Length;
DateTime creationTime = f.CreationTime;
Console.WriteLine("{0,-12:N0} {1,-20:g} {2}", size,
creationTime, name);
}
}
}

可靠编程

在本示例中,DirectoryInfo 是当前目录,用 (".") 表示,代码列出了当前目录中具有 .exe 扩展名的所有文件,同时还列出了这些文件的大小、创建时间和名称。 假设 C:\MyDir 的 \Bin 子目录中存在多个 .exe 文件,此代码的输出可能如下所示:

953          7/20/2000 10:42 AM   C:\MyDir\Bin\paramatt.exe
664 7/27/2000 3:11 PM C:\MyDir\Bin\tst.exe
403 8/8/2000 10:25 AM C:\MyDir\Bin\dirlist.exe

如果需要另一个目录(如 C:\ 根目录)中的文件列表,请将参数“C:\”传入编译此代码生成的可执行文件,例如:“testApplication.exe C:\”。

注意

Visual Basic 用户可以选择使用由 FileSystem 类提供的方法和属性执行文件 I/O 操作。

 

如何:枚举目录和文件

从 .NET Framework 4 版开始,可以通过使用一些方法来枚举目录和文件,这些方法返回一个目录和文件的名称字符串的可枚举集合。 也可以使用将返回 DirectoryInfoFileInfoFileSystemInfo 对象的可枚举集合的方法。 在 .NET Framework 的早期版本中,只能获取这些集合的数组。与数组相比,可枚举的集合可提供更好的性能。

此外,还可以使用通过上述方法获得的可枚举集合为集合类(如 List<T> 类)的构造函数提供 IEnumerable<T> 参数。

如果只需要获取目录或文件的名称,请使用 Directory 类的枚举方法。 如果需要获取目录或文件的其他属性,请使用 DirectoryInfoFileSystemInfo 类。 也可以枚举文本文件的各个行。

下表提供了返回可枚举集合的方法的指南。

 

要枚举的项

要返回的可枚举集合

要使用的方法

目录

目录名称。

Directory.EnumerateDirectories

 

目录信息 (DirectoryInfo)。

DirectoryInfo.EnumerateDirectories

文件

文件名称。

Directory.EnumerateFiles

 

文件信息 (FileInfo)。

DirectoryInfo.EnumerateFiles

文件系统信息

文件系统项。

Directory.EnumerateFileSystemEntries

 

文件系统信息 (FileSystemInfo)。

DirectoryInfo.EnumerateFileSystemInfos

文本文件中的行

文件中的行。

File.ReadLines

虽然可以使用 AllDirectories 选项立即枚举父目录的子目录中的所有文件,但未经授权的访问异常 (UnauthorizedAccessException) 可能会导致枚举无法完成。 如果可能出现这些异常,则可以捕获它们并继续操作,采用的方式是先枚举目录,然后再枚举文件。

如果您运行的是 Windows XP 或早期版本,并且如果有一个打开句柄保持在其中一个枚举的目录或文件中,则对遵循枚举的文件或目录执行删除操作可能会失败。 如果出现这种情况,必须包括垃圾回收以移除打开句柄

枚举目录名称

  • 使用 Directory.EnumerateDirectories(String) 方法可按指定路径获取顶级目录名称的列表。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq; class Program
    { private static void Main(string[] args)
    {
    try
    {
    string dirPath = @"\\archives\2009\reports"; // LINQ query.
    var dirs = from dir in
    Directory.EnumerateDirectories(dirPath)
    select dir; // Show results.
    foreach (var dir in dirs)
    {
    // Remove path information from string.
    Console.WriteLine("{0}",
    dir.Substring(dir.LastIndexOf("\\") + 1)); }
    Console.WriteLine("{0} directories found.",
    dirs.Count<string>().ToString()); // Optionally create a List collection.
    List<string> workDirs = new List<string>(dirs);
    }
    catch (UnauthorizedAccessException UAEx)
    {
    Console.WriteLine(UAEx.Message);
    }
    catch (PathTooLongException PathEx)
    {
    Console.WriteLine(PathEx.Message);
    }
    }
    }

枚举所有目录中的文件名称

  • 使用 Directory.EnumerateFiles(String, String, SearchOption) 方法可搜索所有目录以按指定路径获取与指定搜索模式匹配的文件名称的列表。

    using System;
    using System.IO;
    using System.Linq; class Program
    {
    static void Main(string[] args)
    { try
    {
    var files = from file in Directory.EnumerateFiles(@"c:\",
    "*.txt", SearchOption.AllDirectories)
    from line in File.ReadLines(file)
    where line.Contains("Microsoft")
    select new
    {
    File = file,
    Line = line
    }; foreach (var f in files)
    {
    Console.WriteLine("{0}\t{1}", f.File, f.Line);
    }
    Console.WriteLine("{0} files found.",
    files.Count().ToString());
    }
    catch (UnauthorizedAccessException UAEx)
    {
    Console.WriteLine(UAEx.Message);
    }
    catch (PathTooLongException PathEx)
    {
    Console.WriteLine(PathEx.Message);
    }
    }
    }

枚举 DirectoryInfo 对象的集合

  • 使用 DirectoryInfo.EnumerateDirectories 方法可获取顶级目录的集合。

    // Create a DirectoryInfo of the Program Files directory.
    DirectoryInfo dirPrograms = new DirectoryInfo(@"c:\program files"); DateTime StartOf2009 = new DateTime(2009, 01, 01); // LINQ query for all directories created before 2009.
    var dirs = from dir in dirPrograms.EnumerateDirectories()
    where dir.CreationTimeUtc < StartOf2009
    select new
    {
    ProgDir = dir,
    };
    // Show results.
    foreach (var di in dirs)
    {
    Console.WriteLine("{0}", di.ProgDir.Name);
    }

枚举所有目录中的 FileInfo 对象的集合

  • 使用 DirectoryInfo.EnumerateFiles 方法可获取所有目录中与指定搜索模式匹配的文件的集合。 本示例先枚举顶级目录以捕获可能出现的未经授权的访问异常,然后再枚举文件。

    using System;
    using System.IO; class Program
    {
    static void Main(string[] args)
    {
    // Create a DirectoryInfo object of the starting directory.
    DirectoryInfo diTop = new DirectoryInfo(@"d:\");
    try
    {
    // Enumerate the files just in the top directory.
    foreach (var fi in diTop.EnumerateFiles())
    {
    try
    {
    // Display each file over 10 MB;
    if (fi.Length > 10000000)
    {
    Console.WriteLine("{0}\t\t{1}", fi.FullName,
    fi.Length.ToString("N0"));
    }
    }
    // Catch unauthorized access to a file.
    catch (UnauthorizedAccessException UnAuthTop)
    {
    Console.WriteLine("{0}", UnAuthTop.Message);
    }
    }
    // Enumerate all subdirectories.
    foreach (var di in diTop.EnumerateDirectories("*"))
    {
    try
    {
    // Enumerate each file in each subdirectory.
    foreach (var fi in di.EnumerateFiles("*",
    SearchOption.AllDirectories))
    {
    try
    {
    // Display each file over 10 MB;
    if (fi.Length > 10000000)
    {
    Console.WriteLine("{0}\t\t{1}",
    fi.FullName, fi.Length.ToString("N0"));
    }
    }
    // Catch unauthorized access to a file.
    catch (UnauthorizedAccessException UnAuthFile)
    {
    Console.WriteLine("UnAuthFile: {0}",
    UnAuthFile.Message);
    }
    }
    }
    // Catch unauthorized access to a subdirectory.
    catch (UnauthorizedAccessException UnAuthSubDir)
    {
    Console.WriteLine("UnAuthSubDir: {0}",
    UnAuthSubDir.Message);
    }
    }
    }
    // Catch error in directory path.
    catch (DirectoryNotFoundException DirNotFound)
    {
    Console.WriteLine("{0}", DirNotFound.Message);
    }
    // Catch unauthorized access to a first tier directory.
    catch (UnauthorizedAccessException UnAuthDir)
    {
    Console.WriteLine("UnAuthDir: {0}", UnAuthDir.Message);
    }
    // Catch paths that are too long.
    catch (PathTooLongException LongPath)
    {
    Console.WriteLine("{0}", LongPath.Message);
    } }
    }

在枚举的目录或文件中移除打开句柄

  1. 创建自定义方法(在 Visual Basic 中为函数)以包含枚举代码。

  2. MethodImplAttribute 特性和 NoInlining 选项应用于新方法。 例如:

     
    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    Private void Enumerate()
  3. 包括以下方法调用,以在枚举代码后运行:

 

如何:对新建的数据文件进行读取和写入

BinaryWriterBinaryReader 类用于读取和写入数据,而不是用于读取和写入字符串。 下面的代码示例演示如何向新的空文件流 (Test.data) 写入数据及从中读取数据。 在当前目录中创建了数据文件之后,也就同时创建了相关的 BinaryWriterBinaryReaderBinaryWriter 用于向 Test.data 写入整数 0 到 10,Test.data 将文件指针置于文件尾。 在将文件指针设置回初始位置后,BinaryReader 读出指定的内容。

示例

using System;
using System.IO; class MyStream
{
private const string FILE_NAME = "Test.data"; public static void Main()
{
// Create the new, empty data file.
if (File.Exists(FILE_NAME))
{
Console.WriteLine("{0} already exists!", FILE_NAME);
return;
}
using (FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew))
{
// Create the writer for data.
using (BinaryWriter w = new BinaryWriter(fs))
{
// Write data to Test.data.
for (int i = 0; i < 11; i++)
{
w.Write(i);
}
}
}
// Create the reader for data.
using (FileStream fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read))
{
using (BinaryReader r = new BinaryReader(fs))
{
// Read data from Test.data.
for (int i = 0; i < 11; i++)
{
Console.WriteLine(r.ReadInt32());
}
}
}
}
}

可靠编程

如果当前目录中已存在 Test.data,则会引发 IOException。 始终使用 FileMode.Create 创建新文件,而不引发 IOException

 

如何:打开并追加到日志文件

StreamWriterStreamReader 向流写入字符并从流读取字符。 下面的代码示例打开 log.txt 文件(如果文件不存在则创建文件)以进行输入,并将信息附加到文件尾。 然后将文件的内容写入标准输出以便显示。 除此示例演示的做法外,还可以将信息存储为单个字符串或字符串数组,WriteAllTextWriteAllLines 方法可以用于实现相同的功能。

注意

Visual Basic 用户可以选择使用由 Log 类或 FileSystem 类提供的方法和属性创建或写入日志文件。

示例

using System;
using System.IO; class DirAppend
{
public static void Main()
{
using (StreamWriter w = File.AppendText("log.txt"))
{
Log("Test1", w);
Log("Test2", w);
// Close the writer and underlying file.
w.Close();
}
// Open and read the file.
using (StreamReader r = File.OpenText("log.txt"))
{
DumpLog(r);
}
} public static void Log(string logMessage, TextWriter w)
{
w.Write("\r\nLog Entry : ");
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", logMessage);
w.WriteLine ("-------------------------------");
// Update the underlying file.
w.Flush();
} public static void DumpLog(StreamReader r)
{
// While not at the end of the file, read and write lines.
string line;
while ((line = r.ReadLine()) != null)
{
Console.WriteLine(line);
}
r.Close();
}
}
 

如何:向文件写入文本

下面的示例演示如何向文本文件中写入文本。 此示例使用 "*.txt" 搜索模式从用户的“我的文档”文件夹中读取所有文本文件,并将这些文件写入一个大型文本文件。

注意

Visual Basic 用户可以选择使用由 Microsoft.VisualBasic.FileIO.FileSystem 类提供的方法和属性执行文件 I/O 操作。

示例

using System;
using System.IO;
using System.Text;
using System.Collections.Generic; class Program
{ static void Main(string[] args)
{ string mydocpath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
StringBuilder sb = new StringBuilder(); foreach (string txtName in Directory.EnumerateFiles(mydocpath,"*.txt"))
{
using (StreamReader sr = new StreamReader(txtName))
{
sb.AppendLine(txtName.ToString());
sb.AppendLine("= = = = = =");
sb.Append(sr.ReadToEnd());
sb.AppendLine();
sb.AppendLine();
} } using (StreamWriter outfile =
new StreamWriter(mydocpath + @"\AllTxtFiles.txt"))
{
outfile.Write(sb.ToString());
}
}
}
 

如何:从文件读取文本

下面的代码示例演示如何从文本文件中读取文本。 第二个示例在检测到文件结尾时向您发出通知。 通过使用 ReadAllLinesReadAllText 方法也可以实现此功能。

示例

using System;
using System.IO; class Test
{
public static void Main()
{
try
{
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
String line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
catch (Exception e)
{
// Let the user know what went wrong.
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
}
}
 
using System;
using System.IO; public class TextFromFile
{
private const string FILE_NAME = "MyFile.txt"; public static void Main()
{
if (!File.Exists(FILE_NAME))
{
Console.WriteLine("{0} does not exist.", FILE_NAME);
return;
}
using (StreamReader sr = File.OpenText(FILE_NAME))
{
String input;
while ((input = sr.ReadLine()) != null)
{
Console.WriteLine(input);
}
Console.WriteLine ("The end of the stream has been reached.");
}
}
}

可靠编程

此代码通过调用 File.OpenText 创建一个指向 MyFile.txt 的 StreamReaderStreamReader.ReadLine 将每行作为一个字符串返回。 当不再有要读取的字符时,会有一条消息显示该情况,然后流关闭。

注意

Visual Basic 用户可以选择使用由 FileSystem 类提供的方法和属性执行文件 I/O 操作。

 

如何:从字符串中读取字符

下面的代码示例允许您在现有字符串中从指定的位置开始读取一定数目的字符。 请使用 StringReader 完成此操作,如下所示。

此代码定义一个字符串并将其转换为一个字符数组,然后,可以使用适当的 StringReader.Read 方法读取该字符数组。

本示例只从字符串中读取指定数目的字符,如下所示。

示例

using System;
using System.IO; public class CharsFromStr
{
public static void Main()
{
// Create a string to read characters from.
string str = "Some number of characters";
// Make a char array the size of the source string
char[] b = new char[str.Length];
// Create an instance of StringReader and attach it to the string.
StringReader sr = new StringReader(str);
// Read 13 characters into the array that holds the string,
// starting at the third array member.
sr.Read(b, 0, 13);
// Display the output.
Console.WriteLine(b);
// Read the rest of the string from the current position in the
// source string into the array, starting at the 6th array member.
sr.Read(b, 5, str.Length - 13);
// Display the output.
Console.WriteLine(b);
// Close the StringReader.
sr.Close();
}
}
// The example has the following output:
//
// Some number o
// Some f characters
 

如何:向字符串写入字符

下面的代码示例把从字符数组中指定位置开始的一定数目的字符写入现有的字符串。 使用 StringWriter 执行此操作,如下所示。

示例

using System;
using System.IO;
using System.Text; public class CharsToStr
{
public static void Main()
{
// Create an instance of StringBuilder that can then be modified.
StringBuilder sb = new StringBuilder("Some number of characters");
// Define and create an instance of a character array from which
// characters will be read into the StringBuilder.
char[] b = {' ','t','o',' ','w','r','i','t','e',' ','t','o','.'};
// Create an instance of StringWriter
// and attach it to the StringBuilder.
StringWriter sw = new StringWriter(sb);
// Write three characters from the array into the StringBuilder.
sw.Write(b, 0, 3);
// Display the output.
Console.WriteLine(sb);
// Close the StringWriter.
sw.Close();
}
}
using System;
using System.Text; public class Example
{
public static void Main()
{
StringBuilder sb = new StringBuilder();
bool flag = true;
string[] spellings = { "recieve", "receeve", "receive" };
sb.AppendFormat("Which of the following spellings is {0}:", flag);
sb.AppendLine();
for (int ctr = 0; ctr <= spellings.GetUpperBound(0); ctr++) {
sb.AppendFormat(" {0}. {1}", ctr, spellings[ctr]);
sb.AppendLine();
}
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
}
// The example displays the following output:
// Which of the following spellings is True:
// 0. recieve
// 1. receeve
// 2. receive

可靠编程

此示例演示如何使用 StringBuilder 来修改现有的字符串。 请注意,这需要一个附加的 using 声明,因为 StringBuilder 类是 System.Text 命名空间的成员。 另外,这是一个直接创建字符数组并对其进行初始化的示例,而不是定义字符串然后将字符串转换为字符数组。

此代码产生以下输出:

Some number of characters to
 

如何:添加或移除访问控制列表项

要在文件中添加或从文件中移除访问控制列表 (ACL) 项,必须从文件或目录中获得 FileSecurityDirectorySecurity 对象,对其进行修改,然后重新应用回相应的文件或目录。

在文件中添加或移除 ACL 项

  1. 调用 GetAccessControl 方法以获取包含文件的当前 ACL 项的 FileSecurity 对象。

  2. 在从步骤 1 返回的 FileSecurity 对象中添加或移除 ACL 项。

  3. FileSecurity 对象传递到 SetAccessControl 方法以应用更改。

在目录中添加或移除 ACL 项

  1. 调用 GetAccessControl 方法以获取包含目录的当前 ACL 项的 DirectorySecurity 对象。

  2. 在从步骤 1 返回的 DirectorySecurity 对象中添加或移除 ACL 项。

  3. DirectorySecurity 对象传递到 SetAccessControl 方法以应用更改。

示例

using System;
using System.IO;
using System.Security.AccessControl; namespace FileSystemExample
{
class FileExample
{
public static void Main()
{
try
{
string fileName = "test.xml"; Console.WriteLine("Adding access control entry for "
+ fileName); // Add the access control entry to the file.
AddFileSecurity(fileName, @"DomainName\AccountName",
FileSystemRights.ReadData, AccessControlType.Allow); Console.WriteLine("Removing access control entry from "
+ fileName); // Remove the access control entry from the file.
RemoveFileSecurity(fileName, @"DomainName\AccountName",
FileSystemRights.ReadData, AccessControlType.Allow); Console.WriteLine("Done.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
} // Adds an ACL entry on the specified file for the specified account.
public static void AddFileSecurity(string fileName, string account,
FileSystemRights rights, AccessControlType controlType)
{ // Get a FileSecurity object that represents the
// current security settings.
FileSecurity fSecurity = File.GetAccessControl(fileName); // Add the FileSystemAccessRule to the security settings.
fSecurity.AddAccessRule(new FileSystemAccessRule(account,
rights, controlType)); // Set the new access settings.
File.SetAccessControl(fileName, fSecurity); } // Removes an ACL entry on the specified file for the specified account.
public static void RemoveFileSecurity(string fileName, string account,
FileSystemRights rights, AccessControlType controlType)
{ // Get a FileSecurity object that represents the
// current security settings.
FileSecurity fSecurity = File.GetAccessControl(fileName); // Remove the FileSystemAccessRule from the security settings.
fSecurity.RemoveAccessRule(new FileSystemAccessRule(account,
rights, controlType)); // Set the new access settings.
File.SetAccessControl(fileName, fSecurity); }
}
}

编译代码

您必须提供有效的用户或组帐户才能运行此示例。 此示例使用 File 对象;不过,对于 FileInfoDirectoryDirectoryInfo 类使用同一过程。

 

如何:压缩文件

使用 System.IO.Compression.GZipStream 类压缩和解压缩数据。 也可以使用 System.IO.Compression.DeflateStream 类,该类使用相同的压缩算法;不过,可以使用许多常见的压缩工具对写入到扩展名为 .gz 的文件的经过压缩的 GZipStream 对象进行解压缩。

下面的示例演示如何使用 GZipStream 类压缩和解压缩文件目录。

示例

using System;
using System.IO;
using System.IO.Compression; namespace zip
{ public class Program
{ public static void Main()
{
// Path to directory of files to compress and decompress.
string dirpath = @"c:\users\public\reports"; DirectoryInfo di = new DirectoryInfo(dirpath); // Compress the directory's files.
foreach (FileInfo fi in di.GetFiles())
{
Compress(fi); } // Decompress all *.gz files in the directory.
foreach (FileInfo fi in di.GetFiles("*.gz"))
{
Decompress(fi); } } public static void Compress(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Prevent compressing hidden and
// already compressed files.
if ((File.GetAttributes(fi.FullName)
& FileAttributes.Hidden)
!= FileAttributes.Hidden & fi.Extension != ".gz")
{
// Create the compressed file.
using (FileStream outFile =
File.Create(fi.FullName + ".gz"))
{
using (GZipStream Compress =
new GZipStream(outFile,
CompressionMode.Compress))
{
// Copy the source file into
// the compression stream.
inFile.CopyTo(Compress); Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
fi.Name, fi.Length.ToString(), outFile.Length.ToString());
}
}
}
}
} public static void Decompress(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Get original file extension, for example
// "doc" from report.doc.gz.
string curFile = fi.FullName;
string origName = curFile.Remove(curFile.Length -
fi.Extension.Length); //Create the decompressed file.
using (FileStream outFile = File.Create(origName))
{
using (GZipStream Decompress = new GZipStream(inFile,
CompressionMode.Decompress))
{
// Copy the decompression stream
// into the output file.
Decompress.CopyTo(outFile); Console.WriteLine("Decompressed: {0}", fi.Name); }
}
}
} }
}
 

通用 I/O 任务

System.IO 命名空间提供若干个类,通过这些类可以对文件、目录和流执行各种操作(如读取和写入)。 有关更多信息,请参见文件和流 I/O

通用文件任务

若要执行此操作...

请参见本主题中的示例...

创建文本文件。

System.IO.File

写入文本文件。

如何:向文件写入文本

读取文本文件。

如何:从文件读取文本

向文件中追加文本。

如何:打开并追加到日志文件

File.AppendText

FileInfo.AppendText

重命名或移动文件。

File.Move

FileInfo.MoveTo

删除文件。

File.Delete

FileInfo.Delete

复制文件。

File.Copy

FileInfo.CopyTo

获取文件大小。

FileInfo.Length

获取文件特性。

File.GetAttributes

设置文件特性。

File.SetAttributes

确定文件是否存在。

File.Exists

读取二进制文件。

如何:对新建的数据文件进行读取和写入

写入二进制文件。

如何:对新建的数据文件进行读取和写入

检索文件扩展名。

Path.GetExtension

检索文件的完全限定路径。

Path.GetFullPath

检索路径中的文件名和扩展名。

Path.GetFileName

更改文件扩展名。

Path.ChangeExtension

通用目录任务

若要执行此操作...

请参见本主题中的示例...

重命名或移动目录。

Directory.Move

DirectoryInfo.MoveTo

复制目录

如何:复制目录

删除目录。

Directory.Delete

DirectoryInfo.Delete

创建目录。

Directory.CreateDirectory

FileInfo.Directory

创建子目录。

DirectoryInfo.CreateSubdirectory

查看目录中的文件。

FileInfo.Name

查看目录的子目录。

Directory.GetDirectories

DirectoryInfo.GetDirectories

查看目录的所有子目录中的所有文件。

DirectoryInfo.GetFileSystemInfos

查看目录大小。

System.IO.Directory

确定目录是否存在。

Directory.Exists

 

异步文件 I/O

同步 I/O 意味着在 I/O 操作完成之前,方法被阻塞,I/O 操作完成后,方法返回其数据。 使用异步 I/O,用户可以调用 BeginRead。 主线程可以继续进行其他工作,稍后,用户将能够处理数据。 另外,多个 I/O 请求可以被同时挂起。

要在此数据可用时得到通知,您可以调用 EndReadEndWrite,传入与您发出的 I/O 请求对应的 IAsyncResult。 您还可以提供回调方法,该回调方法应调用 EndReadEndWrite 以计算读取或写入了多少字节。 当许多 I/O 请求被同时挂起时,异步 I/O 可以提供较好的性能,但通常要求对您的应用程序进行一些重要的调整以使其正常工作。

Stream 类支持对同一个流混合执行同步读写和异步读写,而不论操作系统是否允许这样做。 Stream 将按照同步实现的方式提供异步读写操作的默认实现,并按照异步实现的方式提供同步读写操作的默认实现。

当实现 Stream 的派生类时,需要为同步或异步 ReadWrite 方法提供实现。 尽管允许重写 ReadWrite,并且异步方法(BeginReadEndReadBeginWriteEndWrite)的默认实现可配合同步方法的实现使用,但这样做不能提供最佳性能。 同样,如果您提供了一个异步方法的实现,同步 ReadWrite 方法也将正常工作;但如果您专门实现同步方法,性能通常会更好。 ReadByteWriteByte 的默认实现调用带有一个元素字节数组的同步 ReadWrite 方法。 当从 Stream 派生类时,如果有内部字节缓冲区,强烈建议重写这些方法以访问内部缓冲区,这样性能将得到提高。

连接到后备存储器的流重写同步或异步 ReadWrite 方法,以获取默认情况下另一种方法的功能。 如果流不支持异步或同步操作,实施者只需让适当的方法引发异常即可。

下面的示例是一个假设的批量图像处理器的异步实现,其后是同步实现的示例。 本代码用于在目录中的每个文件上执行耗费 CPU 资源的操作。 有关更多信息,请参见主题异步编程设计模式

using System;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles; public class BulkImageProcAsync
{
public const String ImageBaseName = "tmpImage-";
public const int numImages = 200;
public const int numPixels = 512 * 512; // ProcessImage has a simple O(N) loop, and you can vary the number
// of times you repeat that loop to make the application more CPU-
// bound or more IO-bound.
public static int processImageRepeats = 20; // Threads must decrement NumImagesToFinish, and protect
// their access to it through a mutex.
public static int NumImagesToFinish = numImages;
public static Object[] NumImagesMutex = new Object[0];
// WaitObject is signalled when all image processing is done.
public static Object[] WaitObject = new Object[0];
public class ImageStateObject
{
public byte[] pixels;
public int imageNum;
public FileStream fs;
} [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public static void MakeImageFiles()
{
int sides = (int)Math.Sqrt(numPixels);
Console.Write("Making {0} {1}x{1} images... ", numImages,
sides);
byte[] pixels = new byte[numPixels];
int i;
for (i = 0; i < numPixels; i++)
pixels[i] = (byte)i;
FileStream fs;
for (i = 0; i < numImages; i++)
{
fs = new FileStream(ImageBaseName + i + ".tmp",
FileMode.Create, FileAccess.Write, FileShare.None,
8192, false);
fs.Write(pixels, 0, pixels.Length);
FlushFileBuffers(fs.SafeFileHandle);
fs.Close();
}
fs = null;
Console.WriteLine("Done.");
} public static void ReadInImageCallback(IAsyncResult asyncResult)
{
ImageStateObject state = (ImageStateObject)asyncResult.AsyncState;
Stream stream = state.fs;
int bytesRead = stream.EndRead(asyncResult);
if (bytesRead != numPixels)
throw new Exception(String.Format
("In ReadInImageCallback, got the wrong number of " +
"bytes from the image: {0}.", bytesRead));
ProcessImage(state.pixels, state.imageNum);
stream.Close(); // Now write out the image.
// Using asynchronous I/O here appears not to be best practice.
// It ends up swamping the threadpool, because the threadpool
// threads are blocked on I/O requests that were just queued to
// the threadpool.
FileStream fs = new FileStream(ImageBaseName + state.imageNum +
".done", FileMode.Create, FileAccess.Write, FileShare.None,
4096, false);
fs.Write(state.pixels, 0, numPixels);
fs.Close(); // This application model uses too much memory.
// Releasing memory as soon as possible is a good idea,
// especially global state.
state.pixels = null;
fs = null;
// Record that an image is finished now.
lock (NumImagesMutex)
{
NumImagesToFinish--;
if (NumImagesToFinish == 0)
{
Monitor.Enter(WaitObject);
Monitor.Pulse(WaitObject);
Monitor.Exit(WaitObject);
}
}
} public static void ProcessImage(byte[] pixels, int imageNum)
{
Console.WriteLine("ProcessImage {0}", imageNum);
int y;
// Perform some CPU-intensive operation on the image.
for (int x = 0; x < processImageRepeats; x += 1)
for (y = 0; y < numPixels; y += 1)
pixels[y] += 1;
Console.WriteLine("ProcessImage {0} done.", imageNum);
} public static void ProcessImagesInBulk()
{
Console.WriteLine("Processing images... ");
long t0 = Environment.TickCount;
NumImagesToFinish = numImages;
AsyncCallback readImageCallback = new
AsyncCallback(ReadInImageCallback);
for (int i = 0; i < numImages; i++)
{
ImageStateObject state = new ImageStateObject();
state.pixels = new byte[numPixels];
state.imageNum = i;
// Very large items are read only once, so you can make the
// buffer on the FileStream very small to save memory.
FileStream fs = new FileStream(ImageBaseName + i + ".tmp",
FileMode.Open, FileAccess.Read, FileShare.Read, 1, true);
state.fs = fs;
fs.BeginRead(state.pixels, 0, numPixels, readImageCallback,
state);
} // Determine whether all images are done being processed.
// If not, block until all are finished.
bool mustBlock = false;
lock (NumImagesMutex)
{
if (NumImagesToFinish > 0)
mustBlock = true;
}
if (mustBlock)
{
Console.WriteLine("All worker threads are queued. " +
" Blocking until they complete. numLeft: {0}",
NumImagesToFinish);
Monitor.Enter(WaitObject);
Monitor.Wait(WaitObject);
Monitor.Exit(WaitObject);
}
long t1 = Environment.TickCount;
Console.WriteLine("Total time processing images: {0}ms",
(t1 - t0));
} public static void Cleanup()
{
for (int i = 0; i < numImages; i++)
{
File.Delete(ImageBaseName + i + ".tmp");
File.Delete(ImageBaseName + i + ".done");
}
} public static void TryToClearDiskCache()
{
// Try to force all pending writes to disk, and clear the
// disk cache of any data.
byte[] bytes = new byte[100 * (1 << 20)];
for (int i = 0; i < bytes.Length; i++)
bytes[i] = 0;
bytes = null;
GC.Collect();
Thread.Sleep(2000);
} public static void Main(String[] args)
{
Console.WriteLine("Bulk image processing sample application," +
" using asynchronous IO");
Console.WriteLine("Simulates applying a simple " +
"transformation to {0} \"images\"", numImages);
Console.WriteLine("(Async FileStream & Threadpool benchmark)");
Console.WriteLine("Warning - this test requires {0} " +
"bytes of temporary space", (numPixels * numImages * 2)); if (args.Length == 1)
{
processImageRepeats = Int32.Parse(args[0]);
Console.WriteLine("ProcessImage inner loop - {0}.",
processImageRepeats);
}
MakeImageFiles();
TryToClearDiskCache();
ProcessImagesInBulk();
Cleanup();
}
[DllImport("KERNEL32", SetLastError = true)]
private static extern void FlushFileBuffers(SafeFileHandle handle);
}

以下是同一假设的同步示例。

using System;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles; public class BulkImageProcSync
{
public const String ImageBaseName = "tmpImage-";
public const int numImages = 200;
public const int numPixels = 512 * 512; // ProcessImage has a simple O(N) loop, and you can vary the number
// of times you repeat that loop to make the application more CPU-
// bound or more IO-bound.
public static int processImageRepeats = 20; [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public static void MakeImageFiles()
{
int sides = (int)Math.Sqrt(numPixels);
Console.Write("Making {0} {1}x{1} images... ", numImages,
sides);
byte[] pixels = new byte[numPixels];
int i;
for (i = 0; i < numPixels; i++)
pixels[i] = (byte)i;
FileStream fs;
for (i = 0; i < numImages; i++)
{
fs = new FileStream(ImageBaseName + i + ".tmp",
FileMode.Create, FileAccess.Write, FileShare.None,
8192, false);
fs.Write(pixels, 0, pixels.Length);
FlushFileBuffers(fs.SafeFileHandle);
fs.Close();
}
fs = null;
Console.WriteLine("Done.");
} public static void ProcessImage(byte[] pixels, int imageNum)
{
Console.WriteLine("ProcessImage {0}", imageNum);
int y;
// Perform some CPU-intensive operation on the image.
for (int x = 0; x < processImageRepeats; x += 1)
for (y = 0; y < numPixels; y += 1)
pixels[y] += 1;
Console.WriteLine("ProcessImage {0} done.", imageNum);
} public static void ProcessImagesInBulk()
{
Console.WriteLine("Processing images... ");
long t0 = Environment.TickCount;
byte[] pixels = new byte[numPixels];
FileStream input;
FileStream output;
for (int i = 0; i < numImages; i++)
{
input = new FileStream(ImageBaseName + i + ".tmp",
FileMode.Open, FileAccess.Read, FileShare.Read,
4196, false);
input.Read(pixels, 0, numPixels);
input.Close();
ProcessImage(pixels, i);
output = new FileStream(ImageBaseName + i + ".done",
FileMode.Create, FileAccess.Write, FileShare.None,
4196, false);
output.Write(pixels, 0, numPixels);
output.Close();
}
input = null;
output = null;
long t1 = Environment.TickCount;
Console.WriteLine("Total time processing images: {0}ms",
(t1 - t0));
} public static void Cleanup()
{
for (int i = 0; i < numImages; i++)
{
File.Delete(ImageBaseName + i + ".tmp");
File.Delete(ImageBaseName + i + ".done");
}
} public static void TryToClearDiskCache()
{
byte[] bytes = new byte[100 * (1 << 20)];
for (int i = 0; i < bytes.Length; i++)
bytes[i] = 0;
bytes = null;
GC.Collect();
Thread.Sleep(2000);
} public static void Main(String[] args)
{
Console.WriteLine("Bulk image processing sample application," +
" using synchronous I/O.");
Console.WriteLine("Simulates applying a simple " +
"transformation to {0} \"images.\"", numImages);
Console.WriteLine("(ie, Sync FileStream benchmark).");
Console.WriteLine("Warning - this test requires {0} " +
"bytes of temporary space", (numPixels * numImages * 2)); if (args.Length == 1)
{
processImageRepeats = Int32.Parse(args[0]);
Console.WriteLine("ProcessImage inner loop ? {0}",
processImageRepeats);
} MakeImageFiles();
TryToClearDiskCache();
ProcessImagesInBulk();
Cleanup();
} [DllImport("KERNEL32", SetLastError = true)]
private static extern void FlushFileBuffers(SafeFileHandle handle);
}
 

最新文章

  1. html页面读取PDF小案例
  2. css 选择器优先级
  3. 将NSString转换成UTF8编码的NSString
  4. LoadRunner 常用C语言函数使用
  5. 20 Web 编程 - 《Python 核心编程》
  6. mysql引擎互转问题
  7. SQL Server 的远程连接(转载)
  8. 读取App.config自定义标签的值
  9. 【译】Optimize for mobile-移动端优化
  10. SDUT OJ 2783 小P寻宝记
  11. android 获取http网络图片保存png
  12. flex4 amcharts 删除水印
  13. Java 容器在实际项目开发中应用
  14. 编程零基础应当如何开始学习 Python?
  15. 解决反序列化(Deserialize)无法找到程序集的错误
  16. Django REST framework中的版本控制
  17. linux 显示当前所在文件位置 以及git 分支所在
  18. js 中 的 BOM对象
  19. adb 常用命名
  20. Gradle学习系列之读懂Gradle语法

热门文章

  1. python闭包的使用
  2. 设计基于HTML5的APP登录功能及安全调用接口的方式
  3. js执行顺序——学习笔记
  4. 倒计时和div幻灯片
  5. 高性能队列disruptor为什么这么快?
  6. dubbo面试题
  7. jQuery中$this和$(this)的区别
  8. ios 布局 素材 待整理
  9. SQlite数据库框架:LitePal
  10. jmeter接口测试小结