如何提取MS Access数据库Long Text字段存储的二进制TIFF图像数据
问题根因
字段仅显示II*不是数据丢失,核心原因有两点:
II*本身是小端序TIFF图像的标准文件魔数:小端存储的TIFF文件头固定为前2字节0x49 0x49(对应ASCII字符II)、第3字节0x2A(对应ASCII字符*)、第4字节0x00。Access的文本显示逻辑将0x00识别为字符串终止符,所以界面上只会展示前3个字符,后续所有图像数据都被显示层截断,实际仍完整存储在字段内。- 写入逻辑导致直接按文本读取会乱码:VB6 FileSystemObject(FSO)以二进制模式打开TIFF文件写入Access Long Text(即旧版Memo类型)字段时,会将每个原始二进制字节当作系统默认ANSI代码页的单字符,自动转换为.mdb引擎底层使用的UTF-16LE编码字符串,过程中没有做编码合法性校验。如果直接用文本读取接口拉取字段值,会触发编码自动转换,破坏原始字节序列,得到无法识别的乱码。
提取操作步骤
- 读取阶段跳过文本编码转换:不要用Access自带导出功能、也不要用数据读取器的
GetString()方法获取字段内容,直接读取字段的原始存储字节。C#操作OleDb连接.mdb时,调用OleDbDataReader.GetBytes()方法拉取全量字节块,完全绕过默认的文本解码逻辑。 - 逆向还原FSO的编码映射:FSO写入时将每个原始文件字节映射为1个UTF-16LE字符(每个字符占2字节,低字节为原始文件字节值,高字节为0),因此拿到字段原始字节数组后,每隔1个字节取1个低字节,丢弃高字节,即可拼回完整的原始TIFF文件字节流。核心实现代码如下:
// 初始化数据库连接、命令、reader的逻辑略,确保查询语句包含Id和Image字段 // 假设Image字段对应reader的列索引为1 // 第一步:获取字段原始字节总长度 long fieldByteLength = reader.GetBytes(1, 0, null, 0, 0); byte[] fieldRawBuffer = new byte[fieldByteLength]; // 第二步:拉取字段全量原始字节,不做任何编码转换 reader.GetBytes(1, 0, fieldRawBuffer, 0, (int)fieldByteLength); // 第三步:还原原始TIFF字节:UTF-16LE编码每个字符占2字节,取每个字符的低8位 List<byte> tiffFileBytes = new List<byte>(); for (int i = 0; i < fieldRawBuffer.Length; i += 2) { tiffFileBytes.Add(fieldRawBuffer[i]); }
- 结果输出:还原完成后校验字节数组前3位,若为
0x49、0x49、0x2A即为还原成功。需要base64格式直接调用Convert.ToBase64String(tiffFileBytes.ToArray())即可生成;需要文件的话直接将字节数组写入.tif后缀文件,就能正常用图像查看器打开。
注意事项
- 绝对不要尝试将读取到的字符串值用UTF-8、GBK、Windows-1252等编码重新转成字节,这类二次转码会不可逆破坏原始字节数据,必须在数据库读取环节直接获取原始二进制块。
- 如果还原后TIFF文件无法打开,先检查读取字段时是否误走了字符串解析逻辑,只要严格用
GetBytes()拿原始存储数据,按上述规则还原的字节流和原始TIFF文件完全一致。
内容的提问来源于stack exchange,提问作者jo phul
相关产品推荐
相关产品推荐

