四、文件监视类:FileSystemWatcher
侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。可借助FileSystemWatcher会更简单些。
1、属性:
(1)Path——这个属性告诉FileSystemWatcher它需要监控哪条路径。例如,如果我们将这个属性设为“C:\test”,对象就监控test目录下所有文件发生的所有改变(包括删除,修改,创建,重命名)。
(2)IncludeSubDirectories——这个属性说明FileSystemWatcher对象是否应该监控子目录中(所有文件)发生的改变。
(3)Filter——这个属性允许你过滤掉某些类型的文件发生的变化。例如,如果我们只希望在TXT文件被修改/新建/删除时提交通知,可以将这个属性设为“*txt”。在处理高流量或大型目录时,使用这个属性非常方便。
(4)NotifyFilter——获取或设置要监视的更改类型。可以进一步的过滤要监控的更改类型:如watcher.NotifyFilter= NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
2、事件:
(1)Changed——当被监控的目录中有一个文件被修改时,就提交这个事件。值得注意的是,这个事件可能会被提交多次,即使文件的内容仅仅发生一项改变。这是由于在保存文件时,文件的其它属性也发生了改变。
(2)Created——当被监控的目录新建一个文件时,就提交这个事件。如果你计划用这个事件移动新建的事件,你必须在事件处理器中写入一些错误处理代码,它能处理当前文件被其它进程使用的情况。之所以要这样做,是因为Created事件可能在建立文件的进程释放文件之前就被提交。如果你没有准备正确处理这种情况的代码,就可能出现异常。
(3)Deleted——当被监控的目录中有一个文件被删除,就提交这个事件。
(4)Renamed——当被监控的目录中有一个文件被重命名,就提交这个事件。
注:如果你没有将EnableRaisingEvents设为真,系统不会提交任何一个事件。如果有时FileSystemWatcher对象似乎无法工作,请首先检查EnableRaisingEvents,确保它被设为真。
3、事件处理
当FileSystemWatcher调用一个事件处理器时,它包含两个自变量——一个叫做“sender”的对象和一个叫做“e”的FileSystemEventArgs对象。我们感兴趣的自变量为FileSystemEventArgs自变量。这个对象中包含有提交事件的原因。以下是FileSystemEventArgs对象的一些属性:
属性:
(1)Name——这个属性中使事件被提交的文件的名称。其中并不包含文件的路径——只包含使用事件被提交的文件或目录名称。
(2)ChangeType——这是一个WatcherChangeTypes,它指出要提交哪个类型的事件。其有效值包括:Changed,Created,Deleted,Renamed
(3)FullPath——这个属性中包含使事件被提交的文件的完整路径,包括文件名和目录名。
注意:FileSystemEventArgs对象是监控文件夹下有文件创建、删除、修改时的自变量,如果是重命名的话为RenamedEventArgs对象此时除了FileSystemEventArgs对象的属性值,多了一个OldFullPath,为重命名之前的文件名。
五、文件的读取和写入文件
1、流的概念:在.net FrameWork中进行的所有的输入输出工作都需要使用流.流是串行化设备的抽象表示.串行化设备可以以线性方式存储数据,并可以以同样的方式访问:一次访问一个字节.此设备可以是磁盘文件,打印机,内存位置或任何其他支持以线性方式读写的对象.通过使用设备抽象,就可以隐藏流的基础性的目标或源.这种抽象的级别使得代码可以重用,允许我们编写更通用的程序.因此,当程序从文件输入流或网络输入流读取数据时,就可以转换并重用类似的代码.而且,通过使用流,我们还可以忽略每一种设备的物理机制.因此为了从文件流中读取文件,我们无须担心磁盘开销或内存分配等问题
C# 中Stream类是所有流的抽象基类,它可以为流提供一般性视图,从而使得开发人员不需要了解I/O设备的具体细节。与流相关的操作包括以下3个基本操作。
读取流:即读取流中的内容。
写入流:即将指定的内容写入到流中。
流支持查找:即可以查找或设置流的当前位置。
与流相关的、最为常用的类包括Stream类、FileStream类(文件流,常用于操作文件)、MemoryStream类(内存流,常用来操作内存中的数据)和BufferedStream类(缓存流,用来操作缓存中的数据)。其中Stream类为抽象类,FileStream类、MemoryStream类和BufferedStream类从直接继承于Stream类,它们是实体类。
2、使用FileStream类管理文件数据
先看几个例子:
(1) 使用FileStream流写入文本文件:
static void Main(string[] args)
{
string str = "helloworld";
string strPath= @"D:\test.txt";
FileInfo fileStr = new FileInfo(strPath);
byte[] strWrite= new UTF8Encoding(true).GetBytes(str);
FileStream StrStream=fileStr.Create();
StrStream.Write(strWrite,0, strWrite.Length);
Console.WriteLine("写入成功!");
StrStream.Close();
}
(2)使用MemoryStream类管理内存数据
staticvoid Main(string[]args)
{
string str = "你好!"
byte[] MermoryWrite = newUTF8Encoding(true).GetBytes(str);
//在内存中申请适合的空间
MemoryStream ms = new MemoryStream(MermoryWrite.Length);
//写入内存缓冲区
ms.Write(MermoryWrite, 0,MermoryWrite.Length);
//打印出当前流的位置
Console.WriteLine(ms.Position);
//清空缓冲区
ms.Flush();
//seek属于定位指针函数,第一个参数它是相对于第二个参数的位置,也相当于偏移量。第二个参数是它用作查找参考点。
//返回值:流内的新位置,通过将初始参考点和偏移量合并计算而得。
ms.Seek(0, SeekOrigin.Begin);
byte[] temp = new byte[MermoryWrite.Length];
// 从当前流中读取字节块并将数据写入 buffer 中。返回写入缓冲区中的总字节数。
ms.Read(temp, 0, (int)ms.Length);
Console.WriteLine(new UTF8Encoding(true).GetChars(temp));
}
}
(2) 使用BufferedStream来提高流的性能
static void Main(string[] args)
{
string str = "你好!";
string strPath = @"D:\test.txt";
FileInfo fileStr = new FileInfo(strPath);
byte[] strWrite = new UTF8Encoding(true).GetBytes(str);
FileStream StrStream = fileStr.Create();
//实例化缓冲区
BufferedStream bufferStr = new BufferedStream(StrStream);
//向缓冲区中写入流
bufferStr.Write(strWrite, 0, strWrite.Length);
bufferStr.Close();
StrStream.Close();
Console.WriteLine("写入成功!");
}
3、管理应用程序数据
(1) 管理文本数据用StreamReader和StreamWriter,它们继承与抽象类TextReader类和TextWriter类,这点注意不要用错了。
如:读取D:\test.txt文件
static void Main(string[] args)
{
string strPath= @"D:\test.txt";
//写入文件
StreamWriter sw=new StreamWriter(File.Open(strPath,FileMode.Append));
sw.WriteLine(DateTime.Now.ToString());
//注意清空缓冲区和关闭流对象
sw.Flush();
sw.Close();
//从文件中读取数据
StreamReader sr=new StreamReader(File.Open(strPath,FileMode.Open));
Console.WriteLine(sr.ReadToEnd());
}
(2) 管理字符串数据用StringReader类和StringWriter类,注意用到StringBuilder
static void Main(string[]args)
{
//写入字符串
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
sw.WriteLine(DateTime.Now.ToString());
//注意清空缓冲区和关闭流对象
sw.Flush();
sw.Close();
//从文件中读取数据
StringReader sr = new StringReader(sb.ToString());
Console.WriteLine(sr.ReadToEnd());
}
(3) 管理二进制文件用BinaryReader类和BinaryWriter类,注意需要一个stream对象
static void Main(string[] args)
{
string strPath= @"D:\test.dat";
//写入二进制文件
BinaryWriter bw=new BinaryWriter(File.Open(strPath,FileMode.OpenOrCreate));
bw.Write(true);;
bw.Write('A');
//注意清空缓冲区和关闭流对象
bw.Flush();
bw.Close();
//从文件中读取数据
BinaryReaderbr = new BinaryReader(File.Open(strPath, FileMode.Open));
Console.WriteLine(br.ReadBoolean());
Console.WriteLine(br.ReadChar());
}
注:以上这些类都是继承于Stream类的
(4).NET Framework的字符编码类:在这里不再赘述,可以查msdn(http://msdn.microsoft.com/zh-cn/ms404377)
(5)扩展下,高效处理字符串
看一下如下代码:
string str="";
for(int i = 0; i < 1000; i++)
{
str += i.ToString();
}
字符串是引用类型,这样将会有999个空间是浪费的,所以为了提高效率引用StringBuilder,而不仅仅是合并。
以上代码可以改为:
StringBuilder str = newStringBuilder();
for(int i = 0; i < 1000; i++)
{
str.Append(i.ToString());
}
这样效率就会大大提高。