本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在软件开发中,批量处理文件是一项常见需求。本文介绍了一个C#编写的文件批量拷贝和剪切工具,该工具利用C#的系统级I/O功能以及.NET框架提供的API,实现文件的高效操作。文章深入探讨了FileStream、Path类、File与Directory类的使用,以及如何通过多线程和异步操作提升性能,还涉及了异常处理和用户界面设计等关键要素。

1. 文件批量操作的基础知识和C#实现

在现代软件开发中,文件批量操作是一个常见的需求,尤其是在处理大量数据时。它允许开发者通过自动化的方式来执行文件的创建、读取、写入、删除等操作,从而大大提高效率。C#作为一门功能强大的编程语言,提供了丰富且灵活的API,让开发者能够轻松实现复杂的文件操作。

1.1 文件批量操作的概念

文件批量操作主要涉及对文件集合的集中处理。例如,批量删除旧日志文件、批量重命名文件以符合新的命名规范、批量压缩解压文件等。理解文件批量操作的基本概念是实现这类任务的第一步。

1.2 C#实现文件批量操作

在C#中,文件批量操作可以通过标准库中的 System.IO 命名空间实现。使用诸如 DirectoryInfo FileInfo Directory File 类,开发者可以编写出执行批量操作的程序代码。下面将通过一个简单的示例,展示如何使用C#来批量复制文件:

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string sourcePath = @"C:\Source";  // 源文件夹路径
        string destinationPath = @"C:\Destination"; // 目标文件夹路径

        // 创建目标文件夹如果它不存在
        if (!Directory.Exists(destinationPath))
            Directory.CreateDirectory(destinationPath);

        // 获取源文件夹内所有文件
        FileInfo[] files = new DirectoryInfo(sourcePath).GetFiles();

        foreach (FileInfo file in files)
        {
            // 构建目标文件路径
            string destFile = Path.Combine(destinationPath, file.Name);
            // 执行复制操作
            file.CopyTo(destFile, true); // true参数表示覆盖目标文件
        }

        Console.WriteLine("文件批量复制完成。");
    }
}

上面的代码段展示了如何使用C#在指定的源路径和目标路径之间批量复制文件。使用 GetFiles 方法获取源路径下所有文件信息,然后通过 CopyTo 方法将每个文件复制到目标路径。这是文件批量操作的一个基础应用实例,但能力远不止于此。随着章节的深入,我们会探讨更多高级功能,如流处理、路径处理、异步操作和用户界面集成等。

2. C#文件流与缓冲区的实际应用

在现代软件开发中,文件操作是不可避免的一部分,尤其在处理大量数据时,掌握文件流(FileStream)和缓冲区(Buffer)的高效使用至关重要。本章节将深入探讨这些主题,并提供实际应用的示例。

2.1 文件流(FileStream)基础

文件流是用于读取和写入文件的应用程序编程接口(API)。它们为文件操作提供了一种抽象,隐藏了底层操作系统或文件系统实现的细节。文件流在.NET中非常常见,并且是处理文件数据的基础。

2.1.1 文件流的创建和打开

要创建文件流,可以使用 System.IO.FileStream 类。这可以通过多种方式完成,包括创建新文件、打开现有文件进行读取或写入,或者以追加模式打开文件。以下是一个简单的示例,演示如何打开一个现有文件进行读取:

using System.IO;

class Program
{
    static void Main()
    {
        // 创建并打开一个用于读取的FileStream
        using (FileStream fs = new FileStream("example.txt", FileMode.Open, FileAccess.Read))
        {
            // 文件操作代码将在这里添加
        }
    }
}

在上面的代码中, FileStream 对象 fs 是通过指定文件路径 "example.txt" ,模式 FileMode.Open (打开现有文件)以及 FileAccess.Read (读取访问权限)创建的。

2.1.2 文件流的读写操作

一旦创建了文件流,就可以根据需要对其进行读写操作。读取操作通常涉及从文件流中读取数据并将其放入内存中的缓冲区。写入操作则将数据从内存中的缓冲区转移到文件流中。

读取操作的一个示例:

