StreamRead和StreamWriter的使用

本文介绍了使用C#进行文件读写的两种基本方法:通过StreamReader读取文本文件内容,并逐行显示;通过StreamWriter向文本文件中写入或追加内容。示例代码展示了如何打开指定路径的文件,读取所有行并打印,以及如何向文件中追加新的文本。

 

1  //StreamRead来读取一个文件
2             using (StreamReader sr = new StreamReader(@"C:\Users\enle\Desktop\新建文本文档.txt", Encoding.Default))
3             {
4                 while (!sr.EndOfStream)//循环的去读文件
5                 {
6                     Console.WriteLine(sr.ReadLine());
7                 }
8             }
9             Console.ReadKey();

 StreamWriter写入一个文本文件

  //StreamWriter写入一个文本文件
            using (StreamWriter strw = new StreamWriter(@"C:\Users\wbrm\Desktop\新建.txt",true  ))//true 表示追加
            {
                //strw.Write("别再能吃苦的年纪选择安逸");
                strw.Write("看我有某有把你覆盖掉");
            }
            Console.WriteLine("写入成功");
            Console.ReadKey();

 

转载于:https://www.cnblogs.com/enduo/p/7787893.html

<think>我们正在讨论在同一个FileStream上同时使用StreamWriterStreamReader进行读写操作的限制问题。 根据引用[1][4],我们知道StreamWriterStreamReader是操作字符的,而FileStream是操作字节的。当我们同时使用StreamWriterStreamReader包装同一个FileStream时,需要注意它们共享同一个流位置指针,并且各自拥有缓冲区,这可能会导致问题。 主要限制: 1. 位置指针冲突:StreamWriter写入数据后,流的位置指针会移动。如果此时使用StreamReader读取,需要先调整指针位置,否则可能读取不到刚刚写入的数据(因为写入后指针在末尾)。 2. 缓冲区问题:StreamWriterStreamReader各自有缓冲区。当我们通过StreamWriter写入数据时,数据可能还在缓冲区中,没有立即写入底层流,这时用StreamReader读取可能读不到最新数据。 3. 编码一致性:StreamWriterStreamReader使用相同的编码方式,但如果在同一个流上分别创建,需要确保编码一致,否则读取时会出现乱码。 解决方案: 1. 在切换读写操作时,手动刷新缓冲区并调整流位置指针。 2. 避免同时使用两个对象,可以在写入完成后关闭StreamWriter(但不要关闭底层流),然后再用StreamReader读取;或者使用同一个Stream对象(如StreamWriter)写入,然后使用同一个流的StreamReader读取,但要注意指针位置。 然而,引用[2]提到:当我们使用StreamReader(Stream stream)或StreamWriter(Stream stream)构造函数时,它们不会关闭传入的流。因此,我们可以利用这个特性。 但是,同时使用两个对象(一个StreamWriter一个StreamReader)包装同一个FileStream并不是推荐的做法,因为容易出错。更好的做法是: - 写入完成后,调用StreamWriter的Flush()方法,确保数据写入底层流。 - 然后,将流的指针移回开始位置(如果需要读取整个文件)或者移动到需要读取的位置。 - 再使用StreamReader读取。 示例代码: ```csharp using (FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)) { // 创建StreamWriter,注意使用using并设置leaveOpen参数为true,这样在using块结束时不会关闭底层流 using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8, 1024, leaveOpen: true)) { writer.WriteLine("第一行"); writer.WriteLine("第二行"); // 必须刷新,确保数据写入底层流 writer.Flush(); } // 此时,流的位置在写入结束的位置,我们需要将指针移回开始位置才能读取 fs.Seek(0, SeekOrigin.Begin); // 创建StreamReader using (StreamReader reader = new StreamReader(fs, Encoding.UTF8, true, 1024, leaveOpen: true)) { string content = reader.ReadToEnd(); Console.WriteLine(content); } } ``` 注意:上面的代码中,我们在使用StreamWriterStreamReader时都设置了`leaveOpen:true`,这样在using块结束时不会关闭底层的FileStream。然后我们通过`fs.Seek`将指针移回开始位置。 但是,如果我们希望在同一段代码中交替读写(比如写一行,然后读全部),则需要注意每次写入后刷新并移动指针。 然而,更常见的做法是:写入完成后关闭流,然后再用读取模式打开。或者,如果文件不大,可以写入完成后关闭StreamWriter(但保持FileStream打开),然后移动指针再读取。 不推荐在同一流上同时使用StreamWriterStreamReader进行交替读写的原因: - 指针管理复杂:每次读写后都需要调整指针位置。 - 缓冲区同步困难:写入的数据可能还在StreamWriter的缓冲区中,没有到底层流,此时读取会失败。 - 容易出错:比如忘记刷新、忘记移动指针等。 因此,结论是:技术上可行,但需要谨慎操作。通常,我们更倾向于分别进行写操作读操作,中间刷新并调整指针。 引用[4]指出,StreamWriterStreamReader可以封装任何继承自Stream的流,包括FileStream,但要注意上述问题。 所以,如果确实需要在同一个流上同时读写,建议: 1. 每次写入后调用Flush()。 2. 在读写操作切换时,使用FileStream的Seek方法调整位置。 3. 注意编码一致。 但是,对于同一个文件流,同时进行读写操作(尤其是多线程)还需要考虑线程安全,通常需要加锁。 总结:FileStream本身支持读写(通过FileAccess.ReadWrite),但上层的字符流包装器(StreamReader/StreamWriter)的使用需要额外注意指针缓冲区。</think>### C# 中 FileStream 同时使用 StreamWriter StreamReader 的限制分析 在 C# 中使用 `FileStream` 同时配合 `StreamWriter` `StreamReader` 进行读写操作时,存在几个关键限制需要特别注意: #### 核心限制原因 1. **位置指针冲突** `FileStream` 使用单一位置指针管理读写位置。当通过 `StreamWriter` 写入数据后,指针会移动到文件末尾。如果此时直接使用 `StreamReader` 读取,指针仍在末尾位置,导致读取不到数据(返回空内容)[^1][^3]。 2. **缓冲区不一致性** `StreamWriter` 使用独立的字符缓冲区,写入操作不会立即刷新到基础流。若未显式调用 `Flush()`,`StreamReader` 可能无法读取到最新写入的数据[^1][^4]。 3. **编码处理差异** `StreamWriter` `StreamReader` 默认使用 UTF-8 编码,但如果创建时指定了不同编码,会导致读写数据不一致[^4]。 #### 解决方案(正确使用模式) ```csharp using (FileStream fs = new FileStream("data.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)) { // ===== 写入操作 ===== using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8, 1024, leaveOpen: true)) { writer.WriteLine("新写入的第一行"); writer.WriteLine("包含中文的内容"); writer.Flush(); // 关键:强制刷新缓冲区 } // ===== 读取操作 ===== fs.Seek(0, SeekOrigin.Begin); // 关键:重置指针位置 using (StreamReader reader = new StreamReader(fs, Encoding.UTF8, true, 1024, leaveOpen: true)) { string content = reader.ReadToEnd(); Console.WriteLine("读取内容:\n" + content); } } ``` #### 关键技术要点 1. **指针位置管理** - 写入后必须重置指针:`fs.Seek(0, SeekOrigin.Begin)` - 随机访问时需精确计算位置:`fs.Position = targetOffset` 2. **缓冲区控制** - 显式调用 `Flush()` 确保数据写入物理文件 - 设置缓冲区大小(如 1024)平衡性能与实时性 3. **流生命周期控制** ```csharp new StreamWriter(fs, ..., leaveOpen: true) // 关键参数 ``` 此设置确保关闭 `StreamWriter`/`StreamReader` 时不会关闭底层 `FileStream`[^2][^4] 4. **编码一致性** 始终显式指定相同编码: ```csharp Encoding.UTF8 // 推荐统一使用UTF-8 ``` #### 最佳实践建议 1. **避免嵌套读写** 推荐先完成所有写入操作,刷新缓冲区后再进行读取,而非交替读写。 2. **大文件处理策略** ```csharp // 记录写入结束位置 long endPosition = fs.Position; // 回到读取起始点 fs.Seek(startPosition, SeekOrigin.Begin); // 分段读取 char[] buffer = new char[4096]; int bytesRead; while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0) { // 处理数据 } ``` 3. **异常处理** ```csharp try { // 读写操作 } catch (IOException ex) { // 处理文件系统错误 } catch (EncoderFallbackException) { // 处理编码错误 } finally { fs.Flush(); // 确保数据持久化 } ``` #### 替代方案 对于简单场景,推荐使用更简洁的 API: ```csharp // 写入文件 File.WriteAllText("data.txt", "内容", Encoding.UTF8); // 读取文件 string content = File.ReadAllText("data.txt", Encoding.UTF8); ``` > 此方案避免了指针管理问题,但牺牲了流式处理的灵活性[^3]。 --- ### 相关问题 1. **如何实现多线程环境下对同一个文件的并发读写?** (探讨 `FileShare.ReadWrite` `Mutex` 同步机制的应用场景) 2. `FileStream` 的异步读写(`BeginRead`/`BeginWrite`)相比同步方式有哪些性能优势? (分析 I/O 完成端口与线程池的协作机制) 3. 当文件被其他进程锁定时,如何实现等待重试机制? (实现基于指数退避算法的文件访问策略) 4. 为什么 UTF-8 编码需要区分 BOM 无 BOM 版本? (解析字节顺序标记对跨平台文本处理的兼容性影响) 5. 如何优化 `FileStream` 在大文件处理中的内存使用效率? (探索滑动窗口读取与内存映射文件的性能对比)[^1][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值