解释:
我在编写网络应用程序时遇到了一个边缘情况。我接受要上传的 UTF-8 文件,并且我已经进行了检查以确认它是 UTF-8 编码的(或者至少是可能的最佳检查,显然没有灵丹妙药,我知道有很多关于该特定问题的 Stack Overflow 上的其他问题)。
作为测试,我采用了 ANSI 编码文件并将其转换为 UTF-8,方法是(在单独的测试中)在 Notepad++ 中将其转换为 UTF-8,并在上将其解码为 UTF-8(即使它是 ANSI) C# 中的苍蝇使用
Encoding.UTF.GetBytes(inputStream)
。
问题出现在哪里:
随后,我将文件的原始数据作为 XML 文件中的元素之一放置。这就是问题出现的地方。看起来 ANSI 文件中保留了一个字符(我假设)在 UTF-8 中无效。当我尝试使用以下命令加载 XML 时...
XDocument xmlSample = XDocument.Load(outputPath);
我遇到了这个异常...
{"Invalid character in the given encoding. Line 10, position 14."}
在 Visual Studio 中看起来像这样...
就像在 Notepad++ 中这样...
以下是字符复制粘贴。
来自 NPP:
¡
来自 Visual Studio 字符串查看器:�
问题:
如何从 UTF-8 编码文件中删除无效字符,或者至少以合理的方式发现它们,以便我可以拒绝该文件?
首先,就您的示例而言,“温度”一词表明有问题的字符实际上是“度”符号(°,Unicode 176),因此全文为“温度(°C)”。在这种情况下,字符将在 ANSI 中编码为
\260
字节,在 UTF-8 中编码为两个字节 \302\260
。 \260
(在本例中前面带有左括号)不是有效的 UTF-8。
第二 – 如果一年多后您仍然感兴趣 – 您能否澄清一下如何使用
Encoding.UTF.GetBytes()
“将文件解码为 UTF-8”? GetBytes()
读取字符,而不是字节,并且C#中的字符没有编码;读取文件并将其转换为字符时已应用编码。 UTF.GetBytes()
的作用是将字符编码(而不是解码)为 UTF-8 字节序列。
为了检查传入的字节序列,您可以使用
Encoding.UTF.GetChars()
将字节序列解码为字符。根据您使用的构造函数,您可以获得“清理”的字符串(如果出现问题,则会丢失数据)或在有问题的字节序列上收到 DecoderFallbackException
,因此您可以拒绝输入。
如果您想过滤掉无效的 UTF-8 字符,例如来自未知来源的字符,或者作为截断字符串的结果,您可以使用
DecoderFallbackException
,如 @Renardo 所描述。
实现示例:
public static string GetValidString(Encoding encoding, byte[] bytes)
{
try
{
// Try to encode the bytes
return encoding.GetString(bytes);
}
catch (DecoderFallbackException ex)
{
// Get the succesful part
var start = encoding.GetString(bytes[..ex.Index]);
// If there is any part after the invalid bytes, add it to start
int? resume = ex.BytesUnknown != null
? ex.Index + ex.BytesUnknown.Length
: null;
return resume != null && bytes.Length > resume
? start + GetValidString(encoding, bytes[resume.Value..])
: start;
}
}
用途:
var utf8 = new UTF8Encoding(false, true); // throw DecoderFallbackException on invalid characters
var bytes = utf8.GetBytes("🐞🐞")[..5]; // [0xF0, 0x9F, 0x90, 0x9E, 0xF0]
var validString = GetValidString(utf8, bytes); // "🐞"
如果你愿意,你可以将其作为
Encoding
的扩展方法。