byte[] buffer = new byte[1024]; // 创建一个缓冲区用于读取
int bytesRead;

while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
    // 处理读取的数据
    string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);
    // ...
}

写入操作示例:

byte[] dataToWrite = Encoding.ASCII.GetBytes("Hello, world!");
fs.Write(dataToWrite, 0, dataToWrite.Length);

在这个写入示例中,我们首先将字符串转换为字节数组,然后通过 Write 方法写入文件流中。

2.2 缓冲区(Buffer)的处理

缓冲区是用于临时存储数据的内存区域,它在文件操作中用于减少对磁盘的访问次数,提高性能。理解缓冲区的工作原理对于开发高效的文件处理程序是至关重要的。

2.2.1 缓冲区的作用和设置

缓冲区的工作是临时保存数据,直到足够多的数据被收集以进行有效的传输。例如,当写入文件时,程序可能不会每次写入一个字节,而是累积多个字节到缓冲区,然后一次性写入到磁盘,从而减少磁盘I/O操作次数。

在.NET中,可以使用 FileStream 类的构造函数设置缓冲区大小:

FileStream fs = new FileStream("example.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8192, useAsync: true);

在这个例子中, 8192 表示缓冲区的大小是8KB。较大的缓冲区可以提高写入性能,但是也会增加内存的使用。

2.2.2 缓冲区在文件操作中的应用

在实际应用中,通常会结合使用 FileStream 和缓冲区来完成文件操作。例如,以下代码演示了如何在读取操作中使用缓冲区:

int bufferSize = 1024; // 设置缓冲区大小为1KB
byte[] buffer = new byte[bufferSize];
int bytesRead;

while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
    // 将读取的数据从缓冲区写入到另一个文件流中
    using (FileStream fsOutput = new FileStream("output.txt", FileMode.Create, FileAccess.Write))
    {
        fsOutput.Write(buffer, 0, bytesRead);
    }
}

在这个例子中,我们创建了一个读取文件流 fs 和一个写入文件流 fsOutput 。我们读取数据到缓冲区 buffer 中,然后将缓冲区的数据写入到 fsOutput 中。

通过使用缓冲区,可以减少对磁盘的访问次数,从而提高文件操作的效率。这是优化大文件操作性能的关键策略之一。

在下一章节,我们将探讨更高级的主题,如路径处理和文件操作API,以进一步提高文件操作的效率和可靠性。

3. 深入文件路径处理和操作API

3.1 路径处理(System.IO.Path类)

3.1.1 路径的基本操作和注意事项

在处理文件和目录时,路径管理是一个不可或缺的环节。C#通过 System.IO.Path 类提供了一系列对路径进行操作的方法。例如,获取文件的扩展名、合并路径、判断路径是否绝对等。

首先,路径操作需要注意以下几点:

  • 跨平台路径差异:不同的操作系统使用不同的路径分隔符。Windows使用反斜杠( \ ),而Unix/Linux系统使用正斜杠( / )。 System.IO.Path 类会根据运行的操作系统自动处理这种差异。
  • 路径长度限制:操作系统对路径长度有特定的限制。例如,Windows在旧版本中路径长度不能超过255个字符,这被称为“8.3文件名限制”。虽然现代Windows系统如Windows 10可以支持更长的路径,但仍需留意可能存在的限制。
  • 路径验证:在进行文件或目录操作前,验证路径的正确性可以避免运行时错误。 System.IO.Path 类提供方法如 Path.GetFullPath 验证路径是否存在。

下面是一个简单的代码示例,演示了如何使用 System.IO.Path 类获取文件的扩展名,并将两个路径合并:

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string pathToFile = @"C:\Documents\file.txt";
        string extension = Path.GetExtension(pathToFile);
        Console.WriteLine("Extension: " + extension);

        string directory = @"C:\Documents";
        string fileName = "file.txt";
        string fullPath = Path.Combine(directory, fileName);
        Console.WriteLine("Full path: " + fullPath);
    }
}

这段代码将输出文件的扩展名和合并后的完整路径。在这个例子中, Path.GetExtension 用于获取路径字符串中文件的扩展名,而 Path.Combine 用于将目录路径与文件名安全地合并为一个完整的路径。

