You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

读取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");
}

格式分析

  1. LONG类型读取错误:Oracle的LONG是字符型大字段,不是二进制类型,用getBytes()读取会触发编码转换,破坏原始内容的完整性。
  2. 内容格式说明:
    • 第一行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:57:02