【问题标题】:Convert ANSI (Windows 1252) to UTF8 in C#在 C# 中将 ANSI (Windows 1252) 转换为 UTF8
【发布时间】:2011-05-22 04:00:33
【问题描述】:

在 Stack Overflow 之前,我已经以一种迂回的方式asked this before,并且希望这次能做到这一点。如何在保留特殊字符的同时将 ANSI(代码页 1252)转换为 UTF-8? (我知道 UTF-8 支持比 ANSI 更大的字符集,但如果我可以保留 ANSI 支持的所有 UTF-8 字符并将其余字符替换为 ? 或其他内容,则可以)

我为什么要转换 ANSI → UTF-8

我基本上是在编写一个程序,将 vCard 文件 (VCF) 拆分为单独的文件,每个文件都包含一个联系人。我注意到诺基亚和索尼爱立信手机将备份 VCF 文件保存为 UTF-8(无 BOM),但 Android 将其保存为 ANSI(1252)。天知道其他手机以什么格式保存它们!

所以我的问题是

  1. vCard 文件的字符编码没有行业标准吗?
  2. 哪个更容易解决我的问题?将 ANSI 转换为 UTF8(和/或反之)或尝试检测输入文件的编码并通知用户?

tl;博士 需要知道如何在保留所有特殊字符的同时将字符编码从 (ANSI / UTF8) 转换为 (UTF8 / ANSI)。

