java - Access 使用 MS Access 创建的 Oracle10g 数据库中的 BLOBS

标签 java oracle ms-access character-encoding blob

我正在编写一个 Java(好吧,Groovy,但这在这里并不重要)迁移脚本,用于将 BLOB 字段从 Oracle10g 数据库复制到另一个数据库。数据由 MS Access 应用程序创建。这些文件的编码似乎不正确,我猜测 MS Access 或 ODBC 驱动程序以某种方式操纵该文件。

使用查询SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';我发现源数据库具有字符集WE8MSWIN1252

源表定义为:

CREATE TABLE CTR_DOCUMENTS (
  CTR_ID        NUMBER(11)           NOT NULL,
  CTR_A_ID      NUMBER(11),
  CTR_FILENAME  VARCHAR2(260 Char)   NOT NULL,
  CTR_COMMENT   VARCHAR2(255 Char),
  CTR_DATE      DATE,
  CTR_DATA      BLOB
)

我像这样 Access blob:

def blob = sourceDB.firstRow("SELECT CTR_DATA FROM CTR_DOCUMENTS WHERE CTR_ID = ?",
  [id]).CTR_DATA
def blobSize = blob.length()
def blobStream = blob.getBinaryStream()
byte[] byteArray = new byte[blobSize]
blobStream.read(byteArray)

我将一些 blob 保存为文件,编码看起来很奇怪,并且这些文件无法由其程序打开。第二个字节始终为 00:

0000000: 2500 5000 4400 4600 2d00 3100 2e00 3500  %.P.D.F.-.1...5.

我还观察到使用 SQL 客户端(SQL Workbench/J、SQLDeveloper、TOAD) Access BLOBS 的相同行为。

对我来说,看起来我必须将文件从 Windows-1252 转换为 UTF8,但这不起作用。 我在这里遗漏了什么吗?

最佳答案

为了诊断目的,如果没有别的办法,我首先要扫描输入 BLOB 样本中的字节数组,以查看每个第二个字节是否实际上是 0x00,并写入所有其他字节(非零)字节到 bytesOut 字节数组。如果成功,我会将 bytesOut 数组写入文件并查看它们现在是否是有效的 PDF 文档。例如:

public static void main(String[] args) {
   try {
        String connectionUrl = ""; 
        connectionUrl = 
                "jdbc:sqlserver://localhost;" +
                "instanceName=SQLEXPRESS;" +
                "databaseName=myDb;" +
                "integratedSecurity=true";
        Connection con = DriverManager.getConnection(connectionUrl);

        String SQL = 
                "SELECT CTR_ID, CTR_FILENAME, CTR_DATA " +
                "FROM CTR_DOCUMENTS " +
                "WHERE CTR_ID BETWEEN 1 AND 5"; 
        Statement stmt = con.createStatement(); 
        ResultSet rs = stmt.executeQuery(SQL);

        while (rs.next()) { 
            boolean writeFile = true; 
            byte[] bytesIn = rs.getBytes("CTR_DATA");
            //scan input byte array and copy every second byte to output byte array
            byte[] bytesOut = new byte[bytesIn.length / 2];
            for (int i = 0; i < bytesIn.length; i++) {
                if ((i % 2) == 1) {
                    if (bytesIn[i] != 0x00) {
                        System.out.println(String.format("Darn. bytesIn value at offset %d is not 0x00. Skipping...", i));
                        writeFile = false;
                        break;
                    }
                }
                else {
                    bytesOut[i / 2] = bytesIn[i];
                }
            }
            if (writeFile) {
                String outFile =
                        "C:\\__tmp\\pdfTest\\" + rs.getString("CTR_FILENAME");
                FileOutputStream fos = new FileOutputStream(outFile);
                fos.write(bytesOut);
                fos.close();
                System.out.println(String.format("\"%s\" created.", outFile));
            }
        }
        rs.close();
        con.close();
   } catch(Exception e) {
        System.out.println(e.getMessage());
        System.exit(0); 
   }
}

原因是,如果在此过程中的某个地方,某个进程将其认为是单字节字符的“字符串”(例如 Windows-1252)并通过简单地转换为 Unicode(例如 UCS-2LE)在每个字符后插入 0x00(不会破坏实际数据字节),那么最直接的解决方案就是再次取出这些 0x00 字节。

关于java - Access 使用 MS Access 创建的 Oracle10g 数据库中的 BLOBS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20248894/

相关文章:

java - 选择文本需要 XPath 建议

java - 我正在尝试使用按值排序的 HashMap 来构建一棵树。

java - JDBC:是否仅当调用 commit() 方法不成功时,调用 rollback() 方法才有效?

oracle - 如何在 Oracle SQL Developer 中查看数据库的模式树列表?

ms-access - MS Access 2003/2007 VBA - 如何从记录集中获取日期字段并将 dd-MMM-yyyy 格式字符串化?

sql - 将 Access SQL 查询转换为 SqlServer

java - grails 中的 native CXF 集成

sql - Oracle 优化器提示 xmlagg 函数

sql - trunc(date, 'IW' ) 到底是什么?

sql - 比较没有当前月份的 SQL 日期