文件和流(Files and Streams)之 DirectoryInfo类和FileInfo
DirectoryInfo和FileInfo类是Directory类和File类功能的镜像。此外,它们把遍历文件和目录的关系变得更加简单。例如,你可以很方便地获得由DirectoryInfo对象代表的目录内的文件的FileInfo对象。
要注意的是Directory类和File类只是提供了方法,而DirectoryInfo和FileInfo同时提供了方法和属性。例如:File类有单独的GetAttributes()方法和SetAttribute()方法,而FileInfo类提供了可读写的Attribute属性。
关于DirectoryInfo类和FileInfo类的另外一个好处是它们共享一组属性和方法,因为它们都是继承自FileSystemInfo基类,此外,FileInfo和DirectoryInfo类各自有几个独有的成员(具体方法和属性参见msdn)。
创建DirectoryInfo对象和FileInfo对象时,要在构造函数中指定完整的路径。如下所示:
创建FileInfo和DirectoryInfo对象时,如果指定的路径格式不正确(例如,包含非法字符)会得到一个异常。不过,路径不必对应真实的物理文件或目录。如果你不确信,可以用Exists检查文件或目录是否确实存在。
如果目录或文件不存在,可以用Create()方法创建它们,下面是一个示例:
DirectoryInfo对象和FileInfo对象在你第一次查询某个属性时获取来自文件系统的信息,在后继的使用中它们不再检查新的信息。如果文件此时发生了变化,这会导致不一致性,如果你知道或者怀疑指定对象的文件系统信息被改变了,你可以调用Refresh方法获取最新的信息。
DirectoryInfo类没有提供任何获取目录大小的属性,不过,你可以累加某一特定目录中每个文件的FileInfo.Length基值来计算该目录的大小。
在执行这一步前,你需要确定是否包含该子目录的大小。下面的方法允许你是用这两种方式中的任意一种:
关于剩余空间的信息,需要借助于DriveInfo类。
使用Attributes
FileInfo和DirectoryInfo类的Attributes属性代表文件或目录的文件系统特性。因为每个文件和目录都可以有一组属性。Attributes属性包含一组FileAttributes枚举值(具体见msdn)。
要找出文件的所有属性,可以调用Attributes属性的ToString()方法,它返回一个逗号分割的特性列表字符串:
测试单个特性时,需要使用位计算,例如考虑下面这段错误的代码:
测试仅在当前文件只含有只读特性时才成功。这种情形很少见。如果需要正确检测文件是否错误,只需要下面代码:
这个测试成功了,因为它只过滤只读特性。
类似的逻辑允许你验证文件不具备某个特定的特性:
你还必须用位运算来设置特性。此时,要小心不经意间删除文件原先设置的特性:
某些特性不能通过编程来设置。例如Encrpted特性只有你在Windows中使用EFS(加密文件系统)时才会由操作系统设置
要注意的是Directory类和File类只是提供了方法,而DirectoryInfo和FileInfo同时提供了方法和属性。例如:File类有单独的GetAttributes()方法和SetAttribute()方法,而FileInfo类提供了可读写的Attribute属性。
关于DirectoryInfo类和FileInfo类的另外一个好处是它们共享一组属性和方法,因为它们都是继承自FileSystemInfo基类,此外,FileInfo和DirectoryInfo类各自有几个独有的成员(具体方法和属性参见msdn)。
创建DirectoryInfo对象和FileInfo对象时,要在构造函数中指定完整的路径。如下所示:
DirectoryInfo myDirectory = new DirectoryInfo(@"c:\Temp");
FileInfo myFile = new FileInfo(@"c:\Temp\readme.txt");
FileInfo myFile = new FileInfo(@"c:\Temp\readme.txt");
创建FileInfo和DirectoryInfo对象时,如果指定的路径格式不正确(例如,包含非法字符)会得到一个异常。不过,路径不必对应真实的物理文件或目录。如果你不确信,可以用Exists检查文件或目录是否确实存在。
如果目录或文件不存在,可以用Create()方法创建它们,下面是一个示例:
// Define the new directory and file.
DirectoryInfo myDirectory = new DirectoryInfo(@"c:\Temp\Test");
FileInfo myFile = new FileInfo(@"c:\Temp\Test\readme.txt");
// Now create them. Order here is important.
// You can't create a file in a directory that doesn't exist yet.
myDirectory.Create();
FileStream stream = myFile.Create();
stream.Close();
DirectoryInfo myDirectory = new DirectoryInfo(@"c:\Temp\Test");
FileInfo myFile = new FileInfo(@"c:\Temp\Test\readme.txt");
// Now create them. Order here is important.
// You can't create a file in a directory that doesn't exist yet.
myDirectory.Create();
FileStream stream = myFile.Create();
stream.Close();
DirectoryInfo对象和FileInfo对象在你第一次查询某个属性时获取来自文件系统的信息,在后继的使用中它们不再检查新的信息。如果文件此时发生了变化,这会导致不一致性,如果你知道或者怀疑指定对象的文件系统信息被改变了,你可以调用Refresh方法获取最新的信息。
DirectoryInfo类没有提供任何获取目录大小的属性,不过,你可以累加某一特定目录中每个文件的FileInfo.Length基值来计算该目录的大小。
在执行这一步前,你需要确定是否包含该子目录的大小。下面的方法允许你是用这两种方式中的任意一种:
private static long CalculateDirectorySize(DirectoryInfo directory,
bool includeSubdirectories)
{
long totalSize = 0;
// Add up each file.
FileInfo[] files = directory.GetFiles();
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
// Add up each subdirectory, if required.
if (includeSubdirectories)
{
DirectoryInfo[] dirs = directory.GetDirectories();
foreach (DirectoryInfo dir in dirs)
{
totalSize += CalculateDirectorySize(dir, true);
}
}
return totalSize;
}
bool includeSubdirectories)
{
long totalSize = 0;
// Add up each file.
FileInfo[] files = directory.GetFiles();
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
// Add up each subdirectory, if required.
if (includeSubdirectories)
{
DirectoryInfo[] dirs = directory.GetDirectories();
foreach (DirectoryInfo dir in dirs)
{
totalSize += CalculateDirectorySize(dir, true);
}
}
return totalSize;
}
关于剩余空间的信息,需要借助于DriveInfo类。
使用Attributes
FileInfo和DirectoryInfo类的Attributes属性代表文件或目录的文件系统特性。因为每个文件和目录都可以有一组属性。Attributes属性包含一组FileAttributes枚举值(具体见msdn)。
要找出文件的所有属性,可以调用Attributes属性的ToString()方法,它返回一个逗号分割的特性列表字符串:
// This displays a string in the format "ReadOnly, Archive, Encrypted"
lblInfo.Text = myFile.Attributes.ToString();
lblInfo.Text = myFile.Attributes.ToString();
测试单个特性时,需要使用位计算,例如考虑下面这段错误的代码:
if (myFile.Attributes == FileAttributes.ReadOnly)
{ }
{ }
测试仅在当前文件只含有只读特性时才成功。这种情形很少见。如果需要正确检测文件是否错误,只需要下面代码:
if ((myFile.Attributes & FileAttributes.ReadOnly) != 0)
{ }
{ }
这个测试成功了,因为它只过滤只读特性。
类似的逻辑允许你验证文件不具备某个特定的特性:
if ((myFile.Attributes & FileAttributes.ReadOnly) != 0)
{ }
{ }
你还必须用位运算来设置特性。此时,要小心不经意间删除文件原先设置的特性:
// This sets the read-only attribute (and keeps all others as is).
myFile.Attributes = myFile.Attributes | FileAttributes.ReadOnly;
// This removes the read-only attribute (and keeps all others as is).
myFile.Attributes = myFile.Attributes & ~FileAttributes.ReadOnly;
myFile.Attributes = myFile.Attributes | FileAttributes.ReadOnly;
// This removes the read-only attribute (and keeps all others as is).
myFile.Attributes = myFile.Attributes & ~FileAttributes.ReadOnly;
某些特性不能通过编程来设置。例如Encrpted特性只有你在Windows中使用EFS(加密文件系统)时才会由操作系统设置