C#学习笔记——文件系统数据
来源:互联网 发布:苏州矩阵光电 编辑:程序博客网 时间:2024/04/30 20:53
一、前言
C#经常要对数据进行读写操作,而进行这些操作的基础是在流上进行的,即C#通过流来实现对数据的读取。C#中常用的流有两种:
1、输出流:当向某些外部目标写入数据时,就要用到输入流。
2、输入流:用于将数据读入程序可以访问的内存或变量中。
System.IO名称空间包含了用于在文件中读写数据的类,这里仅介绍用于文件输入输出的主要类,如下:
类 说明 File静态实用类,提供许多静态方法,用于移动、复制和删除文件。Directory静态实用类,提供许多静态方法,用于移动、复制和删除目录。Path实用类,用于处理路径名称。FileInfo表示磁盘上的物理文件,该类包含处理此文件的方法。要完成对文件的读写工作,就必须创建Stream对象。DirectoryInfo表示磁盘上的物理目录,该类包含处理此目录的方法。FileSystemInfo用作FileInfo和DirectoryInfo的基类,可以使用多态性同时处理文件和目录。FileStream表示可写或可读,或二者均可的文件。可以同步或异步地读写此文件。StreamReader从流中读取字符数据,可以使用FileStream作为基类创建。StreamWriter向流写入字符数据,可以使用FileStream作为基类创建。FileSystemWatcher FileSystemWatcher是本章要介绍的最复杂类。它用于监控文件和目录,提供了这些文件和目录发生变化时应用程序可以捕获的事件。
DeflateStream——表示在写入时自动压缩数据或读取时自动解压缩的流,使用Deflate算法来实现压缩。
GZipStream——表示在写入时自动压缩数据或者在读取时自动解压缩的流,使用GZIP算法来实现压缩。
二、FiIe类和Directory类
File和Directory实用类提供了许多的静态方法,用于处理文件和目录,这些方法可以移动文件、查询和更新特性,还可以创建FileStream对象。如下为File类最常用的静态类方法:
Directory类最常用的静态类方法:
FileInfo类:它不是静态类,没有静态方法,只有在实例化后才能使用,FileInfo对象表示磁盘或网络位置上的文件,提供文件路径就可以创建一个FileInfo对象:
FileInfo aFile = new FileInfo(@“C:\Log.txt”);注:@表示该字符串按照字面意思解释,而不解释为转义字符
FileInfo类提供了许多方法类似于File类,但由于File是静态方法,它需要一个字符串参数为每个方法调用指定的文件位置,下面代码完成相同工作:
FileInfo aFile = new FileInfo(“Data.txt”); if(File.Exists(“Data.txt”)) Console.WriteLine("File Exists");
if(aFile.Exists) Console,WriteLine("File Exists");
FileInfo和File的使用场景:
1、如果仅进行单一方法调用,则可以使用静态File类,因为不用实例化,所以调用要快些。
2、如果应用程序在文件上执行几种操作,则实例化FileInfo对象并使用其方法就更好一些。
下面介绍FileSystem的属性:
CreationTimeUtc获取当前文件的创建日期和时间,可以使用UTC和非UTC版本。Extension提取文件的扩展名。这个属性是只读的。Exists确定文件是否存在,这是一个只读的抽象属性,在FileInfo和DirectoryInfo中进行了重写。FullName检索文件的完整路径,这个属性是只读的LastAccessTime,
LastAccessTimeUtc获取或设置上次访问当前文件的日期和时间,可以使用UTC和非UTC版本LastWriteTime,
LastWriteTimeUtc获取或设置上次写入当前文件的日期和时间,可以使用UTC和非UTC版本Name检索文件的完整路径,这是一个只读抽象属性,在FileInfo和DirectoryInfo中进行了重写。下面是FileInfo的专用属性:
下面介绍DirectoryInfo:
Directory和DirectoryInfo的区别及用法跟File和FileInfo的区别及用法类似。以下是DirectoryInfo的专用属性:
路径名:也成绝对路径名。就是显示的指定文件或目录来自于哪一个已知的位置,通俗讲就是完整路径。
相对路径:以当前工作目录为起点,这是相对路径名的默认设置。例如应用程序运行在C:\Development\FileDemo目录上,并使用相对路径LogFile.txt,该文件就是:C:\Development\FileDemo\LogFile.txt。若想上移目录,要使用..字符串,那么路径..\Log.txt表示C:\Development\Log.txt文件。如果上移两个目录,则是..\..\。如果有必要可使用Directory.GetCurrentDirectory()找出工作目录的当前位置,也可以使用Directory.SetCurrentDirectory()设置新路径。
FileStream对象:
FileStream对象表示指向磁盘或网络路径上的文件流。这个类提供了在文件中读写字节的方法。但经常使用StreamReader或StreamWrite执行这些功能,这是因为FileStream类操作的是字节和字节数组,而Stream类操作的是字符数据。字符数据易于使用,但是有些操作,如随机文件访问(访问文件中间某点的数据),就必须由FileStream对象执行。创建FileStream对象最简单的构造函数仅有两个参数,即文件名和FileMode枚举值。如下:
FileStream aFile = new FileStream(filename,FileMode.<Member>); FileMode枚举包含几个成员,指定了如何打开或创建文件。如表1-7:
枚举FileAccess.Write结合使用创建一个新文件。只能与枚举
FileAccess.Write结合使用Create删除该文件,然后创建新文件创建新文件CreateNew抛出异常创建新文件Open打开文件,流指向文件开头处抛出异常OpenOrCreate打开文件,流指向文件开头处创建新文件Truncate打开文件,清除其内容,流指向文件
开头处,保留文件的初始创建日期抛出异常
另外一个常用的构造函数如下:
FileStream aFile = new FileStream(filename,FileMode.<Member>,FileAccess.<Member>);第三个参数是FileAcess枚举的一个成员,它指定了流的作用。如表1-8:
File和FileInfo类都提供了OpenRead()和OpenWrite()方法,更易于创建FileStream对象,前者打开了只读访问的文件,后者只允许写入文件。如下打开了用于只读访问的Data.tex文件:
FileStream aFile = File.OpenRead("Data.txt");
下面代码执行同样的功能:FileInfo aFileInfo = new aFileInfo("Data.txt"); FileStream aFile = aFileInfo.OpenRead();
1、文件位置
FileStream类维护内部文件指针,该指针指向文件中进行下一次读写操作的位置。大多情况下打开文件时,它就指向文件的开始位置,但可以通过Seek()方法修改位置。该方法有两个参数:第一个指定文件指针移动距离(以字节为单位)。第二个指定开始计算的起始位置,用SeekOrigin枚举的一个值表示。SeekOrigin枚举包含:Begin、Current和End。例如:aFile.Seek(8,SeekOrigin.Begin);将指针从文件开始位置移动8个字节。
2、读取数据
FileStream类只能处理原始字节(byte),这使得FileStream类可以用于任何数据文件,而不仅仅是文本文件,诸如图像声音等都可读取,但是FileStream对象不能直接将数据读入字符串,StreamReader类却可以。
FileStream.Read()方法是从FileStream对象所指向的文件中访问数据的主要手段,这个方法从文件中读取数据,再把数据写入一个字节数组,它有三个参数:第一个是传入的字节数组,用来接受FileStream对象中的数据;第二个是字节数组中开始写入数据的位置,它通常是0;第三个指定从文件中读取多少字节。
例子:
static void Main(string[] args) { byte[] byteData = new byte[200]; char[] charaData = new char[200]; FileStream aFile = new FileStream("../../Program.cs",FileMode.OpenOrCreate); aFile.Seek(144,SeekOrigin.Begin); aFile.Read(byteData,0,200); Decoder d = Encoding.UTF8.GetDecoder(); d.GetChars(byteData,0,byteData.Length,charaData,0); Console.WriteLine(charaData); Console.ReadLine(); }3、写入数据
写入过程与读取过程类似。如下例子:
static void Main(string[] args) { byte[] byteData; char[] charaData; FileStream aFile = new FileStream("Program.txt",FileMode.Create); charaData = "My pink half of the drainpipe.".ToCharArray(); byteData = new byte[charaData.Length]; Encoder d = Encoding.UTF8.GetEncoder(); d.GetBytes(charaData, 0, charaData.Length, byteData, 0,true); aFile.Seek(0,SeekOrigin.Begin); aFile.Write(byteData,0,byteData.Length); }StreamWriter对象:
操作字节数组比较麻烦,所以通常使用StreamReader或StreamWriter来处理文件,如果不需要改变文件指针位置,这些类就很容易操作文件。StreamWriter类允许将字符和字符串写入到文件中,它处理底层的转换,向FileStream对象写入数据。创建StreamWriter对象的方法很多,如果已经有了FileStream对象,则可以使用此对象来创建:
FileStream aFile = new FileStream("Log.txt",FileMode.CreateNew);
StreamWriter sw = new StreamWriter(aFile);
也可以直接从文件中创建StreamWriter对象:
StreamWriter sw = new StreamWriter("Log.txt",true);这个构造函数的参数是文件名和一个Boolean值,这个Boolean值指定是追加文件,还是创建新文件:
a、如果是false,则创建一个新文件或者截取现有文件并打开它
b、如果是true,则打开文件,保留原来的数据,如果找不到,则创建一个新文件
StreamWriter对象不会提供像FileStream中FileMode、FileAccess类似的选项,只有使用Boolean来追加文件或创建新文件,因此总是对文件拥有读写权。若想使用高级参数,必须首先在FileStream构造函数中指定,然后在FileStream对象中创建StreamWriter。示例如下:
static void Main(string[] args) { FileStream aFile = new FileStream("Log.txt",FileMode.OpenOrCreate); StreamWriter sw = new StreamWriter(aFile); bool truth = true; sw.WriteLine("Hell to you"); sw.WriteLine("It is now {0} and things are looking good.",DateTime.Now.ToLongDateString()); sw.Write("More than that"); sw.Write("it's {0} that C# is fun.",truth); sw.Close(); }注意:WriteLine()自动换行,Write()则每次会在上次的结尾处写入。
StreamReader对象:
用于读取数据,它的创建方式跟StreamWriter类似,最简单的创建方式如下:
FileStream aFile = new FileStream(“Log.txt”,FileMode.Open);StreamReader sr = new StreamReader(aFile);
也可用具体文件路径创建:StreamReader sr = new StreamReader(“Log.txt”);具体示例如下:
static void Main(string[] args) { string line; FileStream aFile = new FileStream("Log.txt",FileMode.OpenOrCreate); StreamReader sr = new StreamReader(aFile); line = sr.ReadLine(); while(line != null) { Console.WriteLine(line); line = sr.ReadLine(); } sr.Close(); Console.ReadKey(); }1、读取数据
ReadLine()方法不是在文件中访问数据的唯一方法。StreamReader类还包含许多读取数据的方法,其中最简单的是Read(),此方法将流的下一个字符作为正整数值返回,如果到达了流的结尾处,则返回-1,使用Convert类可以把这个值转换为字符,用该方法重新编写上面:
StreamReader sr = new StreamReader(aFile); int charCode; charCode = sr.Read(); while(charCode !=-1) { Console.WriteLine(Convert.ToChar(charCode)); charCode = sr.Read(); } sr.Close();对于小型文件,可使用一个非常简单的方法ReadToEnd(),此方法读取整个文件,并将其作为字符串返回。如:
StreamReader sr = new StreamReader(aFile); line = sr.ReadToEnd(); Console.WriteLine(line); sr.Close();处理大型文件的另一个方法是.NET4中新增的静态方法File.ReadLines(),它返回IEnumerable<string>集合。可迭代这个集合中的字符串,一次读取文件中的一行。使用如下
foreach(string alternativeLine in File.ReadLines("Log.txt")) { Console.WriteLine(alternativeLine); }2、用分隔符分隔的文件
用分隔符分割的数据格式,常用String类的Split()方法将字符串转换为一个数组。具体事例如下:
private static List<Dictionary<string, string>> GetData(out List<string> columns) { string line; string[] stringArray; char[] charArray = new char[] { ',' }; List<Dictionary<string, string>> data = new List<Dictionary<string, string>>(); columns = new List<string>(); FileStream aFile = new FileStream(@"..\..\SomeData.txt",FileMode.Open); StreamReader sr = new StreamReader(aFile); line = sr.ReadLine(); stringArray = line.Split(charArray); for(int x = 0;x<=stringArray.GetUpperBound(0);x++) { columns.Add(stringArray[x]); } line = sr.ReadLine(); while(line!=null) { stringArray = line.Split(charArray); Dictionary<string, string> dataRow = new Dictionary<string, string>(); for(int x = 0;x<=stringArray.GetUpperBound(0);x++) { dataRow.Add(columns[x],stringArray[x]); } data.Add(dataRow); line = sr.ReadLine(); } sr.Close(); return data; } static void Main(string[] args) { List<string> columns; List<Dictionary<string, string>> myData = GetData(out columns); foreach(string column in columns) { Console.Write("{0,-20}",column); } Console.WriteLine(); foreach(Dictionary<string,string> row in myData) { foreach(string column in columns) { Console.Write("{0,-20}", row[column]); } Console.WriteLine(); } Console.ReadKey(); }异步文件访问:
当一次性执行大量文件访问操作或者要处理非常大的文件,读写文件系统数据是很缓慢的,此时想在等待这些操作完成的同时去执行其他操作,这时就需要一步操作了,这种异步适用于FileStream、StreamWriter和StreamReader类,通常是带有Async后缀的,例如StreamReader类的ReaderLineAsync()方法。
读写压缩文件:
在处理文件时,使用压缩文件会节约大量的硬盘空间。System.IO.Compression名称空间就包含能在代码中压缩文件的类,这些类使用GZIP或者Deflate算法。但压缩文件并不只是把他们压缩一下就完事了,商业应用程序允许把多个文件放在一个压缩文件(通常称为存档文件)中。本节介绍的内容简单得多:只是把文本数据保存在压缩文件中。不能在外部实用程序中访问这个文件,但这个文件比未压缩版本要小得多。
System.IO.Compression名称空间中有两个压缩流类DeflateStream和GZipStream,它们的工作方式非常类似,对于这两个类,都要用已有的流初始化它们,对于文件,流就是FileStream对象。此后就可以把他们用于StreamReader和StreamWriter了。此外只需指定流是用于压缩(保存文件)还是解压缩(加载文件),类就知道要对传送给它的数据执行什么操作。示例如下:
static void SaveCompressedFile(string filename,string data) { FileStream fileStream = new FileStream(filename,FileMode.Create,FileAccess.Write); GZipStream compressionStream = new GZipStream(fileStream,CompressionMode.Compress); StreamWriter writer = new StreamWriter(compressionStream); writer.Write(data); writer.Close(); } static string LoadCompressedFile(string filename) { FileStream fileStream = new FileStream(filename,FileMode.Open,FileAccess.Read); GZipStream compressionStream = new GZipStream(fileStream,CompressionMode.Decompress); StreamReader reader = new StreamReader(compressionStream); string data = reader.ReadToEnd(); reader.Close(); return data; } static void Main(string[] args) { string filename = "compressedFile.txt"; string sourceString = Console.ReadLine(); StringBuilder sourceStringMultiplier = new StringBuilder(sourceString.Length*100); for(int i = 0; i<100; i++) { sourceStringMultiplier.Append(sourceString); } sourceString = sourceStringMultiplier.ToString(); Console.WriteLine("Source data is {0} bytes long.",sourceString.Length); SaveCompressedFile(filename, sourceString); Console.WriteLine("\nData saved to {0}.",filename); FileInfo compressedFileData = new FileInfo(filename); Console.WriteLine("Compressed file is {0} bytes long.",compressedFileData.Length); string recoveredString = LoadCompressedFile(filename); recoveredString = recoveredString.Substring(0,recoveredString.Length/100); Console.WriteLine("\nRecovered data: {0}",recoveredString); Console.ReadKey(); }序列化对象:
应用程序经常需要在硬盘上存储数据。前面介绍了逐段构建文本和数据文件,但这通常并非是最简单的方式。有时最好以对象的形式存储数据。
1、.NETFramework在System.Runtime.Serialization和System.Runtime.Serialization.Formatter名称空间中提供了序列化对象的基础架构,后者包含的名称空间中有一些具体的类实现了这个基础架构。在框架中,有一个重要的实现可用:System.Runtime.Serialization,Formatter.Binary。这个名称空间包含的BinaryFormatter类能够将对象序列化为二进制数据,也可以将二进制数据序列化为对象。
IFormatter serializer = new BinaryFormatter(); serializer.Serialize(myStream,myObject);
反序列化同样简单:
IFormatter serializer = new BinaryFormatter(); MyObjectType myNewObject = serializer.Deserialize(myStream) as MyObjectType;
下面将实际应用这些代码:
新添加一个Product类:
public class Product { public long Id; public string Name; public double Price; [NonSerialized] string Notes; public Product(long id, string name, double price, string notes) { Id = id; Name = name; Price = price; Notes = notes; } public override string ToString() { return string.Format("{0}: {1} (${2:F2}) {3}", Id, Name, Price, Notes); } }然后在Progress类的Main方法中添加:
static void Main(string[] args) { List<Product> products = new List<Product>(); products.Add(new Product(1,"Spily Pung",1000.0,"Goods stuff.")); products.Add(new Product(2, "Gloop Galloop Soup", 25.0, "Tasty.")); products.Add(new Product(4, "Hat Sauce", 12.0, "One for the kids.")); Console.WriteLine("Products to save:"); foreach(Product product in products) { Console.WriteLine(product); } Console.WriteLine(); IFormatter serializer = new BinaryFormatter(); FileStream saveFile = new FileStream("Products.bin", FileMode.Create, FileAccess.Write); serializer.Serialize(saveFile,products); saveFile.Close(); FileStream loadFile = new FileStream("Products.bin",FileMode.Open,FileAccess.Read); List<Product> saveProducts = serializer.Deserialize(loadFile) as List<Product>; loadFile.Close(); Console.WriteLine("Products loaded:"); foreach(Product product in saveProducts) { Console.WriteLine(product); } }本示例创建一个Product对象集合,把集合保存到磁盘上,然后重新加载它。但第一次运行抛出异常,因为Product对象没有标记为“可序列化”。.NET Framework要求把对象标记为可序列化,才能序列化它们。这有许多原因,包括:
1、一些对象序列化的效果不佳。例如,他们需要引用只有他们本身位于内存中时才存在的本地数据。
2、一些对象包含敏感的数据,这些数据不应该以不安全的方式保存或传输到另一个进程中。
Serializable这个特性并没有由派生类继承,他必须应用于要进行序列化的每个类。NoSerialized这个属性任何成员都可使用,使用之后将不被序列化。
监控文件系统:
.NET Freamwork使用FileSystemWatcher来对文件进行监控,其过程非常简单:首先必须设置一些属性,指定监控的位置、内容以及引发应用程序要处理的事件的时间。然后给FileSystemWatcher提供定制事件处理程序的地址,当发生重要事件时,FileSystemWatcher就可以调用这些事件处理程序,最后打开FileSystemWatcher,等待事件。在启用FileSystemWatcher之前必须设置的属性如下:
这些表示要监控的文件或文件夹的属性。如果指定的属性发生了变化,就引发事件。可能的枚
举值是Attributes、CreationTime、DirectoryName、FileName、LastAccess、LastWrite、
Security和Size。注意,可通过二元OR运算符来合并这些枚举值Filter指定要监控哪些文件的过滤器。例如,*.txt 设置之后,就必须为4个事件Changed、Created、Deleted和Renamed编写事件处理程序。在设置了属性和事件之后,将EnableRaisingEvents属性设置为true,就可以开始监控工作。如下示例:
实例化FileSystemWatcher对象并添加监听
FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Deleted += (s, e) => AddMessage("File: {0} Deleted",e.FullPath); watcher.Renamed += (s, e) => AddMessage("File renamed from {0} to {1}",e.OldName,e.FullPath); watcher.Changed += (s, e) => AddMessage("File: {0} {1}",e.FullPath,e.ChangeType.ToString()); watcher.Created += (s, e) => AddMessage("File: {0} Created",e.FullPath);设置监听位置及其他监听条件:
watcher.Path = System.IO.Path.GetDirectoryName("Progress.txt"); watcher.Filter = System.IO.Path.GetFileName("Progress.txt"); watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size; watcher.EnableRaisingEvents = true;System.IO.Path用来处理和提取文件位置字符串中的信息,这里首先使用它通过GetDirectoryName()方法提取用户在文本框中输入的目录名称,NotifyFilter是过滤器。
- C#学习笔记——文件系统数据
- 《C#入门经典》学习笔记(文件系统数据)
- 《C#入门经典》学习笔记(文件系统数据)
- 黑马程序员 C#学习笔记⑦ 文件系统数据一FileStream
- [文件系统]EXT文件系统学习笔记(一)——概念
- [文件系统]EXT文件系统学习笔记(二)——数据结构
- Win32学习笔记——文件系统
- C#学习笔记——LINQ数据访问
- [文件系统]EXT文件系统学习笔记(三)——日志文件系统
- FAT32文件系统学习(3) —— 数据区(DATA区)
- 大数据学习3——分布式文件系统HDFS
- Linux内核学习笔记十——虚拟文件系统概念
- 学习笔记(4)——磁盘与文件系统
- Linux内核学习笔记十——虚拟文件系统概念
- Linux内核学习笔记十——虚拟文件系统概念
- hadoop学习笔记二——hadoop文件系统
- Hadoop学习笔记(一)——文件系统HDFS
- FATFS文件系统+源码分析——学习笔记
- 第五章 CSS美化网页元素
- Java Annotation
- CSS:A标记样式
- 牛客网专项练习笔记
- Sbt assembly使用
- C#学习笔记——文件系统数据
- java中的类修饰符、成员变量修饰符、方法修饰符。
- BlockingQueue、PriorityBlockingQueue
- 计算1/1-1/2+1/3-1/4=1/5.......+1/99-1/100的值
- android高仿微信布局(二)
- 超链接的样式设置(html+css+jsp)
- UCI数据库
- JAVA 的wait(), notify()与synchronized同步机制
- 搭建 spring + spring mvc +mybatis web项目