UCanAccess не может прочитать столбец OLE Object с помощью getBytes ()

У меня есть довольно большая база данных доступа .mdb, которую я хочу преобразовать в SQLite3, чтобы использовать ее под Linux.

Я не могу передать какие-либо из имеющихся у меня BLOB (в основном содержащих изображения). Вот пример программы тестирования:

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.    [email protected].⠤...8...I..valuexr..java.lang.Number...........xp...
Ht..Indexsr..java.lang.ShorthM7.4`.R...S..valuexq.~.  ..xt..PersonImage

Что я делаю неправильно?

Обновлять: Поскольку моя цель - преобразовать базу данных книг (поддерживаемую в сети как .mdb с использованием устаревшей программы BookCAT по историческим причинам), я нашел AccessConverter, который, кажется, отвечает всем требованиям; К сожалению, здесь есть две проблемы:

  • В моей базе данных некоторые столбцы названы «Индекс», что является зарезервированным словом для SQLite (и других, но, очевидно, не для MS-Access); это тривиально исправлено вставкой фильтра «Индекс» -> «Идентификатор».
  • Существует перевод switch (type) { case xxx: ... для преобразования различных типов MS-Access в более традиционные типы SQLite3; Установив точку останова на этикетке default:, я обнаружил (как правильно догадался @ErikvonAsmuth) существуют необработанные типы OLE. Я понятия не имею, как с этим справиться.

В программе (BookCAT) эти поля содержат данные двух типов:

  • картинки
  • форматированный текст

Последнее менее важно, потому что всегда есть дублирующаяся версия с открытым текстом (было бы неплохо получить также отформатированную версию, но ...).

Однако мне бы очень хотелось иметь возможность извлекать изображения.

В данных изображения есть сопутствующий столбец «ImageType», для которого всегда установлено значение «2», что (если я не ошибаюсь) означает, что это должны быть изображения .jpeg.

Что я могу сделать, чтобы получить данные OLE в удобном для использования формате?

Примечание:AccessConverter не использует ucanaccess, вместо этого он использует непосредственно базовую библиотеку com.healthmarketscience.jackcess.

Заметка 2: кажется, что BookCAT построен с использованием Delphi, если это уместно.

В Access нет такой вещи, как VARBINARY. Существуют объекты OLE, но они бывают разных типов: некоторые просто содержат файл в виде двоичных данных, другие содержат определенные заголовки, а третьи сжимают файлы и помещают несколько файлов в одну строку. Если вы не укажете, что именно вы пытаетесь импортировать, мы, скорее всего, не сможем вам помочь.

Erik A 24.11.2018 00:53

@ErikvonAsmuth: всего несколько минут назад я обнаружил, что Вы абсолютно правы. Я обновлю вопрос, чтобы отразить мои выводы и уточнить вопрос (краткое резюме: эти поля содержат либо изображения, либо «форматированный текст»).

ZioByte 24.11.2018 02:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
476
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Оказывается, в моем конкретном случае все поля «OLE» на самом деле являются большими двоичными объектами, нераспознаваемыми как объекты OLE2.

В этом случае jackcess возвращает тип Enum OleBlob.ContentType.UNKNOWN и в этом случае откажется от доступа к содержимому BLOB (OleBlob.content.getBytes() возвращает null).

Для доступа к хранимым данным необходимо напрямую использовать Column.getBytes(name) (полностью минуя подсистему OLE).

Почему в этом состоянии ucanaccess возвращает недопустимое значение вместо ошибки, я не понимаю (возможно, мне следует отправить отчет об ошибке; комментарии приветствуются).

Данные изображения представляют собой простой файл в формате jpeg, в то время как «форматированный текст» кажется некоторой настраиваемой сериализацией виджета Delphi TRichText, я не знаю, как разбирать, но это другая проблема.

Используя jackcessColumn.getBytes(name), я смог получить нужные мне данные.

С UCanAccess вам нужно использовать ResultSet#getBlob:

String q = "SELECT * FROM PersonImage";
ps = conn.prepareStatement(q);
rs = ps.executeQuery();
while (rs.next()) {
    java.sql.Blob image = rs.getBlob("Image");
    String fn = String.format("C:/Users/Gord/Pictures/i%05d.%d.jpg", rs.getInt("PersonId"), rs.getInt("Index"));
    try (FileOutputStream fos = new FileOutputStream(fn)) {
            fos.write(image.getBytes(1, (int) image.length()));
    } catch (FileNotFoundException e) {
            e.printStackTrace();
    } catch (IOException e) {
            e.printStackTrace();
    }
}

Мы смогли получить доступ к контенту, используя тип файла UCanaccess + accdb:

String columnLabel = "FIELD1"; 
Object obj = rs.getObject(2);
net.ucanaccess.complex.Attachment[] attachments = (net.ucanaccess.complex.Attachment[])obj;
net.ucanaccess.complex.Attachment att = attachments[0];
System.err.println("Attachment Name: " + att.getName());
byte[] bytea = att.getData();

Как видите, вложения представляют собой массив и могут содержать более одного вложения.

Другие вопросы по теме