XIKEW.COM - 实用教程 - C# 8.0&.NET Core 3.0 处理文件 - 实用教程,C# 8.0, .NET Core 3.0,Modern Cross-Platform Development, Chapter 09, Working with Files, Streams, and Serialization - 关于《C# 8.0 And .NET Core 3.0 Modern Cross-Platform Development》第九章文件处理部分的翻译记录

C# 8.0&.NET Core 3.0 处理文件
NETCORE 5/24/2020 11:34:45 AM 阅读:25

关于《C# 8.0 And .NET Core 3.0 Modern Cross-Platform Development》第九章文件处理部分的翻译记录

关键字:C# 8.0, .NET Core 3.0,Modern Cross-Platform Development, Chapter 09, Working with Files, Streams, and Serialization

管理文件系统

您的应用程序经常需要在不同环境中对文件和目录执行输入和输出。 System和System.IO命名空间包含用于此目的的类。

处理跨平台环境和文件系统

让我们探索如何处理跨平台环境,例如Windows与Linux或macOS之间的差异。

  1. 在名为Chapter09的文件夹中创建一个名为WorkingWithFileSystems的新控制台应用程序。
  2. 将工作空间另存为Chapter09并向其中添加WorkingWithFileSystems。
  3. 导入System.IO名称空间,并静态导入System.Console,System.IO.Directory,System.Environment和System.IO.Path类型,如以下代码所示:
using System.IO; // types for managing the filesystem
using static System.Console;
using static System.IO.Directory;
using static System.IO.Path;
using static System.Environment;

Windows,macOS和Linux的路径不同,因此,我们将从探索.NET Core如何处理此问题开始。

  1. 创建一个静态OutputFileSystemInfo方法,并编写语句以执行以下操作:
  • 输出路径和目录分隔符
  • 输出当前目录的路径
  • 输出系统文件,临时文件和文档的一些特殊路径
static void OutputFileSystemInfo()
{
    WriteLine("{0,-33} {1}", "Path.PathSeparator", PathSeparator);
    WriteLine("{0,-33} {1}", "Path.DirectorySeparatorChar", DirectorySeparatorChar);
    WriteLine("{0,-33} {1}", "Directory.GetCurrentDirectory()", GetCurrentDirectory());    
    WriteLine("{0,-33} {1}", "Environment.CurrentDirectory", CurrentDirectory);    
    WriteLine("{0,-33} {1}", "Environment.SystemDirectory", SystemDirectory);    
    WriteLine("{0,-33} {1}", "Path.GetTempPath()", GetTempPath());    
    WriteLine("GetFolderPath(SpecialFolder");    
    WriteLine("{0,-33} {1}", " .System)", GetFolderPath(SpecialFolder.System));
    WriteLine("{0,-33} {1}", " .ApplicationData)",
    GetFolderPath(SpecialFolder.ApplicationData));
    WriteLine("{0,-33} {1}", " .MyDocuments)", GetFolderPath(SpecialFolder.MyDocuments));
    WriteLine("{0,-33} {1}", " .Personal)", GetFolderPath(SpecialFolder.Personal));
}

环境类型还有许多其他有用的成员,包括GetEnvironmentVariables方法以及OSVersion和ProcessorCount属性。

  1. 在Main方法中,调用OutputFileSystemInfo,如以下代码所示:
static void Main(string[] args)
{
    OutputFileSystemInfo();
}
  1. 在Windows上运行时,运行控制台应用程序并查看结果,如以下屏幕截图所示:

img

Windows使用反斜杠作为目录分隔符。 macOS和Linux使用正斜杠表示目录分隔符。

管理驱动器

要管理驱动器,请使用DriveInfo,该驱动器具有静态方法,该方法返回有关连接到计算机的所有驱动器的信息。 每个驱动器都有一个驱动器类型。

  1. 创建WorkWithDrives方法,并编写语句以获取所有驱动器并输出其名称,类型,大小,可用空间和格式,但前提是驱动器已就绪,如以下代码所示:
static void WorkWithDrives()
{
    WriteLine("{0,-30} | {1,-10} | {2,-7} | {3,18} | {4,18}",
    "NAME", "TYPE", "FORMAT", "SIZE (BYTES)", "FREE SPACE");

    foreach (DriveInfo drive in DriveInfo.GetDrives())
    {
        if (drive.IsReady)
        {
            WriteLine(
            "{0,-30} | {1,-10} | {2,-7} | {3,18:N0} | {4,18:N0}",
            drive.Name, drive.DriveType, drive.DriveFormat,
            drive.TotalSize, drive.AvailableFreeSpace);
        }
        else
        {
            WriteLine("{0,-30} | {1,-10}", drive.Name, drive.DriveType);
        }
    }
}

