路径,文件,目录,I/O常见操作汇总(二)

简介:
    摘要:
    文件操作是程序中非常基础和重要的内容,而路径、文件、目录以及I/O都是在进行文件操作时的常见主题,这里想把这些常见的问题作个总结,对于每个问题, 尽量提供一些解决方案,即使没有你想要的答案,也希望能提供给你一点有益的思路,如果你有好的建议,恳请能够留言,使这些内容更加完善。 
    主要内容:
    一、路径的相关操作, 如判断路径是否合法,路径类型,路径的特定部分,合并路径,系统文件夹路径等内容;
    二、相关通用文件对话框,这些对话框可以帮助我们操作文件系统中的文件和目录;
    三、文件、目录、驱动器的操作,如获取它们的基本信息,获取和设置文件和目录的属性,文件的版本信息,
        搜索文件和目录,文件判等,复制、移动、删除、重命名文件和目录;
    四、读写文件,包括临时文件,随机文件名等;
    五、对文件系统的监视;

     上一篇 介绍了第一、二部分,这一篇介绍一下最重要的第三部分。
    
     三、文件和目录相关操作
    文件和目录操作涉及的类主要是:FileInfo,DirectoryInfo,DriveInfo,可以认为它们的一个实例对应着一个文件、目录、驱动器。它们的用法类似,一般是将文件、目录或驱动器的路径作为参数传递给相应的构造函数创建一个实例,然后访问它们的属性和方法。
    注意下面几点:
    FileInfo 类和 DirectoryInfo 类都继承自抽象类 FileSystemInfo , FileSystemInfo 类定义了一些通用的属性,如 CreationTime 、 Exists 等。但 DriveInfo 类没有继承 FileSystemInfo 类,所以它也就没有上面提到的那些通用属性了。

    FileInfo 类和 DirectoryInfo 类的对象公开的属性值都是第一次查询时获取的值,如果在以此查询之后文件或目录发生了改动,就必须调用它们的 Refresh 方法来更新这些属性。但 DriveInfo 则无需这么做,它的属性每次都会读取文件系统最新的信息。

    在创建文件、目录或驱动器的实例时,如果使用了一个不存在的路径,并不会报错,这是你得到一个对象,该对象表示一个并不存在的实体,这意味着它的 Exists 属性(对于 DriveInfo 来说是 IsReady 属性)值为 false 。你仍然可以操作该实体,但如果尝试其它的大多数属性,就会引发相应的 FileNotFoundException 、 DirectoryNotFoundException 或 DriveNotFoundException 异常。

    另外,还可以使用 File / Directory 类,这两个类的成员都是静态方法, 所以如果只想执行一个操作 ,那么使用 File/Directory 中的静态方法的效率比使用相应的 FileInfo / DirectoryInfo中的 实例方法可能更高。所有的 File / Directory 方法都要求当前所操作的文件 / 目录的路径。 注意: File / Directory 类的静态方法对所有方法都执行安全检查。 如果打算多次重用某个对象 ,可考虑改用 FileInfo / DirectoryInfo 的相应实例方法,因为并不总是需要安全检查。  

    下面是一些常见的问题:
    问题1:如何获取指定文件的基本信息;
    解决方案:可以使用FileInfo类的相关属性:
    FileInfo.Exists:获取指定文件是否存在;
    FileInfo.Name,FileInfo.Extensioin:获取文件的名称和扩展名;
    FileInfo.FullName:获取文件的全限定名称(完整路径);
    FileInfo.Directory:获取文件所在目录,返回类型为DirectoryInfo;
    FileInfo.DirectoryName:获取文件所在目录的路径(完整路径);
    FileInfo.Length:获取文件的大小(字节数);
    FileInfo.IsReadOnly:获取文件是否只读;
    FileInfo.Attributes:获取或设置指定文件的属性,返回类型为FileAttributes枚举,可以是多个值的组合(见问题2);
    FileInfo.CreationTime、FileInfo.LastAccessTime、FileInfo.LastWriteTime:分别用于获取文件的创建时间、访问时间、修改时间;
    (更多内容还请参考MSDN)

    问题2:如何获取和设置文件的属性,比如只读、存档、隐藏等;
    解决方案:
    使用FileInfo.Attributes属性可以获取和设置文件的属性,该属性类型为FileAttributes枚举,该枚举的每个值表示一种属性,FileAttributes枚举具有属性(Attribute)FlagsAttribute,所以该枚举的值可以进行组合,也就是一个文件可以同时拥有多个属性。下面看看具体的做法:
    获取属性,比如判断一个文件是否是只读的:

     //  当文件具有其它属性时,这种做法会失败
     if  (file.Attributes  ==  FileAttributes.ReadOnly)
    {
        chkReadonly.Checked 
=   true ;
    }

    
