基本的文件I/O
基本的文件 I/O
抽象基类 Stream 支持读取和写入字节。 Stream 集成了异步支持。 其默认实现根据其相应的异步方法来定义同步读取和写入,反之亦然。
所有表示流的类都是从 Stream 类继承的。 Stream 类及其派生类提供数据源和储存库的一般视图,使程序员不必了解操作系统和基础设备的具体细节。
流涉及三个基本操作:
可以从流读取。 读取是从流到数据结构(如字节数组)的数据传输。
可以向流写入。 写入是从数据源到流的数据传输。
流可以支持查找。 查找是对流内的当前位置进行的查询和修改。
根据基础数据源或储存库,流可能只支持这些功能中的一部分。 例如,NetworkStreams 不支持查找。 Stream 及其派生类的 CanRead、CanWrite 和 CanSeek 属性决定了不同流所支持的操作。
有关通用 I/O 任务的列表,请参见通用 I/O 任务。
注意 |
---|
Visual Basic 用户可以选择使用由 Microsoft.VisualBasic.FileIO.FileSystem 类提供的方法和属性执行文件 I/O 操作。 |
用于文件 I/O 的类
Directory 提供创建、移动和枚举目录和子目录的静态方法。 DirectoryInfo 类提供实例方法。
DirectoryInfo 提供创建、移动和枚举目录和子目录的实例方法。 Directory 类提供静态方法。
DriveInfo 提供访问有关驱动器的信息的实例方法。
File 提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建 FileStream。 FileInfo 类提供实例方法。
FileInfo 提供用于创建、复制、删除、移动和打开文件的实例方法,并协助创建 FileStream。 File 类提供静态方法。
FileStream 支持通过其 Seek 方法随机访问文件。 默认情况下,FileStream 以同步方式打开文件,但它也支持异步操作。 File 包含静态方法,而 FileInfo 包含实例方法。
FileSystemInfo 是 FileInfo 和 DirectoryInfo 的抽象基类。
Path 提供以跨平台的方式处理目录字符串的方法和属性。
DeflateStream 提供使用 Deflate 算法压缩和解压缩流的方法和属性。
GZipStream 提供压缩和解压缩流的方法和属性。 默认情况下,此类使用与 DeflateStream 类相同的算法,但可以扩展到使用其他压缩格式。
SerialPort 提供控制串行端口文件资源的方法和属性。
File、FileInfo、DriveInfo、Path、Directory 和 DirectoryInfo 是密封(在 Microsoft Visual Basic 中为 NotInheritable)类。 可以创建这些类的新实例,但它们不能有派生类。
用于从流读取和写入流的类
BinaryReader 和 BinaryWriter 在 Streams 中读取和写入编码的字符串和基元数据类型。
StreamReader 通过使用 Encoding 进行字符和字节的转换,从 Streams 中读取字符。 StreamReader 具有一个构造函数,该构造函数根据是否存在专用于 Encoding 的 preamble(例如一个字节顺序标记)来尝试确定给定 Stream 的正确 Encoding 是什么。
StreamWriter 通过使用 Encoding 将字符转换为字节,向 Streams 写入字符。
StringReader 从 Strings 中读取字符。 StringReader 允许您用相同的 API 来处理 Strings,因此您的输出可以是 String 或以任何编码表示的 Stream。
StringWriter 向 Strings 写入字符。 StringWriter 允许您用相同的 API 来处理 Strings,因此您的输出可以是 String 或以任何编码表示的 Stream。
TextReader 是 StreamReader 和 StringReader 的抽象基类。 抽象 Stream 类的实现用于字节输入和输出,而 TextReader 的实现用于 Unicode 字符输出。
TextWriter 是 StreamWriter 和 StringWriter 的抽象基类。 抽象 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 版开始,可以通过使用一些方法来枚举目录和文件,这些方法返回一个目录和文件的名称字符串的可枚举集合。 也可以使用将返回 DirectoryInfo、FileInfo 或 FileSystemInfo 对象的可枚举集合的方法。 在 .NET Framework 的早期版本中,只能获取这些集合的数组。与数组相比,可枚举的集合可提供更好的性能。
此外,还可以使用通过上述方法获得的可枚举集合为集合类(如 List<T> 类)的构造函数提供 IEnumerable<T> 参数。
如果只需要获取目录或文件的名称,请使用 Directory 类的枚举方法。 如果需要获取目录或文件的其他属性,请使用 DirectoryInfo 和 FileSystemInfo 类。 也可以枚举文本文件的各个行。
下表提供了返回可枚举集合的方法的指南。
要枚举的项 |
要返回的可枚举集合 |
要使用的方法 |
---|---|---|
目录 |
目录名称。 |
|
目录信息 (DirectoryInfo)。 |
||
文件 |
文件名称。 |
|
文件信息 (FileInfo)。 |
||
文件系统信息 |
文件系统项。 |
|
文件系统信息 (FileSystemInfo)。 |
||
文本文件中的行 |
文件中的行。 |
虽然可以使用 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);
} }
}
在枚举的目录或文件中移除打开句柄
创建自定义方法(在 Visual Basic 中为函数)以包含枚举代码。
将 MethodImplAttribute 特性和 NoInlining 选项应用于新方法。 例如:
[MethodImplAttribute(MethodImplOptions.NoInlining)]
Private void Enumerate()包括以下方法调用,以在枚举代码后运行:
GC.Collect() 方法(无参数)。
如何:对新建的数据文件进行读取和写入
BinaryWriter 和 BinaryReader 类用于读取和写入数据,而不是用于读取和写入字符串。 下面的代码示例演示如何向新的空文件流 (Test.data) 写入数据及从中读取数据。 在当前目录中创建了数据文件之后,也就同时创建了相关的 BinaryWriter 和 BinaryReader,BinaryWriter 用于向 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。
如何:打开并追加到日志文件
StreamWriter 和 StreamReader 向流写入字符并从流读取字符。 下面的代码示例打开 log.txt 文件(如果文件不存在则创建文件)以进行输入,并将信息附加到文件尾。 然后将文件的内容写入标准输出以便显示。 除此示例演示的做法外,还可以将信息存储为单个字符串或字符串数组,WriteAllText 或 WriteAllLines 方法可以用于实现相同的功能。
注意 |
---|
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());
}
}
}
如何:从文件读取文本
下面的代码示例演示如何从文本文件中读取文本。 第二个示例在检测到文件结尾时向您发出通知。 通过使用 ReadAllLines 或 ReadAllText 方法也可以实现此功能。
示例
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 的 StreamReader。 StreamReader.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) 项,必须从文件或目录中获得 FileSecurity 或 DirectorySecurity 对象,对其进行修改,然后重新应用回相应的文件或目录。
在文件中添加或移除 ACL 项
调用 GetAccessControl 方法以获取包含文件的当前 ACL 项的 FileSecurity 对象。
在从步骤 1 返回的 FileSecurity 对象中添加或移除 ACL 项。
将 FileSecurity 对象传递到 SetAccessControl 方法以应用更改。
在目录中添加或移除 ACL 项
调用 GetAccessControl 方法以获取包含目录的当前 ACL 项的 DirectorySecurity 对象。
在从步骤 1 返回的 DirectorySecurity 对象中添加或移除 ACL 项。
将 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 对象;不过,对于 FileInfo、Directory 和 DirectoryInfo 类使用同一过程。
如何:压缩文件
使用 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 任务
通用文件任务
若要执行此操作... |
请参见本主题中的示例... |
---|---|
创建文本文件。 |
|
写入文本文件。 |
|
读取文本文件。 |
|
向文件中追加文本。 |
|
重命名或移动文件。 |
|
删除文件。 |
|
复制文件。 |
|
获取文件大小。 |
|
获取文件特性。 |
|
设置文件特性。 |
|
确定文件是否存在。 |
|
读取二进制文件。 |
|
写入二进制文件。 |
|
检索文件扩展名。 |
|
检索文件的完全限定路径。 |
|
检索路径中的文件名和扩展名。 |
|
更改文件扩展名。 |
通用目录任务
若要执行此操作... |
请参见本主题中的示例... |
---|---|
重命名或移动目录。 |
|
复制目录 |
|
删除目录。 |
|
创建目录。 |
|
创建子目录。 |
|
查看目录中的文件。 |
|
查看目录的子目录。 |
|
查看目录的所有子目录中的所有文件。 |
|
查看目录大小。 |
|
确定目录是否存在。 |
异步文件 I/O
同步 I/O 意味着在 I/O 操作完成之前,方法被阻塞,I/O 操作完成后,方法返回其数据。 使用异步 I/O,用户可以调用 BeginRead。 主线程可以继续进行其他工作,稍后,用户将能够处理数据。 另外,多个 I/O 请求可以被同时挂起。
要在此数据可用时得到通知,您可以调用 EndRead 或 EndWrite,传入与您发出的 I/O 请求对应的 IAsyncResult。 您还可以提供回调方法,该回调方法应调用 EndRead 或 EndWrite 以计算读取或写入了多少字节。 当许多 I/O 请求被同时挂起时,异步 I/O 可以提供较好的性能,但通常要求对您的应用程序进行一些重要的调整以使其正常工作。
Stream 类支持对同一个流混合执行同步读写和异步读写,而不论操作系统是否允许这样做。 Stream 将按照同步实现的方式提供异步读写操作的默认实现,并按照异步实现的方式提供同步读写操作的默认实现。
当实现 Stream 的派生类时,需要为同步或异步 Read 和 Write 方法提供实现。 尽管允许重写 Read 和 Write,并且异步方法(BeginRead、EndRead、BeginWrite 和 EndWrite)的默认实现可配合同步方法的实现使用,但这样做不能提供最佳性能。 同样,如果您提供了一个异步方法的实现,同步 Read 和 Write 方法也将正常工作;但如果您专门实现同步方法,性能通常会更好。 ReadByte 和 WriteByte 的默认实现调用带有一个元素字节数组的同步 Read 和 Write 方法。 当从 Stream 派生类时,如果有内部字节缓冲区,强烈建议重写这些方法以访问内部缓冲区,这样性能将得到提高。
连接到后备存储器的流重写同步或异步 Read 和 Write 方法,以获取默认情况下另一种方法的功能。 如果流不支持异步或同步操作,实施者只需让适当的方法引发异常即可。
下面的示例是一个假设的批量图像处理器的异步实现,其后是同步实现的示例。 本代码用于在目录中的每个文件上执行耗费 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);
}
基本的文件I/O的更多相关文章
- Mapreduce的文件和hbase共同输入
Mapreduce的文件和hbase共同输入 package duogemap; import java.io.IOException; import org.apache.hadoop.co ...
- mapreduce多文件输出的两方法
mapreduce多文件输出的两方法 package duogemap; import java.io.IOException; import org.apache.hadoop.conf ...
- 01.SQLServer性能优化之----强大的文件组----分盘存储
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 文章内容皆自己的理解,如有不足之处欢迎指正~谢谢 前天有学弟问逆天:“逆天,有没有一种方 ...
- SQL Server 大数据搬迁之文件组备份还原实战
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 解决方案(Solution) 搬迁步骤(Procedure) 搬迁脚本(SQL Codes) ...
- SQLSERVER将一个文件组的数据移动到另一个文件组
SQLSERVER将一个文件组的数据移动到另一个文件组 有经验的大侠可以直接忽视这篇文章~ 这个问题有经验的人都知道怎麽做,因为我们公司的数据量不大没有这个需求,也不知道怎麽做实验 今天求助了QQ群里 ...
- SQL Server中的高可用性(2)----文件与文件组
在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...
- C# ini文件操作【源码下载】
介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...
- 【小程序分享篇 一 】开发了个JAVA小程序, 用于清除内存卡或者U盘里的垃圾文件非常有用
有一种场景, 手机内存卡空间被用光了,但又不知道哪个文件占用了太大,一个个文件夹去找又太麻烦,所以我开发了个小程序把手机所有文件(包括路径下所有层次子文件夹下的文件)进行一个排序,这样你就可以找出哪个 ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- GreenDao 数据库:使用Raw文件夹下的数据库文件以及数据库升级
一.使用Raw文件夹下的数据库文件 在使用GreenDao框架时,数据库和数据表都是根据生成的框架代码来自动创建的,从生成的DaoMaster中的OpenHelper类可以看出: public sta ...
随机推荐
- view 的继承关系
view 的继承关系 如果一个view 有多个子view. 甚至是多成次的 子view. 只需要把第一级别的view(父view) 授权给用户,就可以访问view了,子view 不需要授权.
- Linux shell命令之cat
cat:查看文件的内容.连接文件.创建一个或多个文件和重定向输出到终端或文件 用法:cat [选项] [文件] 1. $ cat hello.txt 显示hello.txt文本文件中的内容 2. $ ...
- sql剪切数据
实际项目当中用到的案例,个人笔记. USE [CA-SM]GO/****** Object: StoredProcedure [dbo].[PG_SM_AddSum] Script Date: ...
- AndroidStudio3.0 Canary 8注解报错Annotation processors must be explicitly declared now.
体验最新版AndroidStudio3. Canary 8的时候,发现之前项目的butter knife报错,用到注解的应该都会报错 Error:Execution failed for task ' ...
- Solr搜索引擎 — 通过mysql配置数据源
一,准备数据库数据表结构 CREATE TABLE `app` ( `id` int(11) NOT NULL AUTO_INCREMENT, `app_name` varchar(255) NOT ...
- Shell输入/输出重定向
输出重定向 重定向一般通过在命令间插入特定的符号来实现.特别的,这些符号的语法如下所示 command1 >file1 上面这个命令执行command1然后将输出的内容存入file1. 注意任何 ...
- BZOJ1996: [Hnoi2010]chorus 合唱队 (DP)
就是想水一发 #include <stdio.h> #include <algorithm> #include <iostream> using namespace ...
- eBPF监控工具bcc系列五工具funccount
eBPF监控工具bcc系列五工具funccount funccount函数可以通过匹配来跟踪函数,tracepoints 或USDT探针.例如所有以vfs_ 开头的内核函数. ./funccount ...
- 实战:tcp链接rst场景tcpdump分析
RST为重置报文段,它会导致TCP连接的快速拆迁,且不需要ack进行确认. 1.针对不存在的端口的连请求 客户端: #include <unistd.h> #include <sys ...
- .Net Core2.2 + EF Core + DI,三层框架项目搭建教程
笔记: 近两年.Net Core发展的很快,目前最新版为3.0预览版,之前在网上买了一本1.1版书籍都还没来得及看呢,估计现在拿出来看也毫无意义了.已多年.net工作经验,看书不如直接实际上手来得快, ...