如何使C#抛出解码异常?
我想让我的C#应用程序(有图形界面)帮助用户在“unicode (utf-8)”和“legacy (cp1252)”之间选择。我希望给用户提供两个独立的真/假选项,告诉他们文件是否可以在这两种格式下“成功”读取(虽然不一定是正确的),并且没有任何细节丢失。
我在C#中尝试了以下代码,但没有成功。也就是说,无论我用它去读取一个我知道包含非罗马字符的utf-8文本文件,它似乎总是返回true。
[编辑:其实,我不应该认为这个会失败。可能这是一个合理的成功,但结果却不正确,因为大多数(所有?)字节流在cp1252编码下也是有效的。测试反向读取时,确实能找到无效的utf-8,就像下面的Python代码那样。]
例如,CanBeReadAs("nepali.txt", Encoding.GetEncoding(1252))应该返回false,但它却返回true。
public static bool CanBeReadAs(string filePath, Encoding encoding)
{
// make it strict:
encoding = Encoding.GetEncoding(encoding.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
using (var r = new StreamReader(filePath, encoding, false))
{
try
{
r.ReadToEnd();
}
catch (Exception e)
{
//swallow
return false;
}
}
return true;
}
我还尝试过用“string s = r.ReadToEnd();”来确保数据真的被强制解码,但这似乎没有影响。
我哪里做错了?
注意:如果我需要特别处理BOM(字节顺序标记),请告诉我。我倾向于忽略它们,如果这样做简单的话。(顺便说一下,这些文件有混合编码,不过我希望任何以BOM开头的文件都是纯unicode。)
这是我创建的一个Python脚本,它使用了相同的策略,并且运行良好:
def bad_encoding(filename, enc='utf-8', max=9):
'''Return a list of up to max error strings for lines in the file not encoded in the specified encoding.
Otherwise, return an empty list.'''
errors = []
line = None
with open(filename, encoding=enc) as f:
i = 0
while True:
try:
i += 1
line = f.readline()
except UnicodeDecodeError:
errors.append('UnicodeDecodeError: Could not read line {} as {}.'.format(i, enc))
if not line or len(errors) > max:
break
return errors
1 个回答
通过Encoding类可以找到一些静态的编码实例,比如Ascii、UTF8、Unicode等。这些编码实例在解码输入的字节时会尽量做到最好,即使解码失败也不会报错。
如果你想创建一个具有特定编码/解码行为的Encoding实例,可以使用Encoding.GetEncoding
的重载版本,这个版本需要传入EncoderFallback和DecoderFallback参数。我尝试创建了各种编码的实例(比如AsciiEncoding和UTF8Encoding),但它们是只读的,所以设置回退选项时总是会抛出InvalidOperationException异常。如果你想创建一个在解码失败时会报错的实例,可以试试:
encoding = Encoding.GetEncoding(encoding.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);