Stream.Write写入单行文生成UTF-16LE多行文为UTF8问题咨询
问题背景
我们有两个关联的处理流程:
- 流程1:读取存储目录列表的文本文件,将所有行转换为字节数组后保存为dat文件,文件格式为
[文件大小][行数][目录列表],示例格式为[12 0 0 0][1 0 0 0][92 0 97 0 ....] - 流程2:调用REST API流式传输该dat文件,再将其转换回文本文件
异常现象
当原文本文件只有1行时,转换流程生成的文本文件编码为UTF-16 LE;当文件行数大于1时,生成的文本文件编码为UTF-8。
相关代码
完整转换逻辑:
public static void ExtractDatFileData(string datFilePath) { // Open DAT file as stream var info = new FileInfo(datFilePath); var stream = info.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // Write stream into "data.dat" file (creates a copy to read that data from it) var inputFile = Path.Combine(@"C:\demo\data.dat"); using (var file = File.OpenWrite(inputFile)) { stream.CopyTo(file); } const int BUFFER_SIZE = 1024 * 1024; byte[] buffer = new byte[BUFFER_SIZE]; using (Stream input = File.OpenRead(inputFile)) { // Read the size of the file int bytesRead = input.Read(buffer, 0, 4); int fileSize = BitConverter.ToInt32(buffer, 0); // Read data from the DAT file while (input.Position < input.Length) { // --- directories list --- var dirTxtPath = Path.Combine(@"C:\demo\directories.txt"); using (Stream output = File.Create(dirTxtPath)) { int remaining = fileSize; while (remaining > 0 && (bytesRead = input.Read(buffer, 0, Math.Min(remaining, BUFFER_SIZE))) > 0) { output.Write(buffer, 0, bytesRead); remaining -= bytesRead; } } } } }
初步定位的问题代码段:
var dirTxtPath = Path.Combine(@"C:\demo\directories.txt"); using (Stream output = File.Create(dirTxtPath)) { int remaining = fileSize; while (remaining > 0 && (bytesRead = input.Read(buffer, 0, Math.Min(remaining, BUFFER_SIZE))) > 0) { output.Write(buffer, 0, bytesRead); remaining -= bytesRead; } }
看起来
output.Write(buffer, 0, bytesRead);在不同场景下会分别以UTF-16或UTF-8写入,但我们不清楚它的文件编码判定逻辑。
已完成排查
- 确认原始dat文件的写入逻辑对单行和多行文件完全一致,多次核验无误。
- 使用Beyond Compare对比不同场景生成的dat文件,确认数据格式完全相同。
问题根因分析
首先纠正一个认知误区:File.Create返回的是纯字节流FileStream,Write方法本身不会做任何编码转换,完全按照输入的字节原样写入磁盘,不存在自动判定编码的逻辑。你观察到的编码差异本质是文本编辑器自动检测编码的误判,不是代码写入时用了不同编码。
导致误判的核心原因是代码存在格式解析错误:
你的dat文件规范是[4字节文件大小][4字节行数][N字节目录内容],但代码只读取了前4字节的文件大小,没有跳过接下来的4字节行数字段,直接把行数字段+目录内容全部写入到了txt文件中,额外写入的4字节行数字段干扰了编辑器的编码检测逻辑:
- 当原文件只有1行时,行数字段的小端编码为
01 00 00 00,加上后续目录内容的字节刚好全部符合「偶数个字节、每两个字节的第二个字节为0」的UTF-16 LE特征,因此编辑器自动判定为UTF-16 LE编码。 - 当原文件行数大于1时,目录内容中存在多个换行符,对应的字节不符合UTF-16 LE的双字节编码规则,编辑器就会自动判定为UTF-8编码。
你可以用十六进制编辑器直接打开生成的directories.txt验证:单行和多行场景下的字节写入逻辑完全一致,差异仅为文本编辑器的自动识别结果。
修复方案
读取完4字节的文件大小后,先跳过4字节的行数字段(或者按规范读取行数做校验),再读取后续的目录内容写入文本文件即可解决问题。
内容的提问来源于stack exchange,提问作者Dardar
相关产品推荐
相关产品推荐