3.1.2 路径的标准化和验证

标准化路径是指将路径转换为一个标准的格式,例如,确保路径使用正确的分隔符,移除多余的点( . )和双点( .. )等。

System.IO.Path 类包含 GetFullPath 方法用于标准化路径。这个方法会解析任何相对路径,并转换成绝对路径,同时它还可以解析路径中的快捷方式,使其成为实际的路径。

string relativePath = @"....\Program Files";
string absolutePath = Path.GetFullPath(relativePath);
Console.WriteLine("Absolute path: " + absolutePath);

执行上述代码后, absolutePath 将为 C:\Program Files ,假设当前目录为 C:\Documents

验证路径是否有效,可以使用 Path.IsPathRooted 方法检测一个路径是否为绝对路径,以及使用 File.Exists Directory.Exists 方法检查路径对应的文件或目录是否存在。

bool isRooted = Path.IsPathRooted(relativePath);
Console.WriteLine("Is the path rooted? " + isRooted);

bool fileExists = File.Exists(absolutePath);
Console.WriteLine("Does the file exist? " + fileExists);

通过使用这些方法,开发者可以确保路径的正确性并预防一些常见的文件操作错误。

3.2 文件操作API(File类和Directory类)

3.2.1 File类提供的文件操作功能

System.IO.File 类提供了一系列静态方法来执行文件操作,包括创建、删除、复制和移动文件。它还支持文件属性的读取和设置等。

创建文件:

string filePath = @"C:\Documents\newFile.txt";
using (FileStream fs = File.Create(filePath))
{
    // 文件创建成功,fs为文件流对象
}

删除文件:

bool deleted = File.Delete(filePath);
if (deleted)
{
    Console.WriteLine("File deleted successfully");
}
else
{
    Console.WriteLine("File could not be deleted");
}

复制文件:

string destFile = @"C:\Documents\copyOfNewFile.txt";
bool copied = File.Copy(filePath, destFile);
if (copied)
{
    Console.WriteLine("File copied successfully");
}
else
{
    Console.WriteLine("File could not be copied");
}

移动文件:

string newDestination = @"C:\Archives";
bool moved = File.Move(filePath, Path.Combine(newDestination, Path.GetFileName(filePath)));
if (moved)
{
    Console.WriteLine("File moved successfully");
}
else
{
    Console.WriteLine("File could not be moved");
}

File 类还有更多高级功能,比如读取文件属性、更改文件的最后访问和修改时间等,使得文件管理更为灵活。

3.2.2 Directory类提供的目录操作功能

目录管理是文件操作中的另一个重要方面, System.IO.Directory 类提供了许多用于目录操作的静态方法,包括创建、删除、移动目录以及枚举目录中的文件和子目录。

创建目录:

string directoryPath = @"C:\NewDirectory";
Directory.CreateDirectory(directoryPath);

删除目录:

bool deleted = Directory.Delete(directoryPath);
if (deleted)
{
    Console.WriteLine("Directory deleted successfully");
}
else
{
    Console.WriteLine("Directory could not be deleted");
}

枚举目录:

string searchPath = @"C:\";

// 使用SearchOption.AllDirectories来递归地枚举目录
string[] files = Directory.GetFiles(searchPath, "*.*", SearchOption.AllDirectories);

foreach (string file in files)
{
    Console.WriteLine("File: " + file);
}

移动目录:

string newParent = @"C:\Archives";
Directory.Move(directoryPath, Path.Combine(newParent, Path.GetFileName(directoryPath)));

Directory 类还包含方法来获取特定目录的信息,如 DirectoryInfo 类,它可以用来表示具有特定路径的目录,并进行更复杂的操作。

在使用 Directory 类时,需要小心处理可能出现的异常,比如目录访问权限问题或目录不存在的情况。建议始终使用异常处理机制来确保程序的健壮性。

通过这些基础操作和注意事项,开发者可以更加高效且安全地管理文件和目录。在下一节中,我们将深入探讨文件遍历和多线程技术在文件系统操作中的应用。