//  这种写法就不会有问题了,它只检查只读属性
     if  ((file.Attributes  &  FileAttributes.ReadOnly)  ==  FileAttributes.ReadOnly)
    {
        chkReadonly.Checked 
=   true ;
    }

    设置属性,比如添加和移除一个文件的只读属性:

     if  (chkReadonly.Checked)
    {
        
//  添加只读属性
        file.Attributes  |=  FileAttributes.ReadOnly;
    }
    
else
    {
        
//  移除只读属性
        file.Attributes  &=   ~ FileAttributes.ReadOnly;
    }

    问题3:如何获取文件的版本信息(比如版本号,版权声明,公司名称等);
    解决方案:
    使用FileVersionInfo类,该类有大量的版本信息相关的属性。通过它的静态方法GetVersionInfo获得该类的一个实例,然后就可以访问指定文件的版本信息了,非常方便。如FileVersion表示文件版本号,LegalCopyright表示指定文件的版权声明,CompanyName表示指定文件的公司名称。(更多内容还请参考MSDN)

    问题4:如何判断两个文件的内容是否相同(精确匹配);
    解决方案:
    使用System.security.Cryptography.HashAlgorithm类为每个文件生成一个哈希码,然后比较两个哈希码是否一致。
    在比较文件内容的时候可以采用好几种方法。例如,检查文件的某一特定部分是否一致;如果愿意,你甚至可以逐字节读取文件,逐字节进行比较。这两种方法都是可以的,但在某些情况下,还是使用哈希码算法更为方便。
    该算法为一个文件生成一个小的(通常约为20字节)二进制”指纹”(binary fingerprint)。从统计学角度看,不同的文件不可能生成相同的哈希码。事实上,即使是一个很小的改动(比如,修改了源文件中的一个bit),也会有50%的几率来改变哈希码中的每一个bit。因此,哈希码常常用于数据安全方面。
    要生成一个哈希码,你必须首先创建一个HashAlgorithm对象,而这通常是调用HashAlgorithm.Create方法来完成的;然后调用HashAlgorithm.ComputeHash方法,它会返回一个存储哈希码的字节数组。代码如下:

     ///   <summary>
    
///  判断两个文件内容是否一致
    
