我有一个字节数组,我知道它是一个XML序列化对象,那么有没有办法从中获取编码?
我不打算反序列化它,但我需要将它保存在SQL服务器上的XML字段中...所以我需要将它转换为字符串吗?
我有一个字节数组,我知道它是一个XML序列化对象,那么有没有办法从中获取编码?
我不打算反序列化它,但我需要将它保存在SQL服务器上的XML字段中...所以我需要将它转换为字符串吗?
类似于这个问题的解决方案可以通过使用字节数组上的流来解决。然后您就不必在字节级别上进行操作。就像这样:
Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
encoding = xmlreader.Encoding;
}
}
W3C XML规范中有一节关于如何确定字节串的编码。
BOM只是另一个字符;它是:
例如:
"\ufeff<xml vers"
"\ufeff\u003c\u003f\u0078\u006d\u006c\u0020\u0076\u0065\u0072\u0073"
字符U+FEFF和文件中的其他字符一样,使用合适的编码方案进行编码:
00 00 FE FF
: UCS-4,大端机器(1234顺序)FF FE 00 00
: UCS-4,小端机器(4321顺序)00 00 FF FE
: UCS-4,不寻常的八位顺序(2143)FE FF 00 00
: UCS-4,不寻常的八位顺序(3412)FE FF ## ##
: UTF-16,大端FF FE ## ##
: UTF-16,小端EF BB BF
: UTF-8其中## ##
可以是任何内容 - 除了两个都是零
ff
fe
3c
00
3f
00
78
00
6d
00
6c
00
20
00
76
00
65
00
72
00
73
00
ff
fe
3c
00
3f
00
78
00
6d
00
6c
00
20
00
76
00
65
00
72
00
73
00
首先检查初始字节是否包含这些标识之一。如果找到其中一个,请返回代码页标识符。
UInt32 GuessEncoding(byte[] XmlString)
{
if BytesEqual(XmlString, [00, 00, $fe, $ff]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$ff, $fe, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [00, 00, $ff, $fe]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [$fe, $ff])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
}
if BytesEqual(XmlString, [$ff, $fe])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
}
if BytesEqual(XmlString, [$ef, $bb, $bf]) return 65001; //"utf-8" - Unicode (UTF-8)
如果XML文档没有字节顺序标记字符,那么您需要查找每个XML文档必须具有的前五个字符:
<?xml
知道以下内容会很有帮助:
<
是 #x0000003C?
是 #x0000003F有了这些信息,我们就可以查看前四个字节:
00 00 00 3C
: UCS-4,大端机器(1234顺序)3C 00 00 00
: UCS-4,小端机器(4321顺序)00 00 3C 00
: UCS-4,不寻常的八位顺序(2143)00 3C 00 00
: UCS-4,不寻常的八位顺序(3412)00 3C 00 3F
: UTF-16,大端3C 00 3F 00
: UTF-16,小端3C 3F 78 6D
: UTF-84C 6F A7 94
: EBCDIC的某种风味那么我们可以继续添加更多的代码:
if BytesEqual(XmlString, [00, 00, 00, $3C]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$3C, 00, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [00, 00, $3C, 00]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, $3F]) return return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
if BytesEqual(XmlString, [$3C, 00, $3F, 00]) return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
if BytesEqual(XmlString, [$3C, $3F, $78, $6D]) return 65001; //"utf-8" - Unicode (UTF-8)
if BytesEqual(XmlString, [$4C, $6F, $A7, $94])
{
//Some variant of EBCDIC, e.g.:
//20273 IBM273 IBM EBCDIC Germany
//20277 IBM277 IBM EBCDIC Denmark-Norway
//20278 IBM278 IBM EBCDIC Finland-Sweden
//20280 IBM280 IBM EBCDIC Italy
//20284 IBM284 IBM EBCDIC Latin America-Spain
//20285 IBM285 IBM EBCDIC United Kingdom
//20290 IBM290 IBM EBCDIC Japanese Katakana Extended
//20297 IBM297 IBM EBCDIC France
//20420 IBM420 IBM EBCDIC Arabic
//20423 IBM423 IBM EBCDIC Greek
//20424 IBM424 IBM EBCDIC Hebrew
//20833 x-EBCDIC-KoreanExtended IBM EBCDIC Korean Extended
//20838 IBM-Thai IBM EBCDIC Thai
//20866 koi8-r Russian (KOI8-R); Cyrillic (KOI8-R)
//20871 IBM871 IBM EBCDIC Icelandic
//20880 IBM880 IBM EBCDIC Cyrillic Russian
//20905 IBM905 IBM EBCDIC Turkish
//20924 IBM00924 IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
throw new Exception("We don't support EBCDIC. Sorry");
}
//Otherwise assume UTF-8, and fail to decode it anyway
return 65001; //"utf-8" - Unicode (UTF-8)
//Any code is in the public domain. No attribution required.
}
<?xml
部分明显地看出来(只需检查两种模式即可)。1 可能少于这个数字。我觉得20个字符应该足够了,在UTF-16中是40个字节。
前2或3个字节可能是字节顺序标记(BOM),可以告诉您流是UTF-8、Unicode-LittleEndian还是Unicode-BigEndian。
UTF-8 BOM为0xEF 0xBB 0xBF Unicode-Bigendian为0xFE 0xFF Unicode-LittleEndiaon为0xFF 0xFE
如果没有这些内容,则可以使用ASCII测试 <?xml
(注意,大多数现代XML生成都遵循标准,即不允许空格出现在xml声明之前)。
ASCII一直使用到?>
,因此您可以找到编码的存在并查找其值。如果不存在编码或<?xml
声明不存在,则可以假定为UTF-8。