如何读取上传的 CSV UTF-8 以使用 CsvHelper 进行处理?

How to read uploaded CSV UTF-8 for processing with CsvHelper?

我的 WebAPI 允许用户上传 CSV 文件,然后解析该文件。我使用 CsvHelper 来完成读取 CSV 并将其映射到域 objects.

的繁重工作

但是,我有一位客户的文件是 CSV UTF-8 格式。适用于 "vanilla" (ASCII) CSV 文件的代码在尝试处理 CSV UTF-8 时会抛出异常。

有没有办法导入 CSV UTF-8 数据并将其转换为 ASCII CSV 以便我的代码继续工作?

我当前的代码如下所示:

//In my WebAPI Controller
//fileToProcess is IFormFile
byte[] fileBytes = new byte[fileToProcess.Length];
using(var stream = fileToProcess.OpenReadStream())
{
    await stream.ReadAsync(fileBytes);
    stream.Close();
}

var result = await ProcessFileAsync(fileBytes);

return OK(result);
...

//In a Parsing Class
public async Task<List<Client>> ProcessFileAsync(byte[] fileBytes)
{
    List<Client> result = null;
    var fileText = Encoding.Default.GetString(fileBytes);
    using(var reader = new StringReader(fileText))
    {
       using(var csv = new CsvReader(reader))
       {
          csv.RegisterClassMap<ClientMap>();
          result = csv.GetRecords<T>().ToList();
          await PostProcess(result);
       }
    }

    return result;
 }

问题在于 CSV UTF-8 具有 BOM,因此当 CsvHelper 尝试处理引用第一列的映射时 header

Map(c => c.ClientId).Name("CLIENT ID");

它失败了,因为列名包含 BOM。

所以,我的问题是:

  1. 如何判断传入的文件是 UTF-8 还是 ASCII。
  2. 如何将UTF-8转为ASCII才能正常处理?

注意

我确实尝试了以下方法:

fileBytes = Encoding.Convert(Encoding.UTF8, Encoding.ASCII, fileBytes);

但是,这用 ? 替换了 BOM,这仍然导致 CsvHelper 失败。

通过这样做:

var fileText = Encoding.Default.GetString(fileBytes);
using(var reader = new StringReader(fileText))

...在将其转换为字符串时,您将自己锁定在特定的编码中。 Encoding.Default 可能因平台和 CLR 实现而异。

StreamReader class 旨在从流中读取文本(您可以使用 MemoryStream 环绕原始字节)并且能够为您检测编码如果你愿意的话。试试这个:

using (var stream = new MemoryStream(fileBytes))
using (var reader = new StreamReader(stream))

在您的情况下,您可以通过更改 ProcessFileAsync 以接受流来直接使用传入流。

using (var stream = fileToProcess.OpenReadStream())
{
    var result = await ProcessFileAsync(stream);

    return OK(result);
}
public async Task<List<Client>> ProcessFileAsync(Stream stream)
{
    using (var reader = new StreamReader(stream))
    {
       using (var csv = new CsvReader(reader))
       {
           csv.RegisterClassMap<ClientMap>();
           List<Client> result = csv.GetRecords<Client>().ToList();
           await PostProcess(result);
           return result;
       }
    }
}

只要 BOM 存在,这也将支持 UTF16 编码和 UTF32 编码的文件(以及几乎任何其他可以检测到的文件),因为它会在中看到 U+FEFF 代码点无论它使用哪种编码。