4. ```

第四章:文件遍历和多线程技术

文件遍历是文件系统操作中常见的需求,无论是进行数据备份、搜索特定文件、还是执行系统维护任务,都离不开对文件和目录结构的遍历。同时,为了提高效率和用户体验,多线程技术在文件操作中的应用变得越来越重要。在本章节中,我们将深入了解如何使用C#进行文件遍历和多线程技术的实践应用。

4.1 遍历文件和目录(DirectoryInfo类)

4.1.1 如何使用DirectoryInfo类进行遍历

DirectoryInfo 类是.NET中用于获取文件系统信息的一个重要类,它提供了很多有用的方法来遍历目录和子目录。通过使用递归或队列方式,我们能够实现文件和目录的深度或广度优先遍历。

下面是一个简单的代码示例,展示了如何使用 DirectoryInfo 类进行深度优先遍历:

using System;
using System.IO;

public class DirectoryTraverser
{
    public static void Traverse(string path)
    {
        DirectoryInfo root = new DirectoryInfo(path);
        Iterate(root);
    }

    private static void Iterate(DirectoryInfo dirInfo)
    {
        // 处理当前目录
        foreach (FileInfo fileInfo in dirInfo.GetFiles())
        {
            Console.WriteLine(fileInfo.FullName);
        }

        // 递归处理每一个子目录
        foreach (DirectoryInfo subDirInfo in dirInfo.GetDirectories())
        {
            Iterate(subDirInfo);
        }
    }
}

在上述代码中,我们定义了一个 Traverse 方法,它接受一个目录路径作为参数。在这个方法中,我们创建了一个 DirectoryInfo 实例来表示该路径,并调用了 Iterate 方法。 Iterate 方法首先遍历并处理当前目录下的所有文件,然后递归地遍历每一个子目录。

4.1.2 遍历中的常见问题和解决办法

在使用 DirectoryInfo 类进行遍历时,可能遇到的常见问题包括访问权限问题、文件系统差异以及性能瓶颈等。

  • 访问权限问题 :当遍历的目录或文件被其他进程锁定时,可能会抛出 UnauthorizedAccessException 异常。为了解决这个问题,我们应该对文件操作添加异常处理逻辑,以确保程序的健壮性。
  • 文件系统差异 :不同的操作系统文件系统可能有所不同,例如Windows使用NTFS,而Linux使用ext4。因此,在遍历时需要注意不同操作系统的文件系统差异,避免使用某些仅限于特定文件系统的特性。
  • 性能瓶颈 :在遍历大量文件或目录时,性能可能会成为瓶颈。可以考虑使用多线程或异步操作来并行处理多个子目录,从而提升整体的遍历效率。

4.2 多线程技术(System.Threading命名空间)

多线程技术是处理文件操作中非常重要的一个方面,尤其是当需要处理大量文件或执行耗时较长的操作时。通过合理地使用多线程,可以显著提升程序的性能和响应速度。

4.2.1 线程的创建和管理

在.NET中,我们通常使用 Thread 类来创建和管理线程。下面展示了如何使用 Thread 类创建一个新线程,并执行一个简单的任务:

using System;
using System.Threading;

public class Worker
{
    public void DoWork()
    {
        // 执行一些工作,例如遍历文件等操作
    }
}

public class ThreadExample
{
    public static void Main()
    {
        Worker worker = new Worker();
        Thread thread = new Thread(new ThreadStart(worker.DoWork));
        thread.Start();
    }
}

在这个示例中,我们定义了一个 Worker 类,它有一个 DoWork 方法,用于执行实际的工作。然后在 ThreadExample 类的 Main 方法中,我们创建了一个 Thread 对象,并将 Worker.DoWork 方法作为要执行的线程操作。调用 Start 方法来启动线程。

4.2.2 线程同步和异步执行

在多线程环境中,线程同步非常重要,它确保了共享资源在访问时不会产生数据竞争或不一致的结果。我们可以使用多种同步原语来实现线程间的同步,例如 Monitor Mutex Semaphore EventWaitHandle 等。

同时,使用异步执行可以提高程序对用户输入的响应性,尤其是在执行耗时文件操作时。通过使用 async await 关键字,我们可以轻松地将异步编程集成到我们的应用程序中。

在下面的代码示例中,我们展示了如何使用 async await 来异步执行文件操作:

using System;
using System.IO;
using System.Threading.Tasks;

public class AsyncFileOperations
{
    public static async Task ProcessFileAsync(string filePath)
    {
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            // 假设我们有一个异步读取数据的方法
            byte[] data = await ReadDataAsync(fs);
            // 处理数据
        }
    }

    private static async Task<byte[]> ReadDataAsync(Stream stream)
    {
        // 异步读取数据的逻辑
        // ...
        return new byte[] { /* 数据 */ };
    }
}

在上述代码中, ProcessFileAsync 方法接收一个文件路径作为参数,并以异步方式处理该文件。我们使用 FileStream 的异步方法来读取文件数据,这样不会阻塞主线程,从而提升用户体验。

通过以上内容,本章已经展示了如何使用 DirectoryInfo 类进行高效的文件遍历以及如何利用多线程技术来提升文件操作的性能和响应速度。在接下来的章节中,我们将继续深入探讨异步操作、异常处理和用户界面设计。



# 5. 异步操作、异常处理和用户界面设计

## 5.1 异步操作(async/await)

### 5.1.1 异步编程的原理和优势

异步编程是一种让程序可以在等待诸如I/O操作等耗时任务时继续执行其他任务的编程模式。异步方法在等待操作完成时不会阻塞线程,这意味着UI可以保持响应,其他操作也可以同时进行。它对于提高应用程序的性能和用户体验至关重要。

在C#中,`async`和`await`关键字的引入,使得异步编程变得简单直观。`async`关键字用于标记一个方法,指示它是一个异步操作。而`await`关键字用于在异步方法中等待一个`Task`或`Task<T>`对象完成,它可以暂停异步方法的执行,直到等待的任务完成,并在任务完成时恢复异步方法的执行。

使用异步方法有如下优势:
1. **提高应用程序响应性**:UI线程不需要等待耗时操作,从而能够持续响应用户操作。
2. **提升资源利用率**:应用程序可以更加高效地使用系统资源,通过并发执行多个任务。
3. **更好的用户体验**:减少等待时间,提高应用程序的交互性和流畅度。

### 5.1.2 如何在文件操作中实现异步

在文件操作中,尤其是在处理大文件或网络文件时,使用异步操作可以显著提高程序性能。以下是一个简单的C#异步文件读取示例:

```csharp
using System;
using System.IO;
using System.Threading.Tasks;

