当前位置:首页 > 技能相关 > C#与C++ > 正文内容

C#进阶 IO流全面解析

admin1个月前 (01-22)C#与C++860 修订时间:2026-01-22 15:43:34

IO(输入/输出)流是C#中处理文件和数据流的核心机制。让我为你详细介绍C#中的IO流系统。

1. 命名空间

using System.IO;        // 基础IO操作
using System.Text;      // 编码相关

2. 文件基础操作

2.1 System.IO.Path类

System.IO.Path`类是C#中处理文件路径和目录路径的核心工具类。它提供了一系列静态方法,用于跨平台安全地操作路径字符串。

Path类是静态类,不能实例化

Path类中的方法都是平台无关的(Windows/Linux/macOS)

自动处理不同操作系统的路径分隔符

路径分隔符常量

char directorySeparatorChar = Path.DirectorySeparatorChar;   // Windows: '\', Linux: '/'
char altDirectorySeparatorChar = Path.AltDirectorySeparatorChar; // Windows: '/'
char pathSeparator = Path.PathSeparator;                     // 环境变量分隔符:';' (Windows) 或 ':' (Linux)
char volumeSeparatorChar = Path.VolumeSeparatorChar;         // 卷分隔符:':' (Windows)

组合路径 - Path.Combine()

// 安全地组合路径(推荐使用)
string path1 = @"C:\Users";
string path2 = "Documents";
string path3 = "file.txt";

string fullPath1 = Path.Combine(path1, path2, path3);
Console.WriteLine(fullPath1);  // C:\Users\Documents\file.txt
// 自动处理斜杠
string path4 = @"C:\Users\";
string path5 = @"Documents\";
string fullPath2 = Path.Combine(path4, path5);
Console.WriteLine(fullPath2);  // C:\Users\Documents\

获取路径各部分

string fullPath = @"C:\Users\JohnDoe\Documents\report.txt";

// 获取文件名
string fileName = Path.GetFileName(fullPath);
Console.WriteLine($"文件名: {fileName}");  // report.txt

// 获取不带扩展名的文件名
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullPath);
Console.WriteLine($"无扩展名文件名: {fileNameWithoutExtension}");  // report

// 获取扩展名
string extension = Path.GetExtension(fullPath);
Console.WriteLine($"扩展名: {extension}");  // .txt

// 获取目录名
string directoryName = Path.GetDirectoryName(fullPath);
Console.WriteLine($"目录名: {directoryName}");  // C:\Users\JohnDoe\Documents

// 获取根目录
string root = Path.GetPathRoot(fullPath);
Console.WriteLine($"根目录: {root}");  // C:\

// 获取完整路径(规范化路径)
string fullPathWithDot = @"C:\Users\..\Documents\.\report.txt";
string fullNormalizedPath = Path.GetFullPath(fullPathWithDot);
Console.WriteLine($"完整路径: {fullNormalizedPath}");  // C:\Documents\report.txt

路径验证和修改

string path = @"C:\test\file.txt";

// 改变扩展名
string newPath = Path.ChangeExtension(path, ".dat");
Console.WriteLine($"新路径: {newPath}");  // C:\test\file.dat

// 检查是否有扩展名
bool hasExtension = Path.HasExtension(path);
Console.WriteLine($"是否有扩展名: {hasExtension}");  // true

// 获取临时文件/目录
string tempFile = Path.GetTempFileName();  // 创建临时文件并返回路径
Console.WriteLine($"临时文件: {tempFile}");

string tempPath = Path.GetTempPath();
Console.WriteLine($"临时目录: {tempPath}");  // C:\Users\用户名\AppData\Local\Temp\

// 获取当前目录
string currentDirectory = Directory.GetCurrentDirectory();
string absolutePath = Path.GetFullPath("relative/path.txt");

// 用户特殊目录
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

随机文件名生成

// 生成随机文件名
string randomFileName = Path.GetRandomFileName();
Console.WriteLine($"随机文件名: {randomFileName}");  // 如:3b3w8q4e.tmp

// 比较:GetTempFileName vs GetRandomFileName
string tempFile1 = Path.GetTempFileName();  // 实际创建文件
string randomName = Path.GetRandomFileName();  // 只生成名称,不创建文件

平台兼容性处理

public class CrossPlatformPathExample
{
    public void ProcessPaths()
    {
        // 错误方式:硬编码路径分隔符
        string badPath = "C:\\Users\\Test\\file.txt";  // Windows only
        
        // 正确方式:使用Path类
        string goodPath = Path.Combine("C:", "Users", "Test", "file.txt");
        
        // 处理用户输入路径
        string userInput = @"C:/Users/Test/file.txt";  // 用户可能使用正斜杠
        string normalized = Path.GetFullPath(userInput);  // 自动规范化
        
        // 检查非法字符
        char[] invalidChars = Path.GetInvalidFileNameChars();
        string fileName = "my:file?.txt";
        
        foreach (char invalidChar in invalidChars)
        {
            fileName = fileName.Replace(invalidChar, '_');
        }
        Console.WriteLine($"清理后的文件名: {fileName}");  // my_file_.txt
    }
}

**使用建议:**

- 总是使用 `Path.Combine()` 而不是字符串拼接

- 处理用户输入时,使用 `Path.GetFullPath()` 进行规范化

- 使用 `Path.GetInvalidFileNameChars()` 验证文件名

- 注意 `Path.Combine()` 和 `Path.Join()` 的区别

- 在.NET Core 2.1+中,对于简单连接考虑使用 `Path.Join()`

2.2 System.IO.File类(静态方法)

是C#中处理文件的静态工具类,提供了创建、复制、删除、移动和打开文件的静态方法。

文件存在性检查

string filePath = @"C:\data\test.txt";
// 检查文件是否存在
bool exists = File.Exists(filePath);
if (exists)
{
    Console.WriteLine("文件存在");
}

检查文件是否只读

FileAttributes attributes = File.GetAttributes(filePath);
bool isReadOnly = (attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;

文件属性获取

string filePath = @"C:\data\document.txt";

// 获取文件创建时间
DateTime creationTime = File.GetCreationTime(filePath);
Console.WriteLine($"创建时间: {creationTime}");

// 获取最后修改时间
DateTime lastWriteTime = File.GetLastWriteTime(filePath);
Console.WriteLine($"最后修改: {lastWriteTime}");

// 获取最后访问时间
DateTime lastAccessTime = File.GetLastAccessTime(filePath);
Console.WriteLine($"最后访问: {lastAccessTime}");

// 设置文件时间
File.SetCreationTime(filePath, DateTime.Now);
File.SetLastWriteTime(filePath, DateTime.Now);
File.SetLastAccessTime(filePath, DateTime.Now);

创建文件

// 创建空文件(如果存在则覆盖)
string filePath = @"C:\temp\newfile.txt";
File.Create(filePath).Close();  // 记得关闭流

// 使用using确保关闭
using (FileStream fs = File.Create(filePath))
{
    // 可以在这里写入初始数据
    byte[] info = new UTF8Encoding(true).GetBytes("初始内容");
    fs.Write(info, 0, info.Length);
}

// 如果只是创建空文件,更简单的方法
File.WriteAllText(filePath, string.Empty);

删除文件

string filePath = @"C:\temp\todelete.txt";

// 检查并删除
if (File.Exists(filePath))
{
    try
    {
        File.Delete(filePath);
        Console.WriteLine("文件已删除");
    }
    catch (IOException ex)
    {
        Console.WriteLine($"删除失败: {ex.Message}");
    }
}

// 强制删除(即使只读)
public static void ForceDelete(string filePath)
{
    if (File.Exists(filePath))
    {
        // 移除只读属性
        FileAttributes attributes = File.GetAttributes(filePath);
        if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        {
            File.SetAttributes(filePath, attributes & ~FileAttributes.ReadOnly);
        }
        
        File.Delete(filePath);
    }
}

文件复制

string sourceFile = @"C:\data\source.txt";
string destFile = @"C:\backup\source_backup.txt";

// 简单复制(目标已存在则抛出异常)
File.Copy(sourceFile, destFile);

// 覆盖复制
bool overwrite = true;
File.Copy(sourceFile, destFile, overwrite);

// 带进度显示的复制
public static void CopyWithProgress(string source, string destination)
{
    const int bufferSize = 4096;
    
    using (FileStream sourceStream = new FileStream(source, FileMode.Open, FileAccess.Read))
    using (FileStream destStream = new FileStream(destination, FileMode.Create, FileAccess.Write))
    {
        long totalBytes = sourceStream.Length;
        byte[] buffer = new byte[bufferSize];
        int bytesRead;
        long totalRead = 0;
        
        while ((bytesRead = sourceStream.Read(buffer, 0, bufferSize)) > 0)
        {
            destStream.Write(buffer, 0, bytesRead);
            totalRead += bytesRead;
            
            double progress = (double)totalRead / totalBytes * 100;
            Console.WriteLine($"复制进度: {progress:F1}%");
        }
    }
}

移动与重命名

string sourceFile = @"C:\data\oldname.txt";
string destFile = @"C:\data\newname.txt";

// 移动/重命名文件
File.Move(sourceFile, destFile);

// 跨卷移动(自动复制+删除)
string newLocation = @"D:\archive\newname.txt";
File.Move(sourceFile, newLocation);

// 安全的移动操作
public static bool SafeMove(string source, string destination, bool overwrite = true)
{
    try
    {
        if (File.Exists(destination))
        {
            if (overwrite)
            {
                File.Delete(destination);
            }
            else
            {
                return false; // 目标已存在且不允许覆盖
            }
        }
        
        File.Move(source, destination);
        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"移动失败: {ex.Message}");
        return false;
    }
}

读取文本文件

string filePath = @"C:\data\config.txt";

// 读取所有文本
string allText = File.ReadAllText(filePath);
Console.WriteLine($"文件内容:\n{allText}");

// 读取所有行(返回字符串数组)
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
{
    Console.WriteLine($"行: {line}");
}

// 使用指定编码
string utf8Text = File.ReadAllText(filePath, Encoding.UTF8);
string[] utf8Lines = File.ReadAllLines(filePath, Encoding.UTF8);

// 读取指定行数
public static List<string> ReadFirstNLines(string filePath, int n)
{
    List<string> result = new List<string>();
    using (StreamReader reader = new StreamReader(filePath))
    {
        for (int i = 0; i < n; i++)
        {
            string line = reader.ReadLine();
            if (line == null) break;
            result.Add(line);
        }
    }
    return result;
}

写入文本文件

string filePath = @"C:\data\log.txt";

// 写入所有文本(覆盖)
string content = "这是新的文件内容";
File.WriteAllText(filePath, content);

// 写入所有行(覆盖)
string[] lines = { "第一行", "第二行", "第三行" };
File.WriteAllLines(filePath, lines);

// 追加文本
string newLine = "这是追加的内容";
File.AppendAllText(filePath, newLine);

// 追加多行
string[] newLines = { "追加的第一行", "追加的第二行" };
File.AppendAllLines(filePath, newLines);

// 追加多行
var newLines = new List<string>{ "追加的第一行", "追加的第二行" };
File.AppendAllLines(filePath, newLines);

// 带编码的写入
File.WriteAllText(filePath, "UTF-8内容", Encoding.UTF8);
File.WriteAllLines(filePath, lines, Encoding.UTF8);

2.3 FileInfo类(实例方法)

FileInfo fileInfo = new FileInfo("test.txt");

if (fileInfo.Exists)
{
    Console.WriteLine($"文件名: {fileInfo.Name}");
    Console.WriteLine($"文件大小: {fileInfo.Length} 字节");
    Console.WriteLine($"创建时间: {fileInfo.CreationTime}");
    Console.WriteLine($"最后修改时间: {fileInfo.LastWriteTime}");
}

3.目录操作

3.1Directory类

// 创建目录
Directory.CreateDirectory(@"C:\MyFolder\SubFolder");

// 检查目录是否存在
if (Directory.Exists(@"C:\MyFolder"))
{
    // 获取所有文件
    string[] files = Directory.GetFiles(@"C:\MyFolder", "*.txt");
    
    // 获取所有子目录
    string[] directories = Directory.GetDirectories(@"C:\MyFolder");
    
    // 删除目录(true表示递归删除)
    Directory.Delete(@"C:\MyFolder", true);
}

4. 流的基本概念

C#中的流主要分为:

FileStream:文件流

MemoryStream:内存流

NetworkStream:网络流

BufferedStream:缓冲流

4.1 文件读写操作

FileStream(低级文件操作)

// 写入文件
using (FileStream fs = new FileStream("data.bin", FileMode.Create))
{
    byte[] data = Encoding.UTF8.GetBytes("Hello, World!");
    fs.Write(data, 0, data.Length);
}

// 读取文件
using (FileStream fs = new FileStream("data.bin", FileMode.Open))
{
    byte[] buffer = new byte[1024];
    int bytesRead = fs.Read(buffer, 0, buffer.Length);
    string content = Encoding.UTF8.GetString(buffer, 0, bytesRead);
    Console.WriteLine(content);
}

StreamReader/StreamWriter(文本文件)

// 写入文本文件
using (StreamWriter writer = new StreamWriter("text.txt", false, Encoding.UTF8))
{
    writer.WriteLine("第一行");
    writer.WriteLine("第二行");
    writer.Write("不带换行");
}

// 读取文本文件
using (StreamReader reader = new StreamReader("text.txt", Encoding.UTF8))
{
    // 读取全部内容
    string allContent = reader.ReadToEnd();
    
    // 逐行读取
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
    
    // 读取单个字符
    int charCode;
    while ((charCode = reader.Read()) != -1)
    {
        char ch = (char)charCode;
        Console.Write(ch);
    }
}

BinaryReader/BinaryWriter(二进制文件)

// 写入二进制数据
using (BinaryWriter writer = new BinaryWriter(File.Open("data.bin", FileMode.Create)))
{
    writer.Write(12345);          // int
    writer.Write(3.14159);        // double
    writer.Write(true);           // bool
    writer.Write("Hello");        // string
}

// 读取二进制数据
using (BinaryReader reader = new BinaryReader(File.Open("data.bin", FileMode.Open)))
{
    int intValue = reader.ReadInt32();
    double doubleValue = reader.ReadDouble();
    bool boolValue = reader.ReadBoolean();
    string stringValue = reader.ReadString();
    
    Console.WriteLine($"int: {intValue}, double: {doubleValue}, bool: {boolValue}, string: {stringValue}");
}

异步IO操作

// 异步写入
public async Task WriteFileAsync(string path, string content)
{
    using (StreamWriter writer = new StreamWriter(path))
    {
        await writer.WriteAsync(content);
    }
}

// 异步读取
public async Task<string> ReadFileAsync(string path)
{
    using (StreamReader reader = new StreamReader(path))
    {
        return await reader.ReadToEndAsync();
    }
}

// 使用示例
await WriteFileAsync("async.txt", "异步写入的内容");
string result = await ReadFileAsync("async.txt");

内存流(MemoryStream)

// 创建内存流并写入数据
using (MemoryStream ms = new MemoryStream())
{
    byte[] data = Encoding.UTF8.GetBytes("内存流数据");
    ms.Write(data, 0, data.Length);
    
    // 重置位置到开始
    ms.Position = 0;
    
    // 从内存流读取
    byte[] buffer = new byte[ms.Length];
    ms.Read(buffer, 0, buffer.Length);
    string content = Encoding.UTF8.GetString(buffer);
    Console.WriteLine(content);
}

缓冲流(BufferedStream)

// 使用缓冲流提高性能
using (FileStream fs = new FileStream("largefile.bin", FileMode.Create))
using (BufferedStream bs = new BufferedStream(fs))
{
    for (int i = 0; i < 10000; i++)
    {
        byte[] data = BitConverter.GetBytes(i);
        bs.Write(data, 0, data.Length);
    }
}

文件监控(FileSystemWatcher)

public class FileWatcher
{
    public static void WatchDirectory(string path)
    {
        FileSystemWatcher watcher = new FileSystemWatcher
        {
            Path = path,
            NotifyFilter = NotifyFilters.FileName | 
                          NotifyFilters.DirectoryName | 
                          NotifyFilters.LastWrite,
            Filter = "*.txt"
        };
        
        // 事件处理
        watcher.Created += OnFileCreated;
        watcher.Changed += OnFileChanged;
        watcher.Deleted += OnFileDeleted;
        watcher.Renamed += OnFileRenamed;
        
        watcher.EnableRaisingEvents = true;
    }
    
    private static void OnFileCreated(object source, FileSystemEventArgs e)
    {
        Console.WriteLine($"文件创建: {e.FullPath}");
    }
    
    private static void OnFileChanged(object source, FileSystemEventArgs e)
    {
        Console.WriteLine($"文件修改: {e.FullPath}");
    }
    
    private static void OnFileDeleted(object source, FileSystemEventArgs e)
    {
        Console.WriteLine($"文件删除: {e.FullPath}");
    }
    
    private static void OnFileRenamed(object source, RenamedEventArgs e)
    {
        Console.WriteLine($"文件重命名: {e.OldFullPath} -> {e.FullPath}");
    }
}

5.NET Core/.NET 5+ 新特性

// 使用新的文件读写API(.NET Core 2.0+)
string content = await File.ReadAllTextAsync("file.txt");
await File.WriteAllTextAsync("file.txt", "新内容");

// 读取所有行
string[] lines = await File.ReadAllLinesAsync("file.txt");

// 读取所有字节
byte[] bytes = await File.ReadAllBytesAsync("file.bin");
await File.WriteAllBytesAsync("file.bin", bytes);

6. 实用示例

6.1 复制大文件(带进度显示)

public static void CopyFileWithProgress(string source, string destination)
{
    const int bufferSize = 4096; // 4KB缓冲区
    
    using (FileStream sourceStream = new FileStream(source, FileMode.Open))
    using (FileStream destStream = new FileStream(destination, FileMode.Create))
    {
        long totalBytes = sourceStream.Length;
        byte[] buffer = new byte[bufferSize];
        int bytesRead;
        long totalRead = 0;
        
        while ((bytesRead = sourceStream.Read(buffer, 0, bufferSize)) > 0)
        {
            destStream.Write(buffer, 0, bytesRead);
            totalRead += bytesRead;
            
            // 显示进度
            double progress = (double)totalRead / totalBytes * 100;
            Console.WriteLine($"复制进度: {progress:F2}%");
        }
    }
}

6.2 读取CSV文件

public static List<string[]> ReadCsvFile(string filePath)
{
    List<string[]> records = new List<string[]>();
    
    using (StreamReader reader = new StreamReader(filePath))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            // 简单的CSV解析(实际项目中建议使用专用库)
            string[] fields = line.Split(',');
            records.Add(fields);
        }
    }
    
    return records;
}

6.3 最佳实践

1. **始终使用using语句**:确保流资源被正确释放

2. **异常处理**:处理可能发生的IO异常

3. **异步操作**:处理大文件时使用异步方法避免阻塞

4. **路径验证**:验证文件路径的有效性

5. **文件锁定**:注意文件访问权限和锁定问题

try
{
    using (FileStream fs = new FileStream("file.txt", FileMode.Open))
    {
        // 文件操作
    }
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"文件未找到: {ex.Message}");
}
catch (IOException ex)
{
    Console.WriteLine($"IO错误: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine($"访问被拒绝: {ex.Message}");
}

7. 总结

C#的IO流系统提供了丰富而灵活的文件和数据流操作功能。关键点包括:

1. 区分文本流和二进制流的处理方式

2. 使用using语句确保资源释放

3. 异步操作提高应用响应性

4. 根据场景选择合适的流类型

5. 注意异常处理和文件访问权限

掌握这些IO流知识后,你将能够高效地处理各种文件和数据流操作需求。


 您阅读本篇文章共花了: 

免责声明
本站内容均为博客主本人日常使用记录的存档,如侵犯你的权益请联系:lifei@zaiheze.com 546262132@qq.com 沟通删除事宜。本站仅带访问端口形式使用,已杜绝搜索引擎爬取。

扫描二维码推送至手机访问。

版权声明:本文由LIFEI - blog发布,如需转载请注明出处。

本文链接:http://lifeiai.com/index.php?id=463

分享给朋友:

相关文章

C# 第一篇 踏上征程 3年前 (2022-11-14)
C# 第二篇 基础语法3年前 (2022-11-14)
C# 第三篇 流程控制3年前 (2022-11-15)
C# 第五篇 字符串3年前 (2022-11-15)

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。