首页 > 解决方案 > UCanAccess 似乎无法使用 getBytes() 读取 OLE 对象列

问题描述

我有一个非常大的.mdb访问数据库,我想将其转换为 SQLite3 以在 Linux 下使用它。

我无法转移BLOB我拥有的任何 s(主要包含图像)。这是一个示例测试程序:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class prova {
        public static void main(String[] args) {
                String url = "jdbc:ucanaccess://data/BookDB-201810.mdb";
                try {
                        Connection c = DriverManager.getConnection(url);
                        PreparedStatement ps;
                        ResultSet rs;
                        String q = "SELECT * FROM PersonImage";
                        ps = c.prepareStatement(q);
                        rs = ps.executeQuery();
                        while (rs.next()) {
                                byte[] i = rs.getBytes("Image");
                                String fn = String.format("data/img/i%05d.%d.jpg", rs.getInt("PersonId"), rs.getInt("Index"));
                                try (FileOutputStream fos = new FileOutputStream(fn)) {
                                        fos.write(i);
                                } catch (FileNotFoundException e) {
                                        e.printStackTrace();
                                } catch (IOException e) {
                                        e.printStackTrace();
                                }
                        }
                } catch (SQLException e) {
                        e.printStackTrace();
                }
        }
}

程序运行没有错误,但生成的文件是“奇怪的”(肯定不是图像):

$ ls -l i00072.1.jpg 
-rw-r--r-- 1 mcon mcon 369 Nov 23 11:38 i00072.1.jpg
$ file i00072.1.jpg 
i00072.1.jpg: Java serialization data, version 5

看着他们,我发现:

....sr..net.ucanaccess.jdbc.BlobKey...........L.
columnNamet..Ljava/lang/String;L..keyt..Ljava/util/HashMap;L.   tableNameq.~..xpt..Imagesr..java.util.HashMap......`....F.
loadFactorI.    thresholdxp?@......w.........t..PersonIDsr..java.lang.Integer.⠤...8...I..valuexr..java.lang.Number...........xp...
Ht..Indexsr..java.lang.ShorthM7.4`.R...S..valuexq.~.  ..xt..PersonImage

我究竟做错了什么?

更新: 由于我的目标是转换书籍数据库(由于历史原因,使用过时的程序BookCAT在网上以 .mdb 形式维护)我发现AccessConverter似乎符合要求;不幸的是,这基本上有两个问题:

在程序 (BookCAT) 中,这些字段包含两种数据:

后者不太重要,因为总是有一个重复的“纯文本”版本(最好也检索格式化版本,但是......)。

不过,我真的很希望能够提取图像。

在图像数据中有一个伴随的“ImageType”列总是设置为“2”(如果我没记错的话)意味着它们应该是.jpeg图像。

如何以OLE可用格式检索数据?

注意: AccessConverter不使用ucanaccess,而是直接使用底层com.healthmarketscience.jackcess库。

注意2:它似乎BookCAT是使用 Delphi 构建的,如果相关的话。

标签: javams-accessjdbcucanaccessjackcess

解决方案


事实证明,在我的具体情况下,所有“OLE”字段实际上都是 BLOB,无法识别为 OLE2 对象。

在这种情况下,jackcess 返回一个Enum OleBlob.ContentType.UNKNOWN类型,在这种情况下,它将拒绝访问 BLOB 内容(OleBlob.content.getBytes()返回null)。

为了访问存储的数据必须直接使用Column.getBytes(name)(完全绕过OLE子系统)。

为什么在这种情况下ucanaccess返回无效值而不是失败,这超出了我的理解(可能我应该提交错误报告;欢迎评论)。

图像数据是纯 jpeg 格式的文件,而“格式化文本”似乎是 DelphiTRichText小部件的一些自定义序列化,我不知道如何解析,但这是另一个问题。

使用jackcess Column.getBytes(name)我能够检索我需要的数据。


推荐阅读