public class AsyncFileOperations
{
    public static async Task ReadFileAsync(string path)
    {
        using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            // Read asynchronously, so the UI thread is not blocked
            byte[] buffer = new byte[fs.Length];
            await fs.ReadAsync(buffer, 0, buffer.Length);
            // Do something with the data
        }
    }
}

在上述示例中, FileStream ReadAsync 方法是一个异步操作,它允许读取文件的同时UI可以继续响应用户操作。 await 关键字使得方法在读取完成之前暂停,但不会阻塞线程。

此异步模式不仅适用于文件读取,同样适用于文件写入、复制、移动等操作。通过这种方式,可以将耗时的文件操作从主线程中分离出来,从而避免UI界面卡顿,提升用户体验。

5.2 异常处理(try-catch)

5.2.1 异常处理的最佳实践

异常处理是程序设计中不可分割的一部分,它确保了程序在遇到错误时能够优雅地处理错误并从中恢复。在C#中, try-catch 块用于处理异常。

在文件操作中,异常处理的常见实践包括:
1. 预检查 :在执行文件操作之前,预先检查相关条件,如文件是否存在、路径是否正确等。
2. 使用 try-catch :将可能引发异常的代码包裹在 try 块中,然后使用一个或多个 catch 块来捕获和处理特定类型的异常。
3. 异常记录 :捕获异常时,记录异常信息到日志文件,便于后续的错误追踪和调试。
4. 用户友好的错误提示 :在必要时向用户提供错误信息,但要避免泄露敏感信息。