优化提示:在读取诸如TotalSize之类的属性之前,请检查驱动器是否已准备就绪,否则您将看到可移动驱动器引发异常。

  1. 在Main中,注释掉先前的方法调用,并添加对WorkWithDrives的调用,如以下代码所示:
static void Main(string[] args)
{
    //OutputFileSystemInfo();
    WorkWithDrives();
}
  1. 运行控制台应用程序并查看结果,如以下屏幕截图所示:

img

管理目录

要管理目录请使用Directory,Path和Environment静态类。 这些类型包括用于处理文件系统的许多属性和方法,如下图所示: img

在构造自定义路径时,必须小心地编写代码,这样它就不会对平台做出任何假设,例如,目录分隔符应该使用什么。

  1. 创建一个workwithcategories方法,并编写执行以下操作的语句:
    • 通过为目录名称创建字符串数组,然后将它们与Path类型的静态Combine方法正确组合,在用户的主目录下定义自定义路径。
    • 使用Directory类的静态Exists方法检查自定义目录路径的存在。
    • 使用Directory类的静态CreateDirectory和Delete方法创建并删除目录,包括其中的文件和子目录。
static void WorkWithDirectories()
{
    // define a directory path for a new folder
    // starting in the user's folder
    var newFolder = Combine(GetFolderPath(SpecialFolder.Personal), "Code", "Chapter09", "NewFolder");
    WriteLine($"Working with: {newFolder}");

    // check if it exists
    WriteLine($"Does it exist? {Exists(newFolder)}");

    // create directory
    WriteLine("Creating it...");
    CreateDirectory(newFolder);
    WriteLine($"Does it exist? {Exists(newFolder)}");
    Write("Confirm the directory exists, and then press ENTER: ");
    ReadLine();

    // delete directory
    WriteLine("Deleting it...");
    Delete(newFolder, recursive: true);
    WriteLine($"Does it exist? {Exists(newFolder)}");
}
  1. 在Main方法中,注释掉先前的方法调用,并添加对WorkWithDirectories的调用,如以下代码所示:
static void Main(string[] args)
{
    //OutputFileSystemInfo();
    //WorkWithDrives();
    WorkWithDirectories();
}
  1. 运行控制台应用程序并查看结果,并使用您喜欢的文件管理工具确认目录已创建,然后按Enter删除它,如以下输出所示:
Working with: /Users/markjprice/Code/Chapter09/NewFolder
Does it exist? False
Creating it...
Does it exist? True
Confirm the directory exists, and then press ENTER:
Deleting it...
Does it exist? False

管理文件

处理文件时,可以像导入目录类型一样静态导入文件类型,但是在下一个示例中,我们不会这样做,因为它具有与目录类型相同的方法并且它们会冲突。 The File type has a short enough name not to matter in this case.

  1. 创建一个WorkWithFiles方法,并编写执行以下操作的语句:
    • 检查文件是否存在
    • 创建一个文本文件
    • 在文件中写一行文本
    • 关闭文件以释放系统资源和文件锁(通常在try-finally语句块内执行此操作,以确保即使在写入文件时发生异常,也可以关闭文件)
    • 将复制一份作为备份
    • 删除原始文件
    • 读取备份文件的内容,然后关闭它
static void WorkWithFiles()
{
    // define a directory path to output files
    // starting in the user's folder
    var dir = Combine(GetFolderPath(SpecialFolder.Personal), "Code", "Chapter09", "OutputFiles");
    CreateDirectory(dir);

    // define file paths
    string textFile = Combine(dir, "Dummy.txt");
    string backupFile = Combine(dir, "Dummy.bak");
    WriteLine($"Working with: {textFile}");

    // check if a file exists
    WriteLine($"Does it exist? {File.Exists(textFile)}");

    // create a new text file and write a line to it
    StreamWriter textWriter = File.CreateText(textFile);
    textWriter.WriteLine("Hello, C#!");
    textWriter.Close(); // close file and release resources
    WriteLine($"Does it exist? {File.Exists(textFile)}");

    // copy the file, and overwrite if it already exists
    File.Copy(sourceFileName: textFile,
    destFileName: backupFile, overwrite: true);
    WriteLine($"Does {backupFile} exist? {File.Exists(backupFile)}");
    Write("Confirm the files exist, and then press ENTER: ");
    ReadLine();

    // delete file
    File.Delete(textFile);
    WriteLine($"Does it exist? {File.Exists(textFile)}");

    // read from the text file backup
    WriteLine($"Reading contents of {backupFile}:");
    StreamReader textReader = File.OpenText(backupFile);
    WriteLine(textReader.ReadToEnd());
    textReader.Close();
}
  1. 在Main中,注释掉前面的方法调用,并向WorkWithFiles添加一个调用。
  2. 运行应用程序并查看结果,如下面的输出所示:
