71

我正在编写一个 TFS Checkin 策略,它检查我们的源文件是否包含我们的文件头。

我的问题是,我们的文件头包含一个特殊字符“©”,不幸的是我们的一些源文件是用 ANSI 编码的。因此,如果我阅读策略中的这些文件,字符串看起来像这样“版权所有 2009”。

string content = File.ReadAllText(pendingChange.LocalItem);

我厌倦了更改字符串的编码,但这无济于事。那么如何阅读这些文件以获得正确的字符串“Copyright © 2009”?

4

3 回答 3

140

使用Encoding.Default

string content = File.ReadAllText(pendingChange.LocalItem, Encoding.Default);

但是,您应该知道,它使用系统默认编码读取它 - 这可能与文件的编码不同。没有称为 ANSI 的单一编码,但通常当人们谈论“ANSI 编码”时,他们指的是 Windows 代码页 1252 或他们的盒子碰巧使用的任何东西。

如果您能找出使用的确切编码,您的代码将更加健壮。

于 2009-09-16T10:16:42.373 回答
6

如果你有这样的政策,你也会有团队同意的标准编码,这似乎是明智的。老实说,我不明白为什么任何团队会使用“Unicode(带签名的 UtF-8)-代码页 65001”以外的编码(可能除了具有重要非拉丁静态内容的 ASPX 页面,但即便如此我也不能'看不出使用 UTF-8 有多大意义)。

假设您仍然希望允许混合编码,那么您接下来需要一种方法来确定文件保存在哪种编码中,以便您知道要传递给ReadAllText. 从文件中确定这一点并不容易,但是使用Encoding.Default可能可以正常工作。由于您很可能只有 2 种编码要处理,即 VS(带签名的 UTF-8)和您的机器使用的常见 ANSI 编码(可能是 Windows-1252)。

因此使用

 string content = File.ReadAllText(pendingChange.LocalItem, Encoding.Default);

将工作。(我看到乔恩已经发布了)。这是因为当 UTF-8 BOM(VS 术语“签名”的意思)出现在文件开头时,提供的编码参数将被忽略,并且无论如何都会使用 UTF-8。因此,使用 UTF-8 保存文件的地方会得到正确的结果,而使用 ANSI 的地方也最有可能得到正确的结果。

顺便说一句,如果您正在处理文件头不会ReadAllLines让事情变得更容易?

于 2009-09-16T10:42:25.450 回答
1

我知道这是一个老问题,但我遇到了类似的情况,并发现公认的答案是偷工减料(不要忽视 Jon Skeet 务实的简短回答,但我会再充实一点)......

规范声明标头将在之后直接包含编码{\rtf:

\ansi ANSI(默认)
 \mac 苹果麦金塔
 \pc IBM PC 代码页 437
 \pca IBM PC 代码页 850,由 IBM Personal System/2 使用(未在 Microsoft Word for OS/2 版本 1 中实现)

根据维基百科,“ ANSI 字符集没有明确定义的含义

对于默认的 ANSI,您可以选择这些部分不兼容的编码:

using System.Text;
...
string content = File.ReadAllText(filename, Encoding.GetEncoding("ISO-8859-1"));
or
string content = File.ReadAllText(filename, Encoding.GetEncoding("Windows-1252"));

在 Windows 10 上使用写字板保存带有欧元符号的文件(Windows-1252 中的 0x80 但 ISO-8859-1 中的 0xA4)显示以下内容:

标头在之后说明了确切的编码\ansi

{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1043{ ...

并且编码没有直接使用,而是包装在 RTF 编码中:\'80

根据规格:

\'hh :基于指定字符集的十六进制值(可用于标识 8 位值)。

我想最好的办法是读取标题,如果文件{\rtf1\ansi\ansicpg1252Windows-1252.

但是为了让事情变得更复杂,规范还声明可以混合编码......搜索'\ upr'......

我想没有明确的答案,在您的情况下,最简单的方法可能是搜索(在未解码的原始字节数组中)您可能在源代码库中遇到的编码版权标志的所有变体。

就我而言,我最终决定也走一些捷径,但添加一小部分防御性编码。到目前为止,Windows-1252我看到的所有文件都是针对此进行常见情况优化的。

    Encoding encoding = Encoding.GetEncoding("Windows-1252", EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback);
    
    using (System.IO.StreamReader reader = new System.IO.StreamReader(filename, encoding)) {
        string header= reader.ReadLine();
        if (!header.Contains("cpg1252")) {
            if(header.Contains("\\pca"))
                encoding = Encoding.GetEncoding(850, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback);
            else if (header.Contains("\\pc"))
                encoding = Encoding.GetEncoding(437, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback);
            else
                encoding = Encoding.GetEncoding("ISO-8859-1", EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback);
        }
    }
    
    string content = System.IO.File.ReadAllText(filename, encoding);
于 2021-04-05T00:49:26.957 回答