try
{
    using (FileStream fs = new FileStream(path, FileMode.Open))
    {
        // Perform file operations
    }
}
catch (FileNotFoundException ex)
{
    // Handle file not found scenario
    Console.WriteLine("File not found: " + ex.Message);
    // Log the exception details
}
catch (IOException ex)
{
    // Handle other I/O related exceptions
    Console.WriteLine("I/O Error: " + ex.Message);
    // Log the exception details
}
catch (Exception ex)
{
    // Handle other unforeseen exceptions
    Console.WriteLine("Unexpected Error: " + ex.Message);
    // Log the exception details
}

5.2.2 自定义异常类和异常日志记录

在某些情况下,为了更精细地控制错误处理过程,你可能需要创建自定义异常类。自定义异常类可以从 System.Exception 类继承,并添加特定于你的应用程序的额外属性和行为。

异常日志记录是一种常见的做法,它涉及到捕获异常详情并将其写入日志文件或数据库,以便后续分析。常见的日志框架有log4net、NLog等。

public class CustomFileException : Exception
{
    public CustomFileException(string message)
        : base(message)
    {
    }

    public CustomFileException(string message, Exception innerException)
        : base(message, innerException)
    {
    }
}

// Usage in file operation
try
{
    // File operations that may throw an exception
}
catch (Exception ex)
{
    // Log the exception using a logging framework
    Logger.Log(new CustomFileException("An error occurred during file operation.", ex));
}

通过实现自定义异常和异常日志记录,你可以更准确地追踪错误来源,提高调试效率,并为最终用户提供更准确的错误信息。

5.3 用户界面(UI)设计(WPF/WinForms)

5.3.1 设计友好交互的UI界面

用户界面(UI)设计是任何应用程序成功的关键因素之一。它需要直观、易用且美观。在文件操作应用中,UI设计应考虑如下要素:

  1. 简洁性 :避免UI过于拥挤,提供清晰的导航路径和操作提示。
  2. 反馈性 :对于如文件上传、下载等耗时操作,提供清晰的进度反馈和状态信息。
  3. 一致性 :使用一致的视觉元素和布局,减少用户的学习成本。

在WPF或WinForms中,可以使用各种控件来构建UI。例如,使用 Button 控件来触发文件操作,使用 TextBox 来输入文件路径,使用 ProgressBar 来显示进度信息。

5.3.2 UI与后端逻辑的分离与协作

在现代应用程序开发中,UI与后端逻辑的分离是一个重要原则。这样做的好处包括提高代码的可维护性、可测试性和可扩展性。

分离可以通过将UI逻辑放在XAML(WPF)或设计器文件(WinForms)中,并将业务逻辑和数据处理放在代码后台文件(例如.cs或.vb文件)中来实现。这种方式使得UI设计者和开发者可以并行工作,且更易于各自管理自己的代码部分。

通过依赖注入等设计模式,还可以进一步将UI与后端逻辑解耦。这样可以在不同的环境下重用后端逻辑,例如在单元测试中。

<!-- WPF 示例 -->
<Button Content="Open File" Click="OpenFileDialog" />
<TextBox x:Name="filePathTextBox" Width="300" />
<ProgressBar IsIndeterminate="True" Value="{Binding ProgressValue}" />

在代码后台中,可以定义事件处理程序和数据绑定,以实现UI和后端逻辑之间的通信:

// WPF 后端代码示例
private void OpenFileDialog(object sender, RoutedEventArgs e)
{
    OpenFileDialog openFileDialog = new OpenFileDialog();
    if (openFileDialog.ShowDialog() == true)
    {
        filePathTextBox.Text = openFileDialog.FileName;
        // 文件打开逻辑
    }
}

通过以上代码,可以看出,UI逻辑通过事件和数据绑定与后端逻辑进行协作。这种方式不仅使得代码结构清晰,还提高了代码的可维护性和扩展性。

6. 状态监控、进度条和配置设置

6.1 状态监控与进度条

6.1.1 如何实时监控文件操作状态

