【发布时间】:2020-10-07 23:12:51
【问题描述】:
我正在构建一个应用程序,它从电子邮件服务器下载纯文本格式的 csv 文件并将其写入本地文件系统。我正在使用 .NET Core 3.1 在 C# 中开发此应用程序。
问题是我不知道收到的文件的编码是什么,所以我决定使用StreamReader 类将我从电子邮件下载的字节转换为字符串。
这里是代码
foreach (var data in loadedData)
{
if (IsValidData(data))
{
logger.Info($"Writing data from: {data.FileName}");
using var stream = new MemoryStream(data.FileContent);
using var reader = new StreamReader(stream, true);
var csvData = new CSVData
{
FileName = data.FileName,
FileContent = reader.ReadToEnd(),
};
dataWriter.WriteData(csvData);
logger.Info($"Writing data from: {data.FileName} was successfully written");
}
else
{
logger.Warn($"Invalid format: {data.FileName}");
}
}
并将数据写入我正在使用的实际文件中:
public void WriteData(CSVData data)
{
logger.Debug($"Writing received file: {data.FileName}");
var outputDir = config.GetReceivedFilesPath();
string fileName = this.GetOutputPath(data.FileName, outputDir);
Directory.CreateDirectory(outputDir);
using var writer = new StreamWriter(fileName, false, Encoding.UTF8);
writer.Write(data.FileContent);
logger.Debug($"The received data was successfully written to: {data.FileName}");
}
问题是我收到的一些文件是用 UTF-16 编码的(我相信这是正在使用的编码,因为每个字符后面都有一个 \0),但 StreamReader 正在解释此文件以 UTF-8 编码,因为 reader.CurrentEncoding 属性返回 UTF-8。
最终结果是,我的应用程序没有将文件输出为 UTF-8,而是将它们输出为 UTF-16,即使我明确添加了 UTF-8 作为输出值。
我做错了什么?
【问题讨论】:
-
如果 BOM 存在,它只能检测 UTF-16。
data.FileContent的前 4 个字节是什么? -
文档声明
StreamReaderalways 默认为 UTF-8,除非另有说明,因此您必须自己进行检测,然后将正确的Encoding传递给读者的构造函数。 -
首先需要找到传入文件的编码。前 4 个字节中存在的组合可以说明存在什么编码。那里有很多例子。 StreamReader 未检测到正确的编码。如果没有提及,它只使用默认值。知道编码后,您可以在 StreamReader 中使用它。
-
@EtiennedeMartel:“文档说明 StreamReader 始终默认为 UTF-8” - 该文档具有误导性。是的,使用的默认编码是 UTF8。但是
StreamReader将遵循 UTF16 或 UTF8 BOM 指定的编码(如果找到),除非使用带有detectEncodingFromByteOrderMarks参数的构造函数,并且为该参数的值传递了false。 -
“StreamReader 正在将此文件解释为 UTF-8 编码”——
StreamReader正确解码 UTF16 输入的唯一方法是,如果 a)输入包括一个 UTF16 BOM 作为前两个字节,或者 b) 您通过将Encoding.Unicode传递给构造函数来明确告诉它。如果这些都不适用,您将得到不正确的结果。改变它的唯一方法是修复您的代码,以便为您的代码正确形成输入(即具有 BOM),或者您在创建StreamReader时明确说明要使用哪种编码,请参阅副本以获取更多详细信息.