65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (26投票s)

2001年10月13日

3分钟阅读

viewsIcon

177302

downloadIcon

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 类来枚举特定文件夹中的子目录和文件。它有许多方法,其中两个叫做 GetFilesGetDirectories,前者返回一个 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]); 
}

二进制文件

我们可以使用 BinaryReaderBinaryWriter 类来读取和写入二进制文件。为了好玩,让我们创建一个简单的 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,它将返回下一个字节,但不会移动文件指针。

文本文件

读取和写入文本文件的方法不止一种,但在这里我将向您展示如何使用 StreamWriterStreamReader 类。它们让我想起了 MFC CStdioFile 类。StreamReader 类有一个 ReadLine 方法,而 StreamWrite 类有一个 WriteLine 方法,它们的行为与 CStdioFile::ReadStringCStdioFile::WriteString 方法完全相似。这两个类都有一个构造函数,它接受文件路径作为参数,因此我们不需要像使用 BinaryReaderBinaryWriter 类那样首先创建 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();
} 
© . All rights reserved.