Convert.FromHexString最稳:.NET 5+原生支持标准十六进制字符串(如"A1B2"、"ff")转byte[],自动校验长度偶数及字符范围0-9a-fA-F,非法输入抛FormatException;需确保输入纯净,避免空格、"0x"前缀、不可见字符等。

Hex字符串转byte数组:用Convert.FromHexString最稳
.NET 5+ 直接支持标准十六进制字符串(如"A1B2"、"a1b2"、"0xA1B2"不行)转byte[],不用自己写循环解析。Convert.FromHexString会校验长度是否为偶数、字符是否在0-9a-fA-F范围内,出错直接抛FormatException。
常见错误现象:FormatException: Invalid length for a Base-64 char array——其实是误把Hex当Base64用了;或输入含空格、前缀"0x"、换行符,导致解析失败。
- 输入必须是纯十六进制字符,长度为偶数;
"A1B"会报错,"0xA1"也会报错 - 不区分大小写,
"FF"和"ff"效果一样 - 性能好,内部做了Span优化,比手写for循环快且安全
string hex = "48656C6C6F"; // "Hello" byte[] bytes = Convert.FromHexString(hex); // ✅
老版本.NET Framework(
没有Convert.FromHexString,得手动处理。别用int.Parse(s, NumberStyles.HexNumber)逐字节转——它只适合单字节(两位Hex),且对"00"这种边界值易出错。
更可靠的做法是用Regex.Replace预清洗 + Enumerable.Chunk(.NET 6+)或手动分组,但最兼容的是用BitConverter配合Substring切片。
- 先去掉空格、
"0x"、"0X"等前缀(正则^0[xX]s*|s*$) - 确保长度为偶数,奇数位补前导
"0"(比如"F"→"0F") - 每两位调用
byte.Parse(chunk, NumberStyles.HexNumber),别用Convert.ToByte——它不支持NumberStyles参数
string hex = " 0x4865 6C6C6F ";
hex = Regex.Replace(hex, @"^0[xX]s*|s*$", "").Replace(" ", "");
if (hex.Length % 2 != 0) hex = "0" + hex;
byte[] bytes = Enumerable.Range(0, hex.Length / 2)
.Select(i => byte.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber))
.ToArray();遇到FormatException: Input string was not in a correct format怎么办
这个错90%不是代码逻辑问题,而是输入脏了。Hex字符串里混入不可见字符(比如从剪贴板粘贴带BOM的文本)、全角数字/字母(中文输入法下按了123)、下划线、连字符都可能导致。
- 用
string.Trim()不够,得用Regex.Replace(hex, @"[^0-9a-fA-F]", "")暴力清洗(慎用,可能掩盖原始数据问题) - 调试时先打印
hex.Aggregate("", (a, c) => a + $"\u{(int)c:X4} ")看Unicode码点 - 如果来源是JSON或HTTP响应,注意编码是否为UTF-8,某些服务返回的Hex字段实际是base64编码后再hex展示(极少见,但踩过)
要不要用Span<char>自己实现高性能解析
除非你每秒要转几万次、且已确认这是瓶颈,否则没必要。原生Convert.FromHexString在.NET 6+已用Span重写,吞吐量足够日常所有场景。
自己用Span写,容易在边界上出错:比如没处理好奇数长度、忽略'a'到'f'的ASCII差值('a' - '0'不是10)、或忘记无符号比较导致负数索引。
- 真要手写,优先用
ReadOnlySpan<char>.Trim()再遍历,别用string.Substring - 查表法(预建256项
byte映射数组)比switch快,但维护成本高 - 多数项目里,IO或序列化耗时远大于Hex解析,优化这里意义不大
转换的核心从来不是“怎么写”,而是“怎么保证输入干净”。哪怕用了最稳的Convert.FromHexString,上游数据带个零宽空格,照样崩。










