使用C# Encoding.CreateTranscodingStream转码未生成预期编码文件的问题
EBCDIC转大端Unicode未生成预期BOM的问题排查
问题代码
using (Stream inputFileStream = File.OpenRead("C:\\Users\\User\\Downloads\\test.txt")) { using (Stream transcodingStream = Encoding.CreateTranscodingStream(inputFileStream, Encoding.GetEncoding(500), new UnicodeEncoding(bigEndian: true, byteOrderMark: true))) { using (Stream outputStream = File.OpenWrite("C:\\Users\\User\\Downloads\\test.txt")) { await transcodingStream.CopyToAsync(outputStream, cancellationToken); } } }
转码前后字节信息
- 原EBCDIC(代码页500)文件前16字节:
F5 F1 F1 F0 F2 C2 D4 E6 40 40 40 40 40 40 F1 F1 = 51102BMW 11 - 预期转码后开头:
FF FE - 实际转码后开头:
00 35 00 31 00 31 00 30 00 32 00 42 00 4D 00 57 = �5�1�1�0�2�B�M�W
错误原因及解决方法
核心错误点
CreateTranscodingStream参数顺序与用法完全颠倒Encoding.CreateTranscodingStream的作用是包装底层流,将写入该流的输入编码字节转换为输出编码字节后写入底层流。你当前的写法是把EBCDIC输入流作为底层流,试图从中读取转码后的数据,完全搞反了转码方向,自然不会触发目标编码的BOM写入逻辑。输入输出复用同一个文件
同时用File.OpenRead和File.OpenWrite操作同一个文件,会导致文件内容混乱(比如读取到被部分覆盖的内容),甚至触发文件访问冲突,这是绝对禁止的操作。
正确实现方式
方式一:使用StreamReader+StreamWriter(直观易读)
// 输入输出文件必须分开 using var inputStream = File.OpenRead(@"C:\Users\User\Downloads\test_ebcdic.txt"); using var ebcdicReader = new StreamReader(inputStream, Encoding.GetEncoding(500)); using var outputStream = File.OpenWrite(@"C:\Users\User\Downloads\test_unicode.txt"); // 指定大端Unicode并启用BOM using var unicodeWriter = new StreamWriter(outputStream, new UnicodeEncoding(bigEndian: true, byteOrderMark: true)); await unicodeWriter.WriteAsync(await ebcdicReader.ReadToEndAsync(cancellationToken));
方式二:正确使用CreateTranscodingStream
using var inputStream = File.OpenRead(@"C:\Users\User\Downloads\test_ebcdic.txt"); using var outputStream = File.OpenWrite(@"C:\Users\User\Downloads\test_unicode.txt"); // 参数顺序:底层输出流、源编码(EBCDIC)、目标编码(带BOM的大端Unicode) using var transcodingStream = Encoding.CreateTranscodingStream( outputStream, Encoding.GetEncoding(500), new UnicodeEncoding(bigEndian: true, byteOrderMark: true), leaveOpen: false); await inputStream.CopyToAsync(transcodingStream, cancellationToken); // 强制刷新确保BOM和所有内容写入文件 await transcodingStream.FlushAsync(cancellationToken);
说明
- 两种方式都会自动写入大端Unicode的BOM(
FF FE),符合预期。 - 必须保证输入输出文件路径不同,避免文件访问冲突和数据损坏。
内容的提问来源于stack exchange,提问作者Vocaloidas
相关产品推荐
相关产品推荐

