文件、目录和流的基础知识






4.93/5 (26投票s)
2001年10月13日
3分钟阅读

177302

939
演示了 reader/writer 类以及 file/directory info 类的使用
引言
大多数常见的应用程序都需要读取和写入文件。.NET BCL 中有许多类提供了用于创建和操作文件和目录的各种方法。在本文中,我将介绍您可能需要执行的有关文件的基本操作。由于这里讨论的大多数类提供的功能过于广泛,无法完全覆盖,因此我只演示这些类的一些非常常见的用法。然后读者可以自己探索其余的功能。本文的第一个版本使用了 C# 示例,但在这个改进和扩展的版本中,我使用了托管 C++。本文包含各种技巧,而不是自上而下的教程。我欢迎读者提出更多技巧或技术,希望看到包含在文章中。
获取文件信息
为此,我们可以使用 System.IO.FileInfo
类,该类具有几个用于执行各种文件操作的实例方法。作为一个简短的例子,我们将检索有关 Windows 记事本的一些信息。我使用了一个本机 API 调用来检索 Windows 目录,因为我无法弄清楚使用 .NET 如何做到这一点。如果有人能告诉我如何使用 .NET 做到这一点,我将不胜感激。Show 是一个用户定义的函数,我用于填充输出。
void FileInfoDemo() { TCHAR WinPath[MAX_PATH+1]; GetWindowsDirectory(WinPath,MAX_PATH+1); String* NotepadPath = WinPath; NotepadPath = String::Concat(NotepadPath,S"\\notepad.exe"); FileInfo* finfo = new FileInfo(NotepadPath); Show("Name",finfo->Name); Show("Directory",finfo->Directory); Show("Extension",finfo->Extension); Show("Length",__box(finfo->Length)); Show("FullName",finfo->FullName); Show("CreationTime ",finfo->CreationTime.ToString()); }
基本上,我们所做的就是在构造函数中指定文件的路径。现在我们可以使用一些非常有用的属性来查询有关我们文件的信息。FileInfo
类具有返回各种流读取器和写入器的方法,但是有更好的方法来读取和写入文件,我将在本文稍后介绍。
枚举子目录和文件
我们使用 DirectoryInfo
类来枚举特定文件夹中的子目录和文件。它有许多方法,其中两个叫做 GetFiles
和 GetDirectories
,前者返回一个 FileInfo
数组,后者返回一个 DirectoryInfo
数组。
void DirectoryInfoDemo1() { DirectoryInfo* dinfo = new DirectoryInfo("C:\\"); DirectoryInfo* subdirs[] = dinfo->GetDirectories(); Console::WriteLine("Sub-Directories for C:\\"); Console::WriteLine("-----------------------"); for(int i=0; i<subdirs->Length; i++) Show((i+1).ToString(),subdirs->Item[i]); } void DirectoryInfoDemo2() { DirectoryInfo* dinfo = new DirectoryInfo("C:\\"); FileInfo* filesindir[] = dinfo->GetFiles(); Console::WriteLine("Files under C:\\"); Console::WriteLine("---------------"); for(int i=0; i<filesindir->Length; i++) Show((i+1).ToString(),filesindir->Item[i]); }
二进制文件
我们可以使用 BinaryReader
和 BinaryWriter
类来读取和写入二进制文件。为了好玩,让我们创建一个简单的 16 位 COM 格式可执行文件。我们可以使用如下所示的 4 行 16 位汇编程序来编写它。它只是简单地调用中断 21h 函数 02h,该函数输出 DL 中保存的字符。我还给出了这些汇编语句的机器代码等效项。因此,我们所做的就是创建一个包含这 8 个字节的数组,然后我们使用 BinaryWriter
类将其写入文件。现在我们可以实际运行此文件,它将在屏幕上打印一个 'A'。
MOV AH,02h ; B4 02
MOV DL,41h ; B2 41
INT 21h ; CD 21
INT 20h ; CD 20
void BinaryWriterDemo() { Console::WriteLine("Creating C:\\nish.com"); Console::WriteLine("This will output an 'A' to the console"); FileStream* fs = new FileStream("C:\\nish.com", FileMode::Create,FileAccess::Write); BinaryWriter* bw = new BinaryWriter(fs); unsigned char SomeBinaryData __gc[] = {0xb4,0x02,0xb2,0x41,0xcd,0x21,0xcd,0x20}; bw->Write(SomeBinaryData); bw->Flush(); bw->Close(); }
现在我将向您展示如何使用 BinaryReader
类读取我们上面创建的二进制文件,并显示文件中的字节。
void BinaryReaderDemo() { Console::WriteLine("Reading C:\\nish.com"); FileStream* fs = new FileStream("C:\\nish.com", FileMode::Open,FileAccess::Read); BinaryReader* br = new BinaryReader(fs); unsigned char c; while(br->PeekChar() != -1) { c = br->ReadByte(); Console::Write("{0:X2} ",__box(c)); } br->Close(); Console::WriteLine(); }
BinaryReader.ReadByte
方法的一个小问题是,它抛出一个 EndOfStreamException
,而不是使用一个特殊的返回值来指示它。为了避免处理异常并以旧的 C 样式方式进行操作(这可能是一件好事,也可能不是一件好事),我使用了 PeekChar
,它将返回下一个字节,但不会移动文件指针。
文本文件
读取和写入文本文件的方法不止一种,但在这里我将向您展示如何使用 StreamWriter
和 StreamReader
类。它们让我想起了 MFC CStdioFile
类。StreamReader
类有一个 ReadLine
方法,而 StreamWrite
类有一个 WriteLine
方法,它们的行为与 CStdioFile::ReadString
和 CStdioFile::WriteString
方法完全相似。这两个类都有一个构造函数,它接受文件路径作为参数,因此我们不需要像使用 BinaryReader
和 BinaryWriter
类那样首先创建 FileStream
对象。
void StreamWriterDemo() { Console::WriteLine("Creating C:\\TempFile.txt"); StreamWriter *sw = new StreamWriter ("C:\\TempFile.txt"); sw->WriteLine("This is the first line"); sw->WriteLine("This is the second line"); sw->WriteLine("This is the third/last line"); sw->Close(); } void StreamReaderDemo() { Console::WriteLine("Reading C:\\TempFile.txt"); Console::WriteLine("-----------------------"); StreamReader* sr = new StreamReader ("C:\\TempFile.txt"); String* s; while(s = sr->ReadLine()) Console::WriteLine(s); sr->Close(); }
从字符串读取
他们考虑了一切,不是吗?StringReader
是一个派生自 TextReader
的类,它允许我们直接从字符串中读取。还有一个相应的 StringWriter
类。我对它的用途不是很确定,但我想有人会找到它的一些用途。也许它对于解析简单的字符串可能很有用。
void StringReaderDemo(String* s) { Console::WriteLine("Reading the string [{0}]",s); StringReader* sr = new StringReader(s); int c; while((c = sr->Read()) != -1) Console::Write("{0} ",__box(Convert::ToChar(c))); Console::WriteLine(); sr->Close(); }