///   </summary>
     public   static   bool  IsFilesEqual( string  fileName1,  string  fileName2)
    {
        
using  (HashAlgorithm hashAlg  =  HashAlgorithm.Create())
        {
            
using  (FileStream fs1  =   new  FileStream(fileName1, FileMode.Open), fs2  =   new  FileStream(fileName2, FileMode.Open))
            {
                
byte [] hashBytes1  =  hashAlg.ComputeHash(fs1);
                
byte [] hashBytes2  =  hashAlg.ComputeHash(fs2);

                
//  比较哈希码
                 return  (BitConverter.ToString(hashBytes1)  ==  BitConverter.ToString(hashBytes2));
            }
        }
    }

    问题5:如何获取指定目录的基本信息;
    解决方案:可以使用DirectoryInfo类的相关属性和方法:
    DirectoryInfo.Exists:获取指定目录是否存在;
    DirectoryInfo.Name:获取目录的名称;
    DirectoryInfo.FullName:获取目录的全限定名称(完整路径);
    DirectoryInfo.Attributes:获取或设置指定目录的属性,返回类型为FileAttributes枚举,可以是多个值的组合;   
    DirectoryInfo.CreationTime、FileInfo.LastAccessTime、FileInfo.LastWriteTime:分别用于获取目录的创建时间、访问时间、修改时间;
    DirectoryInfo.Parent:获取目录的上级目录,返回类型为DirectoryInfo;
    DirectoryInfo.Root:获取目录的根目录,返回类型为DirectoryInfo;

    问题6:如何获取指定目录包含的文件和子目录;
    解决方案:
    DirectoryInfo.GetFiles():获取目录中(不包含子目录)的文件,返回类型为FileInfo[],支持通配符查找;
    DirectoryInfo.GetDirectories():获取目录(不包含子目录)的子目录,
        返回类型为DirectoryInfo[],支持通配符查找;
    DirectoryInfo. GetFileSystemInfos():获取指定目录下(不包含子目录)的文件和子目录,
        返回类型为FileSystemInfo[],支持通配符查找;

    问题7:如何获得指定目录的大小;
    解决方案:
    检查目录内的所有文件,利用FileInfo.Length属性获取每个文件的大小,然后进行合计,然后使用递归算法处理所有的子目录的文件,参考下面代码:

     ///   <summary>
    
///  计算一个目录的大小
    
///   </summary>
    
///   <param name="di"> 指定目录 </param>
    
///   <param name="includeSubDir"> 是否 包含子目录 </param>
    
///   <returns></returns>
     private   long  CalculateDirSize(DirectoryInfo di,  bool  includeSubDir)
    {
        
long  totalSize  =   0 ;

        
//  检查所有(直接)包含的文件
        FileInfo[] files  =  di.GetFiles();
        
foreach  (FileInfo file  in  files)
        {
            totalSize 
+=  file.Length;
        }

        
//  检查所有子目录,如果includeSubDir参数为true
         if  (includeSubDir)
        {
            DirectoryInfo[] dirs 
=  di.GetDirectories();
            
foreach  (DirectoryInfo dir  in  dirs)
            {
                totalSize 
+=  CalculateDirSize(dir, includeSubDir);
            }
        }

        
return  totalSize;
    }

    问题8:如何使用通配符搜索指定目录内的所有文件;
    解决方案:
    使用DirectoryInfo.GetFiles方法的重载版本,它可以接受一个过滤表达式,返回FileInfo数组,另外它的参数还可以指定是否对子目录进行查找。如:

    dir.GetFiles(" * .txt", SearchOption.AllDirectories);

    问题9:如何复制、移动、重命名、删除文件和目录;
    解决方案:使用FileInfo和DirectoryInfo类。
    下面是FileInfo类的相关方法:
    FileInfo.CopyTo:将现有文件复制到新文件,其重载版本还允许覆盖已存在文件;
    FileInfo.MoveTo:将指定文件移到新位置,并提供指定新文件名的选项,所以可以用来重命名文件(而不改变位置);    FileInfo.Delete:永久删除文件,如果文件不存在,则不执行任何操作;
    FileInfo.Replace:使用当前FileInfo对象对应文件的内容替换目标文件,而且指定另一个文件名作为被替换文件的备份,微软考虑实在周到。

    下面是DirectoryInfo类的相关方法:
    DirectoryInfo.Create:创建指定目录,如果指定路径中有多级目录不存在,该方法会一一创建;
    DirectoryInfo.CreateSubdirectory:创建当前对象对应的目录的子目录;
    DirectoryInfo.MoveTo:将目录(及其包含的内容)移动至一个新的目录,也可用来重命名目录;
    DirectoryInfo.Delete:删除目录(如果它存在的话)。如果要删除一个包含子目录的目录,要使用它的重载版本,以指定递归删除。

    注意到了没有?DirectoryInfo类少了一个CopyTo方法,不过我们可以通过递归来实现这个功能:

     ///   <summary>
    
///  复制目录到目标目录
    
///   </summary>
    
