CodeGym /课程 /C# SELF /实例类 FileInfo

实例类 FileInfoDirectoryInfo

C# SELF
第 39 级 , 课程 1
可用

1. 介绍

如果把静态类,比如 FileDirectory 当作一把通用的瑞士军刀:随手可用、能快速解决问题,但不绑定到具体对象上;那么 FileInfoDirectoryInfo 就像专用工具:为某个文件或文件夹创建,"知道"很多关于它们的信息,并且在对同一个对象做多次操作时用起来更方便、更灵活。

实例类 保存关于某个具体文件系统对象的细节,而且在首次加载属性后不必每次都去文件系统读取信息(除非该对象已经过期)。

  • FileInfo — 用于操作具体的文件。
  • DirectoryInfo — 用于操作具体的目录(文件夹)。

它们包含属性和方法,可以获取详细信息(大小、创建时间、扩展名、可用属性)并对文件/文件夹执行各种操作:复制、删除、移动等。

FileInfoDirectoryInfo 的结构

两个类都继承自一个共同的抽象类 FileSystemInfo,这样可以写出同时处理文件和文件夹的通用代码。


System.Object
   |
System.MarshalByRefObject
   |
System.IO.FileSystemInfo (抽象类)
   |             |
  FileInfo    DirectoryInfo

什么时候使用实例类?

  • 当你需要关于某个文件/文件夹的大量信息(大小、修改日期、扩展名、属性等),并且这些数据会被多次使用时。
  • 当你想枚举目录中的所有文件/文件夹,并把每个对象当作“活的”实例来处理时。
  • 为了优化,避免不必要地访问文件系统(信息缓存很有用)。
  • 为了写更面向对象的代码(备份、媒体库、文件管理器等)。

如何创建 FileInfoDirectoryInfo 实例

using System.IO;

// 为一个存在的(或不存在的!)文件创建 FileInfo 对象:
var fileInfo = new FileInfo("notes.txt");

// 为一个文件夹创建 DirectoryInfo 对象:
var dirInfo = new DirectoryInfo(@"C:\Projects");

// 可以使用相对路径或绝对路径!

重要提示:创建 FileInfoDirectoryInfo 对象并不会在文件系统中创建文件/文件夹!它只是一个描述(引用关系)。

2. 使用 FileInfo

我们来看看这个类的主要属性和方法,下面是备忘:

