读取Oracle LONG类型列内容生成有效文件的问题求助
Oracle LONG列读取的文件无效:格式解析与修复方案
问题场景
旧Oracle数据库表中有一个LONG类型列IMAGECONTENTS_COMPRESSED,用以下Java代码读取内容写入文件后,文件无法作为PDF打开:
import java.io.FileOutputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TheMainClass{ @SuppressWarnings("resource") public static void main(String[] args) { String username = "easyusername"; String password = "toughpassword"; try (Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@server.com:1521/theservicename", "" + username + "", "" + password + "")) { try (PreparedStatement s = conn.prepareStatement( "SELECT IMAGECONTENTS_COMPRESSED FROM images_compressed where IMAGE_COMPRESSED_K = 'D25Q0XS9T0'"); ResultSet rset2 = s.executeQuery()) { if (rset2.next()) { byte[] bytes = rset2.getBytes(1); try { FileOutputStream file = null; file = new FileOutputStream("somefilename.pdf"); file.write(bytes); } catch (Exception e) { String err = e.toString(); System.out.println(err); } finally { System.out.println("All Done. !"); } } } } catch (SQLException e) { System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
打开生成的文件,内容为:
FORMAT-ZIPV2 504B0304140002000800AC7D113702F7FE42B1340000574900000E000000643235713078733974302E706466EDBC775853CDF6284CEFCD8222520216108524404882F45EA42ANDAVERYLONGSTRING
尝试移除FORMAT-ZIPV2后用Base64解码,生成的ZIP文件仍无效,处理代码如下:
String content = new String(Files.readAllBytes(Paths.get("zipfilename.pdf"))); String newContent = content.replaceAll("FORMAT-ZIPV2", "").replaceAll("\\r|\\n", ""); System.out.println("File Content:: " + content); System.out.println("File New Content:: " + newContent); Base64.Decoder dec = Base64.getDecoder(); String decoded = new String(dec.decode(newContent)); System.out.println("decoded value is \t\n\n" + decoded); Path path = Paths.get("somezipfilename.zip"); try { Files.writeString(path, decoded, StandardCharsets.UTF_8); } catch (IOException ex) { System.out.print("Invalid Path"); }
格式分析
- LONG类型读取错误:Oracle的
LONG是字符型大字段,不是二进制类型,用getBytes()读取会触发编码转换,破坏原始内容的完整性。 - 内容格式说明:
- 第一行
FORMAT-ZIPV2是自定义格式标识,说明后续内容是ZIP格式的十六进制字符串。 - 第二行的字符串是十六进制编码的ZIP文件内容(开头
504B是ZIP文件的魔数签名),并非Base64编码,之前用Base64解码的逻辑完全错误。
- 第一行
正确处理方案
方案1:直接从数据库读取并生成有效文件
修正数据库读取逻辑,用getString()获取LONG列的完整字符内容,再处理十六进制字符串:
import java.io.FileOutputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TheMainClass { public static void main(String[] args) { String username = "easyusername"; String password = "toughpassword"; try (Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@server.com:1521/theservicename", username, password)) { try (PreparedStatement s = conn.prepareStatement( "SELECT IMAGECONTENTS_COMPRESSED FROM images_compressed where IMAGE_COMPRESSED_K = 'D25Q0XS9T0'"); ResultSet rset2 = s.executeQuery()) { if (rset2.next()) { // 用getString读取LONG列的完整字符内容 String longContent = rset2.getString(1); // 分割格式标识和十六进制内容 String[] parts = longContent.split("\\r?\\n", 2); if (parts.length == 2 && "FORMAT-ZIPV2".equals(parts[0].trim())) { String hexString = parts[1].trim(); // 将十六进制字符串转换为字节数组 byte[] zipBytes = hexStringToByteArray(hexString); // 写入ZIP文件 try (FileOutputStream file = new FileOutputStream("valid_file.zip")) { file.write(zipBytes); System.out.println("ZIP文件生成成功,解压后即可得到PDF"); } } } } } catch (SQLException e) { System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } // 十六进制字符串转字节数组工具方法 private static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } }
方案2:修复已生成的错误文件
如果已经生成了错误文件,用以下代码处理:
import java.nio.file.Files; import java.nio.file.Paths; import java.io.FileOutputStream; public class FixFile { public static void main(String[] args) { try { // 读取错误文件内容 String content = new String(Files.readAllBytes(Paths.get("somefilename.pdf"))); // 分割并去除格式标识 String[] parts = content.split("\\r?\\n", 2); if (parts.length == 2) { String hexString = parts[1].trim().replaceAll("\\s", ""); // 十六进制转字节数组 byte[] zipBytes = hexStringToByteArray(hexString); // 写入ZIP文件 try (FileOutputStream file = new FileOutputStream("valid_file.zip")) { file.write(zipBytes); System.out.println("修复完成,解压ZIP得到PDF"); } } } catch (Exception e) { e.printStackTrace(); } } private static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } }
关键注意事项
- Oracle的
LONG类型属于字符型,必须用getString()读取,getBytes()会触发字符编码转换,破坏原始内容。 - 第二行内容是十六进制编码,不是Base64,必须用十六进制转字节数组的逻辑处理。
- 生成的ZIP文件直接解压就能得到目标PDF文件。
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

