如何使用FileStream向文本文件的指定位置写入内容?
问题描述
我需要写入符合以下结构的文本文件:
目前我尝试使用Seek()和Write()方法实现该需求,但每次写入新数据时原有内容都会被覆盖,最终文件中仅保留一行内容。
我使用的代码如下:
private async void CreacionArchivoBCD(ArchivoPerfil contenidoPerfil, string nombreFinalBCD, bool checkPrevia) { var result = await ensayoDataProvider.ObtenerUexCapturador(checkPrevia, contenidoPerfil, codensSeleccionado.Id); var cant = System.Text.Encoding.UTF8.GetBytes(Convert.ToString(result.Count())); ////TextWriter archivoExportar = new StreamWriter(nombreFinalBCD); ////archivoExportar.Close(); var file = new FileStream(nombreFinalBCD, FileMode.OpenOrCreate, FileAccess.Write); file.Seek(1, SeekOrigin.Begin); file.Write(cant, 0, cant.Length); byte[] newline = Encoding.ASCII.GetBytes(Environment.NewLine); file.Write(newline, 0, newline.Length); int nroMedAux = 0; long rutaAux = 0; var cont = 0; var bandera = 0; //var posicion = 0; foreach (var item in result) { var primerByte = System.Text.Encoding.UTF8.GetBytes("00"); file.Seek(0, SeekOrigin.Begin); file.Write(primerByte, 0, primerByte.Length); if (bandera == 0) { nroMedAux = item.IdMed; rutaAux = item.Ruta; bandera = 1; } var tipo = item.GetType(); if (nroMedAux != item.IdMed || rutaAux != item.Ruta) { nroMedAux = item.IdMed; rutaAux = item.Ruta; file.Write(newline, 0, newline.Length); } foreach (var pi in tipo.GetProperties()) { var propName = pi.Name; var propValue = pi.GetValue(item, null)?.ToString(); var propValueAux = propName == "Campo" ? item.GetType().GetProperty("Valor").GetValue(item, null) : propValue; if (propName == "IdMed" || propName == "Valor") { continue; } //TODO: buscar posicion y ancho por nombre campo var posicion = BuscarPosicion(propName, propValue, contenidoPerfil); //var ancho = BuscarAncho(propName, contenidoPerfil); Debug.WriteLine(propName); Debug.WriteLine(propValueAux); Debug.WriteLine(posicion); if (posicion == -1) { continue; } var lacadena = propValue; var lacadenAux = propName == "Campo" ? propValueAux : propValue; var cadena = System.Text.Encoding.UTF8.GetBytes(lacadenAux.ToString()); file.Seek(posicion, SeekOrigin.Begin); file.Write(cadena, 0, cadena.Length); } } file.Close(); }
问题原因&修复方案
核心问题
内容覆盖的问题主要来自两处错误用法:
- 循环内每次都执行
file.Seek(0, SeekOrigin.Begin),强制把写入位置跳转到文件开头,后续写入自然会覆盖开头的原有内容 - 所有字段写入都直接用
Seek(posicion, SeekOrigin.Begin),如果posicion是字段在当前行的相对偏移,直接从全局文件开头计算位置,就会反复覆盖前面行的内容,最终只会保留最后一行的写入结果
修复要点
- 移除循环开头的
Seek(0, SeekOrigin.Begin)调用,避免每次循环都覆盖文件头部内容 - 按行管理偏移:每次新增行后记录当前行的起始偏移,该行内所有字段的写入位置都按当前行起始偏移+字段相对偏移计算,不要直接使用全局文件开头的位置
- 用
using包裹FileStream,自动处理资源释放,避免异常场景下文件流泄漏 - 如果第一行需要写入总条数,建议优先计算好总条数再写入,避免后续行写入覆盖头部统计值
修复后参考代码
private async void CreacionArchivoBCD(ArchivoPerfil contenidoPerfil, string nombreFinalBCD, bool checkPrevia) { var result = await ensayoDataProvider.ObtenerUexCapturador(checkPrevia, contenidoPerfil, codensSeleccionado.Id); // 先获取总条数,后续统一写入 string countStr = result.Count().ToString(); byte[] newline = Encoding.UTF8.GetBytes(Environment.NewLine); // using自动释放流,不需要手动调用Close using var file = new FileStream(nombreFinalBCD, FileMode.Create, FileAccess.Write); // 写入第一行总条数 byte[] countBytes = Encoding.UTF8.GetBytes(countStr); file.Write(countBytes, 0, countBytes.Length); file.Write(newline, 0, newline.Length); // 记录当前行的起始偏移 long currentLineStart = file.Position; int nroMedAux = 0; long rutaAux = 0; var bandera = 0; foreach (var item in result) { // 首行写入00标识,不要跳回全局文件开头 if (bandera == 0) { var primerByte = Encoding.UTF8.GetBytes("00"); file.Seek(currentLineStart, SeekOrigin.Begin); file.Write(primerByte, 0, primerByte.Length); nroMedAux = item.IdMed; rutaAux = item.Ruta; bandera = 1; } var tipo = item.GetType(); if (nroMedAux != item.IdMed || rutaAux != item.Ruta) { nroMedAux = item.IdMed; rutaAux = item.Ruta; // 写入换行 file.Write(newline, 0, newline.Length); // 更新新行的起始偏移 currentLineStart = file.Position; } foreach (var pi in tipo.GetProperties()) { var propName = pi.Name; var propValue = pi.GetValue(item, null)?.ToString(); var propValueAux = propName == "Campo" ? item.GetType().GetProperty("Valor").GetValue(item, null) : propValue; if (propName == "IdMed" || propName == "Valor") { continue; } var posicion = BuscarPosicion(propName, propValue, contenidoPerfil); if (posicion == -1) { continue; } var lacadenAux = propName == "Campo" ? propValueAux : propValue; var cadena = Encoding.UTF8.GetBytes(lacadenAux.ToString()); // 写入位置 = 当前行开头 + 字段相对偏移 file.Seek(currentLineStart + posicion, SeekOrigin.Begin); file.Write(cadena, 0, cadena.Length); } } }
内容的提问来源于stack exchange,提问作者LaraYs
相关产品推荐
相关产品推荐

