
用 File.ReadAllBytes
读取文件再转十六进制字符串
这是最直接的方式:先读取整个文件为字节数组,再逐字节格式化为两位十六进制字符。适合中小文件(
常见错误是用
Encoding.UTF8.GetString后再调用
GetBytes—— 这会破坏原始二进制内容,完全不可取。
File.ReadAllBytes(path)返回
byte[],保持原始字节不变 用
string.Join("", bytes.Select(b => b.ToString("x2"))) 转成小写十六进制字符串(如 "48656c6c6f") 若需大写,改用
"X2"格式(如
"48656C6C6F") 不建议对超大文件一次性读入内存,会触发
OutOfMemoryException
大文件用 FileStream
+ Span<byte></byte>
流式处理
当文件超过几百 MB,必须避免全量加载。用
FileStream分块读取,配合
Span<byte></byte>避免重复分配数组,性能更稳。
注意:别用
StreamReader或任何基于文本的流——它们会尝试解码,彻底毁掉二进制数据。 创建
FileStream时指定
FileAccess.Read和
FileShare.Read分配一个固定大小的
byte[] buffer = new byte[8192],或用
stackalloc byte[8192](仅限
unsafe上下文) 循环调用
stream.Read(buffer, 0, buffer.Length),直到返回值为 0 每块用
Span<byte>.Slice(0, bytesRead).SequenceEqual(...)</byte>不需要,只需对当前块做
ToString("x2") 拼接
输出带地址偏移和 ASCII 显示的类 Unix Hex Dump
如果目标是模拟
xxd或
hexdump -C的可读格式(含偏移、十六进制区、ASCII 区),就不能只拼字符串,得按行组织。
典型坑是 ASCII 区乱码处理:非打印字符(
0x00–0x1F、
0x7F)应显示为
.,空格和换行等要保留语义。 每行通常 16 字节,偏移用 8 位十六进制左对齐(如
"00000000: ") 十六进制部分每字节两个字符,每 4 字节加空格分隔(
"48656c6c 6f20776f...") ASCII 区:对每个字节
b,判断
char.IsControl((char)b) || b > 127,是则填
'.',否则转
(char)b最后一行可能不满 16 字节,ASCII 区右侧补空格对齐
注意编码与 BOM 对结果的影响
Hex dump 是对原始字节的忠实呈现,跟文本编码无关。但如果你误用
File.ReadAllText再转字节,就会引入编码层干扰——比如 UTF-8 BOM(
0xEF,0xBB,0xBF)会被自动剥离或错误解释。
哪怕文件本身是纯文本,只要需求是“Hex Dump”,就必须绕过所有编码逻辑,直触字节流。
绝对不要用File.ReadAllText、
StreamReader、
Encoding.Default确认路径存在且有读取权限,否则
File.ReadAllBytes抛
FileNotFoundException或
UnauthorizedAccessExceptionLinux/macOS 路径区分大小写,
C:\test.txt和
c:\test.txt在 Windows 下等价,但代码里保持一致更安全 实际 Hex Dump 的复杂点不在转换本身,而在格式对齐、边界处理和不可见字符的判定逻辑。很多人卡在最后一行补空格或 ASCII 区错位上,建议先写单行逻辑验证,再扩展成完整块渲染。