在进行大量或长时间的文件操作时,实时监控文件操作状态能够给用户提供即时反馈,改善用户体验。C#中可以通过委托(Delegate)和事件(Event)模式实现状态监控。以下是一个监控文件复制状态的例子:

public class FileCopyMonitor
{
    public event EventHandler<FileCopyEventArgs> CopyProgress;

    protected virtual void OnCopyProgress(FileCopyEventArgs e)
    {
        CopyProgress?.Invoke(this, e);
    }

    public void CopyFile(string source, string destination)
    {
        using (FileStream sourceStream = new FileStream(source, FileMode.Open, FileAccess.Read))
        using (FileStream destinationStream = new FileStream(destination, FileMode.Create, FileAccess.Write))
        {
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                destinationStream.Write(buffer, 0, bytesRead);
                OnCopyProgress(new FileCopyEventArgs(bytesRead, sourceStream.Length));
            }
        }
    }
}

public class FileCopyEventArgs : EventArgs
{
    public long BytesWritten { get; }
    public long TotalBytes { get; }

    public FileCopyEventArgs(long bytesWritten, long totalBytes)
    {
        BytesWritten = bytesWritten;
        TotalBytes = totalBytes;
    }
}

在UI层,可以订阅并处理 CopyProgress 事件来更新进度信息。

6.1.2 进度条的设计和实现

进度条是向用户展示操作进度的直观方式。在.NET中,我们可以使用WPF或WinForms来创建进度条。WPF中可以使用 ProgressBar 控件,WinForms中同样有 ProgressBar 控件。下面是一个WPF进度条示例:

<Window x:Class="YourNamespace.ProgressBarWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="File Copy Progress" Height="150" Width="300">
    <Grid>
        <ProgressBar Minimum="0" Maximum="100" Value="{Binding ProgressValue}" />
    </Grid>
</Window>

对应的后端代码逻辑:

public partial class ProgressBarWindow : Window
{
    public ProgressBarWindow()
    {
        InitializeComponent();
        DataContext = this;
        new FileCopyMonitor().CopyFile("source.txt", "destination.txt");
    }

    public int ProgressValue { get; private set; }

    private void UpdateProgress(long bytesWritten, long totalBytes)
    {
        ProgressValue = (int)(100 * bytesWritten / totalBytes);
        Dispatcher.Invoke(() => { });
    }
}

在实际的应用中, UpdateProgress 方法会在适当的时候被调用来更新进度条的值,这可能是在主线程或者使用 Dispatcher

6.2 配置和设置选项

6.2.1 设计可配置的程序参数

设计可配置的程序参数可以让应用程序更加灵活。通过读取外部的配置文件,可以避免修改源代码即可改变程序行为。一个常见的做法是使用 app.config web.config 文件来存储配置信息。

<configuration>
    <appSettings>
        <add key="BufferSize" value="1024" />
        <add key="LoggingLevel" value="Verbose" />
        <!-- More settings -->
    </appSettings>
</configuration>

程序中可以通过 ConfigurationManager 类读取这些参数。

6.2.2 读取和应用配置文件

下面的代码示例展示了如何在应用程序启动时读取和应用这些配置:

using System.Configuration;

public class ConfigReader
{
    public static void Initialize()
    {
        // Initialize application settings
        string bufferSize = ConfigurationManager.AppSettings["BufferSize"];
        int bufferSizeValue = int.Parse(bufferSize);

        // Initialize other settings
        string loggingLevel = ConfigurationManager.AppSettings["LoggingLevel"];
        // Apply loggingLevel configuration to the logger object

        // Log the initialization process
        // ...
    }
}

在这个例子中,我们读取了缓冲区大小和日志记录级别。然后,程序可以根据这些设置执行相应的初始化操作。通过这种方式,程序的配置变得易于维护和修改。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在软件开发中,批量处理文件是一项常见需求。本文介绍了一个C#编写的文件批量拷贝和剪切工具,该工具利用C#的系统级I/O功能以及.NET框架提供的API,实现文件的高效操作。文章深入探讨了FileStream、Path类、File与Directory类的使用,以及如何通过多线程和异步操作提升性能,还涉及了异常处理和用户界面设计等关键要素。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