文件(file)是存储在磁盘上的一组信息的集合;目录(directory),即文件夹,是组织多个文件的方式;注册表(registry)则是操作系统中存储各种配置信息的其中地(数据库)。
文件与目录管理
C#支持文件管理和目录管理,它们由System.IO
命名空间中的相关类来实现。这些类不是Stream或者TextReader的子类,因为它们不负责内容的输入/输出,而是用来专门管理磁盘文件和目录的。
文件和目录由System.IO
命名空间中的6个类来表示。
- ①
FileSystemInfo
——FileInfo和DirectoryInfo的基类 - ②
File
——包含对文件进行操作的静态方法 - ③
FileInfo
——用来表示某个文件并对其进行操作 - ④
Directory
——包含对目录进行操作的静态方法 - ⑤
DirectoryInfo
——用来表示某个目录并对其进行操作 - ⑥
Path
——用来对路径信息进行操作
1.FileSystemInfo类
FieSystemlnfo类是 Filelnfo和 Directorylnfo的基类,用于对文件和目录进行操作。该类提供了文件和目录中通用的很多方法和属性。
2.File类
下表是File类中所提供的方法:
示例,直接使用File类进行内容的读取,并将各行显示出来:
using System;
using System.IO;
class FileOpenText
{
static void Main(){
StreamReader sr = File.OpenText(".\\FileOpenText.cs");
string contents = sr.ReadToEnd();
sr.Close();
string[] lines = contents.Split(new char[] {
'\n' });
for(int i = 0; i < lines.Length; i++)
Console.WriteLine(i + ":\t" + lines[i]);
}
}
虽然File.OpenText()
很方便,但对于一些不同编码方式的文件(如汉字GB码),不能直接使用File.OpenText()
。可以使用FileStream
,在包装成StreamReader
并加上编码方式;也可以直接生成StreamReader
对象并指定编码方式(如Encoding.Default
)。
3.FileInfo类
FileInfo
类用来表示文件路径。与File
类不同的是,其成员全都是非static
的。有部分功能既可以用File
类来实现,也可以用FileInfo
类来实现。注意:File类中的所有方法都需要安全性检验。如果要对同一文件执行很多操作,那么创建一个FileInfo
对象进行处理效率将会更高,因为FileInfo对象不会每次调用都需要进行安全性检验。
FileInfo类中的方法和属性是从其父类FileSystemInfo
中继承而来的。
4.Directory类
Directory
类提供可以对目录进行操作的静态方法,包含了对目录进行创建、删除、移动、拷贝以及列表等操作。一个Directory
对象可以用来表示对已经存在的目录进行命名的路径,或者用来创建一个新的目录。
5.DirectoryInfo类
DirectoryInfo
类用来表示目录。一个DirectoryInfo
对象表示一个路径,该路径或者是用来命名已存在的目录,或者用来创建一个新的目录。
6.Path类
使用Path
类可以以跨平台方式处理文件和目录的路径名称。该类中所有方法都是static
的。
例,ListAlFiles.cs 递归地列出某目录下的所有文件。
using System;
using System.IO;
class ListAllFiles
{
public static void Main(){
ListFiles(new DirectoryInfo(@"C:\Users\Frenkie\Desktop"));
}
public static void ListFiles(FileSystemInfo info) {
if (!info.Exists) return;
DirectoryInfo dir = info as DirectoryInfo;
if (dir == null) return; // 不是目录
FileSystemInfo[] files = dir.GetFileSystemInfos();
for (int i = 0; i < files.Length; i++) {
FileInfo file = files[i] as FileInfo;
if (file != null) // 是文件
Console.WriteLine(file.FullName + "\t" + file.Length);
else // 是目录
ListFiles(files[i]);// 对于子目录, 进行递归调用
}
}
}
监控文件和目录的改动
1.FileSystemWatcher类
FileSystemWatcher
是一个非常有用的类,用它可以监测指定目录中的文件和子目录的变化。被检测的目录可以在本地机器上,也可以是网络驱动器,甚至可以是远程机器上的目录。
在程序中可以创建一个FileSystemWatcher
对象用来监视某个指定的目录,当被监视目录下的文件或子目录发生创建、修改以及删除等操作时,该对象可以产生事件作为响应。
2.Path及Filter属性
FileSystemWatcher
的Path
属性,指明要监视的目录。
Filter
属性用以指明监视该目录下的某些文件。例如,若要监视文本文件的更改,应将Filter属性设置为"*.txt"
。如果只监视某一个文件,则用其文件名。要监视所有文件中的更改,应将Filter属性设置为空字符串(""
)。IncludeSubdirectories
属性用以指明是否要包括子目录。
3.NotifyFilters属性
可监视目录或文件中的若干种更改。例如,可以监视文件或目录的Attributes、LastWrite日期和时间或Size方面的修改。通过将FileSystemWatcher.NotifyFilter
属性设置为NotifyFilters
值之一或其组合来达到此目的。
4.事件
当文件和目录发生改动时,FileSystemWatcher
可以通过产生一个事件来做响应,这时客户代码就需要执行某些事件处理器代码。
公共文件系统操作可能会引发多个事件。例如,将文件从一个目录移到另一个目录时,可能会引发若干Changed
以及一些Created
和Deleted
事件。移动文件是一个包含多个简单操作的复杂操作,因此会引发多个事件。同样,一些应用程序(如反病毒软件)可能导致被FileSystemWatcher
检测到的附加文件系统事件。
事件处理所用的代理是FileSystemEventHandler
及RenamedEventHandler
。 在事件的处理函数中的参数中除了object sender
以处,还有一个是FileSystemEventArgs
对象,包含了事件相关的信息。FieSystemEventArgs 的最有用的属性如下:
- ①
FullPath
——包含引发事件的文件或目录的完整路径 - ②
Name
——只包含文件或目录的名称 - ③
ChangeType
——告知所改动的类型
而RenamedEventArgs
中的最常用的属性是 OldFullPah
和FullPah
,分别表示原来的名字及后来的名字。
当程序中设置 EnableRaisingEvents
属性为 true
时,就会开始监视。
要注意的是,过多、过快的事件,可能导致系统需要更多的缓冲区,并会产生系统效率 的下降。因此,要合理地使用Filter
,NotifyFilter
和IncludeSubdirectories
属性,以便可筛选掉不想要的更改通知。
例,Watcher. cs 使用 FileSystemWatcher 监视文件的改动。
using System;
using System.IO;
class Watcher
{
public static void TestMain() {
const string path = @"E:\Visual Studio 2019\C#\Mooc学习\ConsoleApp18流、文件IO\bin\Debug";
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.Filter = "*.txt";
watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite | NotifyFilters.FileName |
NotifyFilters.DirectoryName;
// 事件处理函数
watcher.Changed += OnChanged;
watcher.Created += OnChanged;
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// 开始监视
watcher.EnableRaisingEvents = true;
// 等待用户输入q才结束程序
Console.WriteLine("Press'q' to quit the sample.");
while (Console.Read() != 'q') {
}
}
// 事件处理函数
private static void OnChanged(object sender, FileSystemEventArgs e) {
// 显示哪些文件做了何种修改
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}
private static void OnRenamed(object sender, RenamedEventArgs e) {
// 显示被更改的文件名
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
}
注册表
示例,RegistryDemo.cs 获取及设置注册表。
using Microsoft.Win32;
using System;
class RegistryDemo
{
public static void TestMain() {
// 获取信息
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Main");
string page = key.GetValue("Start Page") as string;
Console.WriteLine("浏览器的起始页是" + page);
// 设置信息
RegistryKey test = Registry.CurrentUser.CreateSubKey("MyTest");
using (RegistryKey mySetting = test.CreateSubKey("MySetting")) {
mySetting.SetValue("ID", 123);
mySetting.SetValue("Language", "Chinese");
mySetting.SetValue("WindowSize", "Max");
mySetting.SetValue("LastLogin", DateTime.Now.ToString());
}
// 查询信息
RegistryKey setting = Registry.CurrentUser.OpenSubKey(@"MyTest\MySetting");
foreach (string name in setting.GetValueNames())
Console.WriteLine(name + ":" + setting.GetValue(name));
}
}
运行结果:
在实际工作中,可以将程序中的一些设置项保存到注册表中,下一次运行时先从注册表中读取这些注册项。
注意:操作注册表有可能造成系统故障,若是对Windows注册表不熟悉,尽量不要随意操作注册表。另外,有的注册表项需要特定权限才能进行修改。