属性/方法 返回什么? 使用示例
Name
文件名
fileInfo.Name
FullName
完整路径
fileInfo.FullName
Length
文件大小(字节)
fileInfo.Length
Directory
父目录(DirectoryInfo
fileInfo.Directory.FullName
Exists
文件是否真实存在?
fileInfo.Exists
Extension
文件扩展名(.txt)
fileInfo.Extension
CreationTime
创建日期
fileInfo.CreationTime
LastWriteTime
最后修改日期
fileInfo.LastWriteTime
IsReadOnly
是否只读?
fileInfo.IsReadOnly
方法
CopyTo()
复制文件
fileInfo.CopyTo("copy.txt")
Delete()
删除文件
fileInfo.Delete()
MoveTo()
移动文件
fileInfo.MoveTo("move.txt")
OpenRead()
打开读取流
using var stream = fileInfo.OpenRead()
OpenWrite()
打开写入流
using var stream = fileInfo.OpenWrite()

示例:文件信息

加一个小模块,用 FileInfo 获取文件的详细信息。

Console.WriteLine("请输入文件名:");
string fileName = Console.ReadLine();

var file = new FileInfo(fileName);
if (file.Exists)
{
    Console.WriteLine($"文件名: {file.Name}");
    Console.WriteLine($"路径: {file.FullName}");
    Console.WriteLine($"大小: {file.Length} 字节");
    Console.WriteLine($"扩展名: {file.Extension}");
    Console.WriteLine($"创建时间: {file.CreationTime}");
    Console.WriteLine($"最后修改: {file.LastWriteTime}");

    // 另外:显示父目录
    Console.WriteLine($"父文件夹: {file.DirectoryName}");
}
else
{
    Console.WriteLine("未找到文件。");
}

注意:我们并没有读取文件内容,只是获取元信息。

练习:复制和删除文件

// ... 在主方法中,在成功输出文件信息之后:
Console.WriteLine("输入复制文件的路径:");
string copyPath = Console.ReadLine();

try
{
    file.CopyTo(copyPath);
    Console.WriteLine($"文件已成功复制到 {copyPath}");
}
catch (IOException ex)
{
    Console.WriteLine($"无法复制文件: {ex.Message}");
}

// 现在删除副本
Console.WriteLine("删除副本吗? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
    var copyFile = new FileInfo(copyPath);
    if (copyFile.Exists)
    {
        copyFile.Delete();
        Console.WriteLine("副本已删除。");
    }
}

3. 使用 DirectoryInfo

看看 DirectoryInfo 能带来什么便利:

属性/方法 返回什么? 使用示例
Name
文件夹名
dirInfo.Name
FullName
完整路径
dirInfo.FullName
Parent
父文件夹(DirectoryInfo
dirInfo.Parent.FullName
Exists
文件夹是否存在?
dirInfo.Exists
CreationTime
创建日期
dirInfo.CreationTime
LastWriteTime
修改日期
dirInfo.LastWriteTime
方法
Create()
创建文件夹
dirInfo.Create()
Delete()
删除文件夹
dirInfo.Delete()
GetFiles()
文件数组(FileInfo 数组)
dirInfo.GetFiles()
GetDirectories()
子文件夹数组(DirectoryInfo 数组)
dirInfo.GetDirectories()
EnumerateFiles()
枚举文件(返回 IEnumerable<FileInfo>,延迟模式)
dirInfo.EnumerateFiles()
MoveTo()
移动文件夹
dirInfo.MoveTo("path")

示例:遍历文件和文件夹

Console.WriteLine("请输入文件夹路径:");
string path = Console.ReadLine();

var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
    Console.WriteLine("未找到文件夹!");
    return;
}

Console.WriteLine("\n--- 文件 ---");
foreach (var file in dir.GetFiles())
{
    Console.WriteLine($"{file.Name} ({file.Length} 字节)");
}

Console.WriteLine("\n--- 子文件夹 ---");
foreach (var subDir in dir.GetDirectories())
{
    Console.WriteLine(subDir.Name);
}

4. 有用的细节

静态方法 vs 实例类

什么时候用哪个?如果你只是做一次性的快速操作——例如 File.Exists(path)File.ReadAllText(path),静态方法更合适。它们更简单,开销更小,速度略快。

但如果你想获取大量关于文件或文件夹的信息、对同一对象做重复操作,或者想用面向对象的风格写代码,最好用实例 FileInfoDirectoryInfo

有趣的是,两种方式在底层都调用了相似的系统调用。但实例类会缓存某些属性(大小、日期、属性),从而减少对文件系统的访问——在遍历大量文件时特别有用。

关于日期和时间的小提示

属性 CreationTimeLastWriteTimeLastAccessTime 返回的是 DateTime 类型。

Console.WriteLine($"文件创建: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"最后修改: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");

如果在你创建 FileInfoDirectoryInfo 实例之后,文件或文件夹在磁盘上被修改了,缓存的信息就可能过时。要刷新它,调用 file.Refresh()

建议和实战注意事项

  • 实例类适合用来构造文件系统的包装:备份、媒体库、索引器等场景。
  • 与 LINQ 配合得很好:可以按大小、日期或扩展名过滤,然后对选中的对象执行操作。
  • 在批量操作时优先考虑 EnumerateFiles()EnumerateDirectories(),而不是 GetFiles()/GetDirectories()——延迟枚举节省内存并能更快开始处理。

静态方法和实例方法的比较

静态方法 实例类
语法
File.Delete(path)
new FileInfo(path).Delete()
缓存 没有
大量信息 需要调用很多方法 对象里就有
OO 风格 没有
批量操作 不方便 方便
流的操作

刷新信息和对象

对象 FileInfo/DirectoryInfo 在第一次访问属性时会缓存值。如果在实例创建后文件(或文件夹)在磁盘上被修改,想要更新信息,就调用 .Refresh() 方法。

var file = new FileInfo("notes.txt");
long oldSize = file.Length;

// 这期间别人(或你自己)在程序外修改了文件

file.Refresh();
long newSize = file.Length;

这种情况不常见,但如果你的程序在监视文件系统,刷新机制很重要。

5. 使用实例类时常见的错误

误解:创建对象 new FileInfo("file.txt") 就意味着文件已经存在。实际上不是——文件只有在显式写入或调用 Create() 后才会出现在磁盘上。

尝试访问不存在文件的属性:有些属性会返回默认值(例如大小为 0),但尝试打开读取流会抛出异常。

文件夹也一样:创建 DirectoryInfo 并不保证磁盘上存在该文件夹,除非调用 Create() 或它实际被创建。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION