前言
官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/file-system/
官方文档写的真心不错。
常用路径
系统特殊文件夹的目录路径
https://docs.microsoft.com/zh-cn/dotnet/api/system.environment.specialfolder?redirectedfrom=MSDN&view=netcore-3.1
项目根目录
代码语言:javascript复制string projectPath =AppDomain.CurrentDomain.BaseDirectory;
我的文档
代码语言:javascript复制string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
桌面
代码语言:javascript复制string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
数据目录
代码语言:javascript复制string ApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
EXE路径
代码语言:javascript复制string starupPath = GetType().Assembly.Location;
Console.WriteLine("starupPath:" starupPath);
string starupPath2 = Process.GetCurrentProcess().MainModule.FileName;
Console.WriteLine("starupPath2:" starupPath2);
Download路径
Windows没有为下载
文件夹定义CSIDL.aspx),并且通过Environment.SpecialFolder
枚举无法使用它。
但是,新的Vista 知名文件夹.aspx) API确实使用ID定义它FOLDERID_Downloads
.aspx)。获取实际值的最简单方法可能是SHGetKnownFolderPath
.aspx)。
public static class KnownFolder
{
public static readonly Guid Downloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath);
private static string GetDownloadPath()
{
string downloadsPath;
SHGetKnownFolderPath(KnownFolder.Downloads, 0, IntPtr.Zero, out downloadsPath);
Console.WriteLine(downloadsPath);
return downloadsPath;
}
路径拼接
代码语言:javascript复制Path.Combine(ZConfig.basePath, "images")
注意
这样路径拼接后类似于
E:projectschoolclientbinx86Debugimages
,没有最后的反斜杠 参数可以多个,类型必须为字符串
文件夹
创建文件夹
代码语言:javascript复制var dirPath = ZConfig.cacheImagePath;
DirectoryInfo directoryInfo = new DirectoryInfo(dirPath);
if (!directoryInfo.Exists)
{
System.IO.Directory.CreateDirectory(dirPath);
}
根据文件路径创建文件夹
代码语言:javascript复制FileInfo fi = new FileInfo(filepath);
var di = fi.Directory;
if (!di.Exists)
{
di.Create();
}
删除文件夹
代码语言:javascript复制DirectoryInfo tongpingPath = new DirectoryInfo(ZConfig.classTongpingPath());
if (tongpingPath.Exists)
{
tongpingPath.Delete(true);
}
其中
Delete(true)会自动删除子文件夹
文件
向文件写入一个字符串
代码语言:javascript复制using System.IO;
using System.Threading.Tasks;
class WriteAllText
{
public static async Task ExampleAsync()
{
string text =
"A class is the most powerful data type in C#. Like a structure, "
"a class defines the data and behavior of the data type. ";
await File.WriteAllTextAsync("WriteText.txt", text);
}
}
将文本追加到现有文件
代码语言:javascript复制using System.IO;
using System.Threading.Tasks;
class StreamWriterTwo
{
public static async Task ExampleAsync()
{
using StreamWriter file = new("WriteLines2.txt", append: true);
await file.WriteLineAsync("Fourth line");
}
}
读取文本文件
代码语言:javascript复制int counter = 0;
// Read the file and display it line by line.
foreach (string line in System.IO.File.ReadLines(@"c:test.txt"))
{
System.Console.WriteLine(line);
counter ;
}
System.Console.WriteLine("There were {0} lines.", counter);
// Suspend the screen.
System.Console.ReadLine();
异常
以下情况可能会导致异常:
- InvalidOperationException:文件已存在并且为只读。
- PathTooLongException:路径名可能太长。
- IOException:磁盘可能已满。
使用文件系统时,还有其他可能会导致异常的情况,因此最好进行防御性编程。
文件夹/文件复制移动
循环访问目录树
如果你确信拥有指定根目录下的所有目录的访问权限,则可以使用 System.IO.SearchOption.AllDirectories
标志。 此标志返回与指定的模式匹配的所有嵌套的子目录。
root.GetDirectories("*.*", System.IO.SearchOption.AllDirectories);
此方法的缺点是,如果指定根目录下的任何子目录引发 DirectoryNotFoundException 或 UnauthorizedAccessException 异常,则整个方法失败且不返回任何目录。 使用 GetFiles 方法时也是如此。 如果需要处理特定子文件夹中的异常,则必须手动遍历目录树,如以下示例所示。
手动遍历目录树时,可以先处理文件(前序遍历),或者先处理子目录(后序遍历)。 如果执行前序遍历,则可直接访问该文件夹本身下的文件,然后遍历当前文件夹下的整个树。 后序遍历是另一种方法,在访问当前文件夹的文件之前遍历下面的整个树。 本文档后面的示例执行的是前序遍历,但你可以轻松地修改它们以执行后序遍历。
获取目录下所有文件
代码语言:javascript复制root.GetFiles("*.*");
另一种选择是,是使用递归遍历还是基于堆栈的遍历。
本文档后面的示例演示了这两种方法
下面的示例演示如何以递归方式遍历目录树。
递归方法是一种很好的方法,但是如果目录树较大且嵌套深度较深,则可能引起堆栈溢出异常。
在每个文件或文件夹上处理的特定异常和执行的特定操作仅作为示例提供。
代码语言:javascript复制public class RecursiveFileSearch
{
static System.Collections.Specialized.StringCollection log = new System.Collections.Specialized.StringCollection();
static void Main()
{
// Start with drives if you have to search the entire computer.
string[] drives = System.Environment.GetLogicalDrives();
foreach (string dr in drives)
{
System.IO.DriveInfo di = new System.IO.DriveInfo(dr);
// Here we skip the drive if it is not ready to be read. This
// is not necessarily the appropriate action in all scenarios.
if (!di.IsReady)
{
Console.WriteLine("The drive {0} could not be read", di.Name);
continue;
}
System.IO.DirectoryInfo rootDir = di.RootDirectory;
WalkDirectoryTree(rootDir);
}
// Write out all the files that could not be processed.
Console.WriteLine("Files with restricted access:");
foreach (string s in log)
{
Console.WriteLine(s);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key");
Console.ReadKey();
}
static void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
// First, process all the files directly under this folder
try
{
files = root.GetFiles("*.*");
}
catch (UnauthorizedAccessException e)
{
log.Add(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
Console.WriteLine(fi.FullName);
}
// Now find all the subdirectories under this directory.
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
// Resursive call for each subdirectory.
WalkDirectoryTree(dirInfo);
}
}
}
}
下面的示例演示如何不使用递归方式遍历目录树中的文件和文件夹。
此方法使用泛型 Stack 集合类型,此集合类型是一个后进先出 (LIFO) 堆栈。
代码语言:javascript复制public class StackBasedIteration
{
static void Main(string[] args)
{
// Specify the starting folder on the command line, or in
// Visual Studio in the Project > Properties > Debug pane.
TraverseTree(args[0]);
Console.WriteLine("Press any key");
Console.ReadKey();
}
public static void TraverseTree(string root)
{
// Data structure to hold names of subfolders to be
// examined for files.
Stack<string> dirs = new Stack<string>(20);
if (!System.IO.Directory.Exists(root))
{
throw new ArgumentException();
}
dirs.Push(root);
while (dirs.Count > 0)
{
string currentDir = dirs.Pop();
string[] subDirs;
try
{
subDirs = System.IO.Directory.GetDirectories(currentDir);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
string[] files = null;
try
{
files = System.IO.Directory.GetFiles(currentDir);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
// Perform the required action on each file here.
// Modify this block to perform your required task.
foreach (string file in files)
{
try
{
// Perform whatever action is required in your scenario.
System.IO.FileInfo fi = new System.IO.FileInfo(file);
Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
}
catch (System.IO.FileNotFoundException e)
{
// If file was deleted by a separate application
// or thread since the call to TraverseTree()
// then just continue.
Console.WriteLine(e.Message);
continue;
}
}
// Push the subdirectories onto the stack for traversal.
// This could also be done before handing the files.
foreach (string str in subDirs){
dirs.Push(str);
}
}
}
}
通常,检测每个文件夹以确定应用程序是否有权限打开它是一个很费时的过程。 因此,此代码示例只将此部分操作封装在 try/catch
块中。 你可以修改 catch
块,以便在拒绝访问某个文件夹时,可以尝试提升权限,然后再次访问此文件夹。 一般来说,仅捕获可以处理的、不会将应用程序置于未知状态的异常。
如果必须在内存或磁盘上存储目录树的内容,那么最佳选择是仅存储每个文件的 FullName 属性(类型为 string
)。 然后可以根据需要使用此字符串创建新的 FileInfo 或 DirectoryInfo 对象,或打开需要进行其他处理的任何文件。
复制文件和目录
代码语言:javascript复制// Simple synchronous file copy operations with no user interface.
// To run this sample, first create the following directories and files:
// C:UsersPublicTestFolder
// C:UsersPublicTestFoldertest.txt
// C:UsersPublicTestFolderSubDirtest.txt
public class SimpleFileCopy
{
static void Main()
{
string fileName = "test.txt";
string sourcePath = @"C:UsersPublicTestFolder";
string targetPath = @"C:UsersPublicTestFolderSubDir";
// Use Path class to manipulate file and directory paths.
string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
string destFile = System.IO.Path.Combine(targetPath, fileName);
// To copy a folder's contents to a new location:
// Create a new target folder.
// If the directory already exists, this method does not create a new directory.
System.IO.Directory.CreateDirectory(targetPath);
// To copy a file to another location and
// overwrite the destination file if it already exists.
System.IO.File.Copy(sourceFile, destFile, true);
// To copy all the files in one directory to another directory.
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
Console.WriteLine("Source path does not exist!");
}
// Keep console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
移动文件和目录
代码语言:javascript复制// Simple synchronous file move operations with no user interface.
public class SimpleFileMove
{
static void Main()
{
string sourceFile = @"C:UsersPublicpublictest.txt";
string destinationFile = @"C:UsersPublicprivatetest.txt";
// To move a file or folder to a new location:
System.IO.File.Move(sourceFile, destinationFile);
// To move an entire directory. To programmatically modify or combine
// path strings, use the System.IO.Path class.
System.IO.Directory.Move(@"C:UsersPublicpublictest", @"C:UsersPublicprivate");
}
}
删除文件和目录
代码语言:javascript复制// Simple synchronous file deletion operations with no user interface.
// To run this sample, create the following files on your drive:
// C:UsersPublicDeleteTesttest1.txt
// C:UsersPublicDeleteTesttest2.txt
// C:UsersPublicDeleteTestSubDirtest2.txt
public class SimpleFileDelete
{
static void Main()
{
// Delete a file by using File class static method...
if(System.IO.File.Exists(@"C:UsersPublicDeleteTesttest.txt"))
{
// Use a try block to catch IOExceptions, to
// handle the case of the file already being
// opened by another process.
try
{
System.IO.File.Delete(@"C:UsersPublicDeleteTesttest.txt");
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
return;
}
}
// ...or by using FileInfo instance method.
System.IO.FileInfo fi = new System.IO.FileInfo(@"C:UsersPublicDeleteTesttest2.txt");
try
{
fi.Delete();
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
// Delete a directory. Must be writable or empty.
try
{
System.IO.Directory.Delete(@"C:UsersPublicDeleteTest");
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
// Delete a directory and all subdirectories with Directory static method...
if(System.IO.Directory.Exists(@"C:UsersPublicDeleteTest"))
{
try
{
System.IO.Directory.Delete(@"C:UsersPublicDeleteTest", true);
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
}
// ...or with DirectoryInfo instance method.
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(@"C:UsersPublicpublic");
// Delete this dir and all subdirs.
try
{
di.Delete(true);
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
}
}