Working with: /Users/markjprice/Code/Chapter09/OutputFiles/Dummy.txt
Does it exist? False
Does it exist? True
Does /Users/markjprice/Code/Chapter09/OutputFiles/Dummy.bak exist? True
Confirm the files exist, and then press ENTER:
Does it exist? False
Reading contents of /Users/markjprice/Code/Chapter09/OutputFiles/Dummy.bak:
Hello, C#!

管理路径

有时候,你需要处理路径的一部分;例如,您可能只想提取文件夹名、文件名或扩展名。有时,您需要生成临时文件夹和文件名。您可以使用Path类的静态方法来实现这一点。

  1. 在WorkWithFiles方法的末尾添加以下语句
// Managing paths
WriteLine($"Folder Name: {GetDirectoryName(textFile)}");
WriteLine($"File Name: {GetFileName(textFile)}");
WriteLine("File Name without Extension: {0}", GetFileNameWithoutExtension(textFile));
WriteLine($"File Extension: {GetExtension(textFile)}");
WriteLine($"Random File Name: {GetRandomFileName()}");
WriteLine($"Temporary File Name: {GetTempFileName()}");
  1. 运行应用程序并查看结果,如下面的输出所示:
Folder Name: /Users/markjprice/Code/Chapter09/OutputFiles
File Name: Dummy.txt
File Name without Extension: Dummy
File Extension: .txt
Random File Name: u45w1zki.co3
Temporary File Name:
/var/folders/tz/xx0y_wld5sx0nv0fjtq4tnpc0000gn/T/tmpyqrepP.tmp

GetTempFileName会创建一个零字节的文件并返回其名称供您使用,实际上他只返回了一个预备的文件名而不会创建文件。

获取文件信息

要获取有关文件或目录的更多信息,例如文件或目录的大小或上次访问的时间,可以创建FileInfo或DirectoryInfo类的实例。

FileInfo和DirectoryInfo都继承自FileSystemInfo,所以它们都有LastAccessTime和Delete这样的成员,如下图所示: img

  1. 让我们编写一些使用FileInfo实例的代码,以便在一个文件上有效地执行多个操作。在WorkWithFiles方法的末尾添加语句,以创建备份文件的FileInfo实例,并将有关该文件的信息写入控制台,如下面的代码所示:
var info = new FileInfo(backupFile);
WriteLine($"{backupFile}:");
WriteLine($"Contains {info.Length} bytes");
WriteLine($"Last accessed {info.LastAccessTime}");
WriteLine($"Has readonly set to {info.IsReadOnly}");
  1. 运行应用程序并查看结果,如下面的输出所示:
/Users/markjprice/Code/Chapter09/OutputFiles/Dummy.bak:
Contains 11 bytes
Last accessed 26/11/2018 09:08:26
Has readonly set to False

字节数在您的操作系统上可能会有所不同,因为操作系统可以使用不同的行尾。

控制如何处理文件

使用文件时通常需要控制文件的打开方式。 File.Open方法具有重载功能,可使用枚举值指定其他选项。 枚举类型如下:

  • FileMode:控制您要对文件执行的操作,例如CreateNew,OpenOrCreate或Truncate。
  • FileAccess:这控制您需要什么访问级别,例如ReadWrite。
  • FileShare:此控件可锁定文件,以允许其他进程指定访问级别,例如Read。

您可能想要打开一个文件并从中读取文件,并允许其他进程也读取它,如以下代码所示:

FileStream file = File.Open(pathToFile, FileMode.Open, FileAccess.Read, FileShare.Read);

还有一个文件属性的枚举,如下所示:

  • FileAttributes:这是检查FileSystemInfo派生的types Attributes属性的值,例如Archive和Encrypted。

您可以检查文件或目录属性,如以下代码所示:

var info = new FileInfo(backupFile);
WriteLine("Is the backup file compressed? {0}", info.Attributes.HasFlag(FileAttributes.Compressed));