在C#中将ANSI(Windows 1252)转换为UTF8

时间:2010-12-08 11:07:36

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

我之前在Stack Overflow上以圆周方式asked this before,并希望这次正确。如何将ANSI(代码页1252)转换为UTF-8,同时保留特殊字符? (我知道UTF-8支持比ANSI更大的字符集,但是如果我可以保留ANSI支持的所有UTF-8字符并用?或其他东西替换其余的字符集,那就没关系了)

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

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

所以我的问题是

  1. vCard文件的字符编码是否没有行业标准?
  2. 哪个更容易解决我的问题?将ANSI转换为UTF8(和/或反过来)或尝试检测输入文件具有哪种编码并通知用户有关它?
  3. TL;博士 需要知道如何将字符编码从(ANSI / UTF8)转换为(UTF8 / ANSI),同时保留所有特殊字符。

7 个答案:

答案 0 :(得分:13)

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

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

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

答案 1 :(得分:8)

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

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

答案 2 :(得分:7)

这是我在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);
    }

答案 3 :(得分:5)

我是这样做的:

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

答案 4 :(得分:1)

在将大量的古代文本文件处理为格式正确的PDF时,我发现了这个问题。这些文件都没有BOM,并且最旧的文件包含Codepage 1252代码点,这些代码点会导致对UTF8的错误解码。这仅在某些时间发生,UTF8在大多数时间都起作用。另外,最新的文本数据确实包含UTF8代码点,因此情况参差不齐。

因此,我还设置了“检测输入文件具有哪种编码” ,并且在读取How to detect the character encoding of a text file?How to determine the encoding of text?之后得出的结论是:最好。

但是,我在评论中发现了The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets,将其阅读并找到了这个宝石:

  

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.UTF8;
            utf8Encoding.DecoderFallback = 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进行细粒度的工作,则仍然可以使用这种方法。

答案 5 :(得分:0)

我用它来将文件编码转换为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);
            }
        }

答案 6 :(得分:-1)

  1. vCard文件的字符编码是否没有行业标准?
  2. 哪个更容易解决我的问题?将ANSI转换为UTF8(和/或反过来)或尝试检测输入文件具有哪种编码并通知用户有关它?
  3. 我是如何解决这个问题的: 我有vCard文件(* .vcf) - 俄语中一个文件中的200个联系人... 我用vCardOrganizer 2.1程序打开它然后让Split将其分成200 ....我所看到的 - 接触到凌乱的符号,只有我能读到它的数字:-) ...

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

    祝你好运!