如何用Java将DB2中的BLOB数据转为JSON/字符串并处理特殊字符
解决DB2大型机BLOB转JSON/字符串的特殊字符问题
你的问题核心是BLOB存储的并非纯UTF-8 JSON,而是带有控制字符、长度前缀的结构化二进制数据,直接按UTF-8解析会把二进制控制符当成乱码输出。以下是针对性的解决方案:
第一步:分析二进制结构(从你的示例反推)
从你提供的输出片段可以看出数据的规律:
- 键以
\u0002(ASCII STX)开头,键名结束后用\u0000(NULL)分隔 - 键名后跟着4字节大端序的长度值(比如
USER_ID后的\u0014\u0000\u0000\u0000对应十进制20,正好匹配值2022-01-01-01.01.01的长度) - 长度值后是对应长度的字符串值,值结束后用
\u0000分隔 - 开头的
\u0003?\u0004\u0000\u0000\u0003BUSINFON\u0000...属于元数据/组标识,需要跳过
第二步:修改代码解析二进制结构
放弃直接用UTF-8 Reader解析JSON的方式,改为读取二进制流,按结构提取键值对后再转JSON:
import com.google.gson.Gson; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.HashMap; import java.util.Map; import java.nio.charset.StandardCharsets; import java.util.Properties; public class DB2BlobParser { public static void main(String[] args) { String jdbcClassName = "com.ibm.db2.jcc.DB2Driver"; String url = "jdbc:db2://your-db2-host:port/your-db"; String q = "select COLUMN_NAME from TABLE_TEST"; Properties props = new Properties(); props.setProperty("useJDBC4ColumnNameAndLabelSemantics", "2"); props.setProperty("user", "******"); props.setProperty("password", "*****"); Connection connection = null; PreparedStatement pstate = null; ResultSet res = null; try { Class.forName(jdbcClassName); System.out.println("DB2 driver loaded successfully\n"); connection = DriverManager.getConnection(url, props); System.out.println("Connected successfully.\n"); pstate = connection.prepareStatement(q); res = pstate.executeQuery(); Gson gson = new Gson(); while (res.next()) { Blob blob = res.getBlob("COLUMN_NAME"); byte[] blobBytes = blob.getBytes(1, (int) blob.length()); ByteArrayInputStream bais = new ByteArrayInputStream(blobBytes); DataInputStream dis = new DataInputStream(bais); Map<String, String> resultMap = new HashMap<>(); // 跳过开头的元数据部分,直到找到第一个\u0002(STX) int b; while ((b = dis.read()) != -1) { if (b == 0x02) { // 找到键的起始标记 // 读取键名:直到遇到\u0000 StringBuilder keyBuilder = new StringBuilder(); while ((b = dis.read()) != 0x00 && b != -1) { keyBuilder.append((char) b); } String key = keyBuilder.toString(); // 读取4字节大端序的长度值 int valueLength = dis.readInt(); // 读取对应长度的字节,转成字符串(注意:如果是EBCDIC编码,替换为对应字符集) byte[] valueBytes = new byte[valueLength]; dis.readFully(valueBytes); String value = new String(valueBytes, StandardCharsets.UTF_8); // 跳过值后的\u0000分隔符 dis.read(); resultMap.put(key, value); } } // 转成JSON输出 System.out.println(gson.toJson(resultMap)); } } catch (Exception e) { e.printStackTrace(); } finally { // 标准资源关闭流程(需补充关闭res、pstate、connection) try { if (res != null) res.close(); if (pstate != null) pstate.close(); if (connection != null) connection.close(); } catch (Exception e) { e.printStackTrace(); } } } }
关键注意事项
- 编码确认:DB2大型机的数据可能采用EBCDIC编码而非UTF-8,如果解析后值仍乱码,将
StandardCharsets.UTF_8替换为IBM对应的EBCDIC字符集(比如Charset.forName("IBM-1047"))。 - 结构调整:如果你的BLOB结构和反推的不完全一致(比如长度字段是2字节、分隔符不同),需要根据实际二进制数据调整解析逻辑。
- 资源管理:代码补充了标准的资源关闭流程,避免数据库连接泄漏。
内容的提问来源于stack exchange,提问作者Mukul Venkatesh
相关产品推荐
相关产品推荐