【问题讨论】:

    标签: c# .net string character-encoding special-characters


    【解决方案1】:

    我在将大量古代文本文件处理成格式良好的 PDF 时发现了这个问题。所有文件都没有 BOM,并且最旧的文件包含导致错误解码为 UTF8 的 Codepage 1252 代码点。这仅在某些时候发生,UTF8 大部分时间都有效。此外,最新的文本数据确实包含 UTF8 代码点,所以好坏参半。

    因此,我还设置了“检测输入文件具有哪种编码”,在阅读了How to detect the character encoding of a text file?How to determine the encoding of text? 之后得出的结论是,这充其量是很难的。 p>

    但是,我在 cmets 中找到了 The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets,阅读它,发现了这个 gem:

    UTF-8 有一个简洁的副作用,即 UTF-8 中的英文文本看起来与 ASCII 中的完全相同,因此美国人甚至不会注意到任何错误。只有世界其他地方必须跳过铁环。具体来说,Hello,它是 U+0048 U+0065 U+006C U+006C U+006F,将存储为 48 65 6C 6C 6F,看哪!与存储在 ASCII、ANSI 和地球上每个 OEM 字符集中的相同。

    整篇文章很短,值得一读。

    所以,我用下面的代码解决了我的问题。由于只有少量的文本数据包含困难的字符代码点,我不介意异常处理的性能开销,特别是因为它只需要运行一次。也许有更聪明的方法可以避免try/catch,但我没有费心去设计一个。

        public static string ReadAllTextFromFile(string file)
        {
            const int WindowsCodepage1252 = 1252;
    
            string text;
    
            try
            {
                var utf8Encoding = Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); 
                text = File.ReadAllText(file, utf8Encoding);
            }
            catch (DecoderFallbackException dfe)//then text is not entirely valid UTF8, contains Codepage 1252 characters that can't be correctly decoded to UTF8
            {
                var codepage1252Encoding = Encoding.GetEncoding(WindowsCodepage1252, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
                text = File.ReadAllText(file, codepage1252Encoding);
            }
    
            return text;
        }
    

    还值得注意的是,StreamReader 类具有采用特定 Encoding 对象的构造函数,正如我所展示的,您可以调整 EncoderFallback/DecoderFallback 行为以满足您的需求。因此,如果您需要 StreamReader 或 StreamWriter 进行更细粒度的工作,仍然可以使用这种方法。

    【讨论】:

      【解决方案2】:

      我使用它来将文件编码转换为 UTF-8

      public static void ConvertFileEncoding(String sourcePath, String destPath)
              {
                  // If the destination's parent doesn't exist, create it.
                  String parent = Path.GetDirectoryName(Path.GetFullPath(destPath));
                  if (!Directory.Exists(parent))
                  {
                      Directory.CreateDirectory(parent);
                  }
      
                  // Convert the file.
                  String tempName = null;
                  try
                  {
                      tempName = Path.GetTempFileName();
                      using (StreamReader sr = new StreamReader(sourcePath))
                      {
                          using (StreamWriter sw = new StreamWriter(tempName, false, Encoding.UTF8))
                          {
                              int charsRead;
                              char[] buffer = new char[128 * 1024];
                              while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0)
                              {
                                  sw.Write(buffer, 0, charsRead);
                              }
                          }
                      }
                      File.Delete(destPath);
                      File.Move(tempName, destPath);
                  }
                  finally
                  {
                      File.Delete(tempName);
                  }
              }
      

      【讨论】:

        【解决方案3】:

        我是这样做的:

            private static void ConvertAnsiToUTF8(string inputFilePath, string outputFilePath)
            {
                string fileContent = File.ReadAllText(inputFilePath, Encoding.Default);
                File.WriteAllText(outputFilePath, fileContent, Encoding.UTF8);
            }
        

        【讨论】:

          【解决方案4】:
          1. vCard 文件的字符编码没有行业标准吗?
          2. 哪个更容易解决我的问题?将 ANSI 转换为 UTF8(和/或反之)或尝试检测输入文件的编码并通知用户?

          我是如何解决这个问题的: 我有 vCard 文件 (*.vcf) - 一个文件中有 200 个联系人,使用俄语... 我用 vCardOrganizer 2.1 程序打开它,然后将其拆分为 200....而我所看到的 - 带有杂乱符号的联系人,只有我能读懂的数字:-) ...

          步骤:(执行此步骤时请耐心等待,有时需要时间) 使用“记事本”打开 vCard 文件(我的文件大小为 3mb) 然后从菜单-文件-另存为..在打开的窗口中选择文件名,不要忘记放 .vcf 和编码 - ANSI 或 UTF-8 ......最后点击保存.. 我将 filename.vcf (UTF-8) 转换为 filename.vcf (ANSI) - 没有丢失和完美可读的俄语......如果你有任务写:yoshidakatana@gmail.com

          祝你好运!!!

          【讨论】:

          • 问题所有者正在开发(编程)应用程序。他不打算使用 3rdparty 应用程序,而且很可能一次都不会这样做。问题是关于在 C# 中执行此操作。请正确阅读问题
          【解决方案5】:

          这是我在 C# 中使用的(我一直在使用它从 Windows-1252 转换为 UTF8)

              public static String readFileAsUtf8(string fileName)
              {
                  Encoding encoding = Encoding.Default;
                  String original = String.Empty;
          
                  using (StreamReader sr = new StreamReader(fileName, Encoding.Default))
                  {
                      original = sr.ReadToEnd();
                      encoding = sr.CurrentEncoding;
                      sr.Close();
                  }
          
                  if (encoding == Encoding.UTF8)
                      return original;
          
                  byte[] encBytes = encoding.GetBytes(original);
                  byte[] utf8Bytes = Encoding.Convert(encoding, Encoding.UTF8, encBytes);
                  return Encoding.UTF8.GetString(utf8Bytes);
              }
          

          【讨论】:

          • 谢谢! MS Word 的 Save as Filtered Html 是使用 Windows-1252 保存的,这导致我正在编写的工具中出现智能引号问题。您的代码解决了这个问题。
          【解决方案6】:

          按照第 3.4 章中the spec 的要求,VCF 以 utf-8 编码。你需要认真对待这一点,如果不是一成不变的,这种格式将毫无用处。如果您看到某些 Android 应用程序修改了重音字符,那么请假设这是该应用程序中的错误。或者更有可能的是,它从其他地方得到了错误的信息。您尝试更正编码会导致 更多 问题,因为您的卡版本永远不会与原始版本匹配。

          您使用 Encoding.GetEncoding(1252).GetString() 将 1252 转换为 utf-8,传入 byte[]。永远不要尝试编写读取字符串并将其转换为 byte[] 的代码,这样您就可以使用转换方法,这只会使编码问题很多变得更糟。换句话说,您需要使用 FileStream 而不是 StreamReader 来读取文件。但同样,避免解决其他人的问题。

          【讨论】:

          • 感谢您指出标准。当我说 Android 将联系人保存在 ANSI 中时,我并不是指任何第三部分应用程序。 Android 自己的“联系人”功能以 ANSI 格式导出 VCF!我们现在怎么办?
          • 在.net core中,编码1252不存在,需要安装,参考:stackoverflow.com/questions/37870084/…
          【解决方案7】:

          您不应从一种编码转换为另一种编码。您必须使用创建文件时使用的编码来读取每个文件,否则您将丢失信息。

          一旦您使用正确的编码读取文件,您就可以将内容作为 Unicode 字符串,然后您可以使用任何您喜欢的编码保存它。

          如果您需要检测编码,可以将文件读取为字节,然后查找特定于任一编码的字符代码。如果文件不包含特殊字符,则任何一种编码都将起作用,因为字符 32..127 对于两种编码都是相同的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-16
            • 2021-07-12
            • 2017-11-29
            • 1970-01-01
            • 2016-02-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多