///   <param name="source"> 源目录 </param>
    
///   <param name="destination"> 目标目录 </param>
     public   static   void  CopyDirectory(DirectoryInfo source, DirectoryInfo destination)
    {
        
//  如果两个目录相同,则无须复制
         if  (destination.FullName.Equals(source.FullName))
        {
            
return ;
        }

        
//  如果目标目录不存在,创建它
         if  ( ! destination.Exists)
        {
            destination.Create();
        }

        
//  复制所有文件
        FileInfo[] files  =  source.GetFiles();
        
foreach  (FileInfo file  in  files)
        {
            
//  将文件复制到目标目录
            file.CopyTo(Path.Combine(destination.FullName, file.Name),  true );
        }

        
//  处理子目录
        DirectoryInfo[] dirs  =  source.GetDirectories();
        
foreach  (DirectoryInfo dir  in  dirs)
        {
            
string  destinationDir  =  Path.Combine(destination.FullName, dir.Name);

            
//  递归处理子目录
            CopyDirectory(dir,  new  DirectoryInfo(destinationDir));
        }
    }

 

    问题10:如何获得计算机的所有逻辑驱动器;
    解决方案:使用DriveInfo类(需要.NET 2.0)
    DriveInfo.GetDrives():获得计算机的所有逻辑驱动器,返回类型为DriveInfo[];  

    问题11:如何获取指定驱动器的信息;
    解决方案:
    DriveInfo.Name:获取驱动器的名称(如C:\);
    DriveInfo.DriveType:获取驱动器的类型(如Fixed,CDRom,Removable,Network等);
    DriveInfo.DriveFormat:获取驱动器的格式(如NTFS,FAT32,CDFS,UDF等);
    DriveInfo.IsReady:获取驱动器是否已准备好,比如CD是否已放入CD驱动器,如果驱动器没有准备好,访问其信息会引发IOException类型异常;
    DriveInfo.AvailableFreeSpace:获取驱动器的可用空间;
    DriveInfo.TotalFreeSpace:获取驱动器总的可用空间,它与AvailableFreeSpace的不同在于AvailableFreeSpace会磁盘配额的设置;
    DriveInfo.TotalSize:获取驱动器总的空间;
    DriveInfo.RootDirectory:获得驱动器的根目录(DirectoryInfo类型);

    至此,我们已经了解了文件和目录相关的一些基本操作。但还不清楚如何去读写文件的内容,下一篇中会详细了解这方面的操作。  


                                                                                   Anders Cui

    参考:

  • Apress-Visual C# 2005 Recipes A Problem Solution Approach
  • 还有不可缺少的MSDN

本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2006/12/27/filedirectory.html,如需转载请自行联系原作者。
目录
相关文章
|
11天前
|
Linux 编译器
目录文件篇
目录文件篇
|
8月前
读取指定文件夹下面的所有文件(含子目录)
读取指定文件夹下面的所有文件(含子目录)
30 0
|
9月前
目录的操作
目录的操作
60 0
获取目录下的文件及文件夹等信息
获取目录下的文件及文件夹等信息
83 0
|
内存技术
若某文件系统的目录结构如下图所示,假设用户要访问文件 fault.swf ,且当前工作目录为 swshare ,则该文件的全文件名为( ),相对路径和绝对路径分别为( 请在此空作答
若某文件系统的目录结构如下图所示,假设用户要访问文件 fault.swf ,且当前工作目录为 swshare ,则该文件的全文件名为( ),相对路径和绝对路径分别为( 请在此空作答
251 0
若某文件系统的目录结构如下图所示,假设用户要访问文件 fault.swf ,且当前工作目录为 swshare ,则该文件的全文件名为( ),相对路径和绝对路径分别为( 请在此空作答
|
开发框架 .NET Windows
文件和文件夹的操作——获取当前路径方法
文件和文件夹的操作——获取当前路径方法
244 0
文件和文件夹的操作——文件夹的操作
文件和文件夹的操作——文件夹的操作
99 0
文件和文件夹的操作——文件夹的操作