本文讨论Windows操作系统中驱动器、文件、文件夹(目录)和路径的处理,并将常用操作封装到cfx命名空间的Drv、CFile和Dir类。
.Net Framework类库中,文件系统操作资源定义在System.IO命名空间。路径处理资源主要包括Path类,下面是一些常用方法:
下面的代码演示了这些方法的应用。
using System; using System.IO; namespace csfx_demo { class Program { static void Main(string[] args) { string path = @"d:\test\abc.txt"; // Console.WriteLine(Path.GetDirectoryName(path)); Console.WriteLine(Path.GetFileName(path)); Console.WriteLine(Path.GetFileNameWithoutExtension(path)); Console.WriteLine(Path.HasExtension(path)); Console.WriteLine(Path.GetExtension(path)); Console.WriteLine(Path.ChangeExtension(path, ".text")); Console.WriteLine(Path.GetPathRoot(path)); Console.WriteLine(Path.Combine(@"d:\tmp", @"xyz.txt")); } } }
代码执行结果如下图所示。
应注意,使用Path类操作时并不检查路径中的目录和文件是否真实存在,只是对路径的文本内容进行操作。
Directory类定义了目录操作的静态方法,常用的有:
DirectoryInfo类是目录处理的可实例化类,构造函数中可以使用包含目录路径的字符串作为参数,创建对象后可以使用以下属性获取目录信息:
DirectoryInfo对象的常用方法包括:
Directory和DirectoryInfo类中有一些同名和功能相似的操作方法,需要注意这些方法的参数和返回值,并根据需要合理使用。此外,还可以对常用的功能进行封装,如下面的代码(cfx/Dir.cs)。
using System.IO; using System.Collections.Generic; // namespace cfx { public static class Dir { // 创建路径 public static bool Create(string path) { try { if (Directory.Exists(path)) { return true; } else { Directory.CreateDirectory(path); return true; } } catch { return false; } } // 判断目录是否存在 public static bool Exists(string path) { return Directory.Exists(path); } // 按过滤读取文件名列表 public static string[] GetFiles(string path, string filter = "*.*", bool onlyFileName = false) { string[] files = Directory.GetFiles(path, filter); if (onlyFileName) { List<string> result = new List<string>(); for (int i = 0; i < files.Length; i++) result.Add(Path.GetFileName(files[i])); return result.ToArray(); } else { return files; } } } }
代码中定义了Dir静态类,其中包含三个方法:
假设不存在d:\test1目录,有d:\test目录,其中包含a.txt、b.txt和c.txt三个文件;下面的代码测试了cfx.Dir类的使用。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { string path = @"d:\test\"; string path1 = @"d:\test\1"; // Console.WriteLine(Dir.Exists(path1)); // False Console.WriteLine(Dir.Create(path1)); // True Console.WriteLine(Dir.Create(path1)); // False // string[] fileNames = Dir.GetFiles(path, "*.txt", true); foreach(string s in fileNames) { Console.WriteLine(s); } } } }
文件同样有两个类,分别是定义静态方法的File类和可实例化的FileInfo类。File类常用的方法有:
AppendLines(path,lines),在文件后追加多行文本,如果文件不存在则创建它。
AppendText(path,text),在文件后追加文本内容,如果文件不存在则创建它。
Copy(path1,path2),将path1文件复制到path2,可以使用第三个参数指定在file2存在时是否覆盖它,不指定或指定为false,则path2已存在时会产生异常。
Exists(path),判断文件是否存在,存在时返回true,否则返回false。
Move(path1,path2),将path1文件移动到path2位置。
ReadAllLines(path),读取文本文件的所有行,返回string[]数组。
ReasAllText(path),读取文本文件的所有内容,返回string类型。
WriteAllLines(path, lines),将多行内容写入文本文件,操作将覆盖文件中的原有内容,追加文本行时应使用AppendLines()方法。
WriteAllText(path, text),将文本内容写入文本文件,操作将覆盖文件中的原有内容,追加文本内容时应使用AppendText()方法。
FileInfo类的构造函数可以使用包含文件位置的路径作为参数,常用属性包括:
FileInfo对象方法和File类的方法功能相似,这里不再一一列举。
下面的代码(cfx/CFile.cs),可以对文件的常用操作进行封装。
using System.Drawing.Imaging; using System.Drawing; using System.IO; // namespace cfx { public static class CFile { // 文件是否存在 public static bool Exists(string filename) { try { return File.Exists(filename); } catch { return false; } } // 返回路径中的文件名 public static string GetFileName(string path) { try { return Path.GetFileName(path); } catch { return ""; } } // 不包含扩展名的文件名 public static string GetBaseName(string path) { try { return Path.GetFileNameWithoutExtension(path); } catch { return ""; } } // 文件扩展名(小写) public static string GetExtName(string path) { try { return Path.GetExtension(path).ToLower(); } catch { return ""; } } // 删除文件 public static bool Delete(string path) { try { if (File.Exists(path)) { File.Delete(path); return true; } else { return true; } } catch { return false; } } // 复制文件 public static bool Copy(string source, string target) { try { File.Copy(source, target, true); return File.Exists(target); } catch { return false; } } // public static string ReadAllText(string filename) { try { return File.ReadAllText(filename); } catch { return ""; } } // public static bool WriteAllText(string filename, string content) { try { File.WriteAllText(filename, content); return File.Exists(filename); } catch { return false; } } // 读取所有行 public static string[] ReadAllLines(string path) { try { return File.ReadAllLines(path); } catch { return new string[0]; } } // 写入所有行 public static bool WriteLines(string filename, string[] lines) { try { File.WriteAllLines(filename, lines); return File.Exists(filename); } catch { return false; } } // 文件重命名,相同目录下 public static bool Rename(string path, string newFileName) { try { string dirPath = Path.GetDirectoryName(path); string newPath = Path.Combine(dirPath, newFileName); if (Exists(path) == false || Exists(newPath) == true) return false; File.Move(path, newPath); return true; } catch { return false; } } // 判断是否为.zip文件 public static bool IsZip(string filename) { try { return Path.GetExtension(filename).ToLower() == ".zip"; } catch { return false; } } } }
代码中封装了CFile类,其中包含了文件的一些常用操作。
Exists(string filename)方法,判断文件是否存在。
GetFileName(string path)方法,返回文件名,包括基本名称和扩展名。
GetBaseName(string path)方法,返回文件基本名称,不包含扩展名。
GetExtName(string path)方法,返回文件的扩展名。
Delete(string path)方法,删除文件。如果文件不存在也会返回true。
Copy(string source, string target)方法,复制文件。
ReadAllText(string filename)方法,读取文本文件的所有内容,出错时返回空字符串。
WriteAllText(string filename, string content)方法,将文本写入文本文件,操作会替换文件原内容,写后确认文件存在并返回true;操作错误返回false。
ReadAllLines(string path)方法,读取文本文件的所有行并返回string[]数组,读取错误返回包含0个元素的空数组。
WriteLines(string filename, string[] lines)方法,将多行文本写入文本文件,操作成功返回true,否则返回false。
Rename(string path, string newFileName)方法,文件重命名。
IsZip(string filename)方法,以扩展名是为是.zip判断文件是否为ZIP文件。
假设有d:\test目录,其中包含a.txt文件,文件中包含a1、a2、a3三行文本;下面的代码,在Program.cs文件中测试CFile类的应用。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { string path1 = @"d:\test\a.txt"; string path2 = @"d:\test\b.txt"; // Console.WriteLine(CFile.Exists(path1)); // True Console.WriteLine(CFile.Exists(path2)); // Fasle Console.WriteLine(CFile.GetFileName(path1)); // a.txt Console.WriteLine(CFile.GetBaseName(path1)); // a Console.WriteLine(CFile.GetExtName(path1)); // .txt string[] lines = CFile.ReadAllLines(path1); foreach(string ln in lines) { Console.WriteLine(ln); } Console.WriteLine(CFile.WriteLines(path2, lines)); // True } } }
获取驱动器信息可以使用DriveInfo类,其构造函数需要使用"a"到"z"的字符串作为参数,其中,"a"和"b"为软盘驱动器,从"c"开始应用于硬盘分区或其它类型的驱动器。下面的代码,通过在cfx/Drv.cs文件中封装Drv类来演示DriveInfo类的应用。
using System.IO; namespace cfx { public static class Drv { // 获取全部尺寸 public static long GetTotalSize(string s) { try { return new DriveInfo(s).TotalSize; } catch { return -1000; } } // 获取可用尺寸 public static long GetAvailableSize(string s) { try { return new DriveInfo(s).AvailableFreeSpace; } catch { return -1000; } } // 获取空闲尺寸 public static long GetFreeSize(string s) { try { return new DriveInfo(s).TotalFreeSpace; } catch { return -1000; } } // 判断驱动器状态 public static bool IsReady(string s) { try { return new DriveInfo(s).IsReady; } catch { return false; } } // 获取驱动器格式,如NTFS,FAT32 public static string GetFormat(string s) { try { return new DriveInfo(s).DriveFormat; } catch { return ""; } } // 驱动器名称,如C:\ public static string GetName(string s) { try { return new DriveInfo(s).Name; } catch { return ""; } } // 获取驱动器卷标 public static string GetVolumeLabel(string s) { try { return new DriveInfo(s).VolumeLabel; } catch { return ""; } } // 驱动器类型,返回整数值 public static int GetDriveType(string s) { try { return (int)new DriveInfo(s).DriveType; } catch { return -1000; } } } }
代码中定义了Drv类,其中的静态方法参数都使用"a"到"z"的字符串;定义的方法包括:
GetTotalSize()方法,返回驱动器全部尺寸,单位为字节。
GetAvailableSize()方法,返回驱动器可用的尺寸,单位为字节。
GetFreeSize()方法,返回驱动器空闲尺寸,单位为字节。
IsReady()方法,返回驱动器状态。
GetFormat()方法,返回驱动器格式,如NTFS、FAT32。
GetName()方法,返回驱动器名称,如C:\。
GetVolumeLabel()方法,返回驱动器卷标。
GetDriveType()方法,获取驱动器类型,返回为DriveType枚举成员的整数值,对应的枚举成员和整数值如下表。
下面的代码显示了作者计算中D盘的相关信息。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "d"; Console.WriteLine(Drv.GetTotalSize(s)); Console.WriteLine(Drv.GetAvailableSize(s)); Console.WriteLine(Drv.GetName(s)); Console.WriteLine(Drv.IsReady(s)); } } }
获取驱动器的尺寸时,默认单位为字节,可以使用整数的位运算改变单位对应的数值,如下面的代码。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "d"; Console.WriteLine(Drv.GetTotalSize(s)+" bytes"); Console.WriteLine((Drv.GetTotalSize(s) >> 10) + " KB"); Console.WriteLine((Drv.GetTotalSize(s) >> 20) + " MB"); Console.WriteLine((Drv.GetTotalSize(s) >> 30) + " GB"); } } }
需要保留小数部分,可以参考如下代码。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "d"; Console.WriteLine(Drv.GetTotalSize(s) + " bytes"); Console.WriteLine(Math.Round(Drv.GetTotalSize(s) / Math.Pow(2, 10),2)+" KB"); Console.WriteLine(Math.Round(Drv.GetTotalSize(s) / Math.Pow(2, 20), 2) + " MB"); Console.WriteLine(Math.Round(Drv.GetTotalSize(s) / Math.Pow(2, 30), 2) + " GB"); } } }
代码中,使用Math.Pow()方法计算2的次方,返回结果为double类型,然后使用尺寸数据除以它,结果同样为double类型,最后,使用Math.Round()方法保留两位小数形式并显示。
以MB为单位是常见的操作,下面的代码(cfx/Drv.cs),会在Drv类中添加新的驱动器尺寸获取方法,其返回值为整数,单位为MB。
using System.IO; namespace cfx { public static class Drv { // 其它参数 // 获取全部尺寸MB public static long GetTotalMB(string s) { try { return new DriveInfo(s).TotalSize>>20; } catch { return -1000; } } // 获取可用尺寸 public static long GetAvailableMB(string s) { try { return new DriveInfo(s).AvailableFreeSpace>>20; } catch { return -1000; } } // 获取空闲尺寸 public static long GetFreeMB(string s) { try { return new DriveInfo(s).TotalFreeSpace>>20; } catch { return -1000; } } } }
实际工作中,可以根据需要扩展Dir、Drv和CFile类的方法。