Экспорт таблиц accessdb в csv

Работал над фрагментом кода Java для экспорта нескольких таблиц из базы данных доступа в CSV. Я хочу развернуть этот код как лямбда-функцию. Я пытался использовать Jackcess, но следующее

        try {
            String dateOfExtraction = LocalDateTime.now().toString();
            Database db = DatabaseBuilder.open(new File("java-runtime/src/access_db_file.accdb"));
            System.out.println(db.getTableNames());
            ExportUtil.exportFile(db, "table_name", new File("table_name" + dateOfExtraction + ".csv"));
        } catch (IOException e) {
            e.printStackTrace();
        }

выдает ошибку: java.io.FileNotFoundException: given file does not exist: C:\Users\john.doe.ctr\Desktop\Work\table_name

Я запускаю свой код на Mac, этот путь к файлу принадлежит пользователю, который предоставил мне БД. Это какая-то ошибка разрешений? Должен ли я вместо этого просто использовать UCanAccess? Я не могу использовать какие-либо инструменты командной строки UCanAccess, мне нужно запустить это в лямбде. Строка System.out.println(db.getTableNames()); работает точно так, как ожидалось, и выводит список всех имен таблиц в accessdb.


person Ravmcgav    schedule 29.04.2021    source источник
comment
Вы пытались получить доступ к таблице с помощью Table table = db.getTable("table_name")?   -  person Olivier    schedule 03.05.2021


Ответы (2)


В коде может быть несколько проблем.

Во-первых, вы используете LocalDateTime.now().toString() как часть имени файла CSV, в котором будет сохранена информация. Это даст вам что-то вроде:

2021-05-02T23:42:03.282

В некоторых операционных системах — вы упомянули MacOS, но она должна позволить вам создать файл с таким именем — это имя может быть возможной причиной проблем; рассмотрите возможность использования чего-то менее подверженного ошибкам, например System.currentTimeMillis:

String filename = "table_name" + System.currentTimeMillis() + ".csv";
ExportUtil.exportFile(db, "table_name", new File(filename));

Сказав это, пожалуйста, имейте в виду, что в функции AWS Lambda вам, вероятно, потребуется хранить свои результаты во внешнем хранилище, обычно S3: у вас есть возможность записи в файловую систему, но обычно это имеет значение при работе с временными файлами, не с постоянным хранилищем. Пожалуйста, рассмотрите, например, следующий фрагмент кода.

// Here you can have a problem as well when trying to access the filesystem
// to read the Access file, but the API does not give you another option
// Probably deploying (https://docs.aws.amazon.com/lambda/latest/dg/lambda-java.html)
// your lambda function as a container (https://docs.aws.amazon.com/lambda/latest/dg/java-image.html) 
// and include your database file
Database db = DatabaseBuilder.open(new File("java-runtime/src/access_db_file.accdb"));
System.out.println(db.getTableNames());
String filename = "table_name" + System.currentTimeMillis() + ".csv";
// Instead of writing to a file, write to a byte array through a writer
try (ByteArrayOutputStream output = new ByteArrayOutputStream();
     BufferedWriter writer = new BufferedWriter(
         new OutputStreamWriter(output));
) {
  // Dump data
  ExportUtil.exportWriter(db, "table_name", writer);
  // Just in case
  writer.flush();
  // Get actual information
  byte[] data = output.toByteArray();
  // Save data to S3: please, consider refactor and organize the code
  S3Client s3 = ...; // Initialize as appropriate
  String bucketName = "your-bucket";
  String objectKey = filename; // object key, same as filename, for example
  // Perform actual S3 request
  PutObjectResponse response = s3.putObject(
    PutObjectRequest.builder()
      .bucket(bucketName)
      .key(objectKey)
      .build(),
    RequestBody.fromBytes(data)
  );
} catch (IOException e) {
  e.printStackTrace();
}

С совершенно другой точки зрения проблема может быть вызвана тем, что table_name является связанная таблица. Когда вы создаете связанную таблицу, вам необходимо указать путь к связанной информации: в вашем случае, вероятно, эта информация хранится в C:\Users\john.doe.ctr\Desktop\Work\table_name на исходном компьютере вашего клиента.

Если у вас есть программа MS Access, вы можете проверить, действительно ли это проблема, с помощью Диспетчер связанных таблиц.

Если у вас нет программы MS Access, вы можете также используйте класс Database. Пожалуйста, рассмотрите следующий пример:

Database db = DatabaseBuilder.open(new File("java-runtime/src/access_db_file.accdb"));
Table table = db.getTable("table_name");
boolean isLinkedTable = db.isLinkedTable(table);

Если таблица связана, вам нужны две вещи: с одной стороны, сама связанная информация, а с другой, вам нужно обеспечить удобную реализацию LinkResolver, вероятно, путем расширения CustomLinkResolver. Этот интерфейс в основном предоставляет вам возможность сопоставить расположение связанной таблицы с другим путем. Пожалуйста, обратите внимание на обзор этот тест для удобного примера такой реализации.

Например, подумайте примерно так:

public class RemapLinkResolver implements LinkResolver {

  // Maintain a correspondence between the original linked db file
  // and the same db in your new filesystem 
  private Map<String, String> dbLinkeeFileRemap = new HashMap<>();

  public void remap(String originalLinkeeFileName, String newLinkeeFileName) {
    this.dbLinkeeFileRemap.put(originalLinkeeFileName, newLinkeeFileName);
  }

  @Override
  public Database resolveLinkedDatabase(Database linkerDb,
                                        String linkeeFileName)
    throws IOException {
    // if linker is read-only, open linkee read-only
    boolean readOnly = ((linkerDb instanceof DatabaseImpl) ?
                       ((DatabaseImpl)linkerDb).isReadOnly() : false);
    String newLinkeeFileName = this. dbLinkeeFileRemap.get(linkeeFileName);
    if (newLinkeeFileName != null) {
      return new DatabaseBuilder(new File(newLinkeeFileName))
        .setReadOnly(readOnly).open();
    }

    // Fallback to default
    return LinkResolver.DEFAULT.resolveLinkedDatabase(linkerDb, linkeeFileName);
  }
}

Затем используйте его в своем коде:

Database db = DatabaseBuilder.open(new File("java-runtime/src/access_db_file.accdb"));
RemapLinkResolver linkResolver = new RemapLinkResolver();
linkResolver.remap(
  "C:\Users\john.doe.ctr\Desktop\Work\table_name",
  "java-runtime/src/table_name.accdb"
);
db.setLinkResolver(linkResolver);
// Continue as usual

Надеюсь, вы поняли идею, пожалуйста, адаптируйте пути и, в целом, код соответствующим образом.

person jccampanero    schedule 02.05.2021
comment
это не работает - выдает ту же ошибку, что и раньше. Не думаю, что это имеет какое-то отношение к тому, как я писал в CSV, но вместо этого проблема с getTable. Я включил трассировку стека выше! - person Ravmcgav; 03.05.2021
comment
Большое спасибо за отзыв @Ravmcgav. Да, это действительно возможность. Я обновил свой ответ дополнительной информацией, связанной с использованием связанных таблиц. Я надеюсь, что это помогает. - person jccampanero; 03.05.2021
comment
@DerekO Ravmcgav Верно ли предположение о связанных таблицах? Удалось ли вам протестировать решение на основе LinkResolver? Это сработало? Пожалуйста, имейте в виду, что я не смог на самом деле протестировать код: при необходимости попробуйте отладить предложенный метод resolveLinkedDatabase, чтобы иметь возможность правильно сопоставить информацию, предоставленную Jackcess, и фактический альтернативный путь к базе данных. Я надеюсь, что это помогает. - person jccampanero; 07.05.2021
comment
Большое спасибо @Derek_O. Но, приятель, ты действительно решил проблему? Действительно ли проблема связана со связанными таблицами? - person jccampanero; 11.05.2021
comment
Эй, извини, просто возвращаюсь к этому ... Я так и не понял. После вызова вашего класса getTable() больше не происходит сбой, но извлекается таблица null - person Ravmcgav; 15.05.2021
comment
Нет нужды извиняться @Ravmcgav. Я понимаю:. Если вы отлаживаете код в resolveLinkedDatabase с вашей фактической базой данных, предоставляет ли параметр linkeeFileName значимую информацию? Сопоставляется ли это значение соответствующим образом? Я предполагаю, что это невозможно, но не могли бы вы поделиться своим фактическим файлом доступа? без данных конечно, просто структура таблиц. - person jccampanero; 15.05.2021
comment
Что вы имеете в виду под структурой? Нравятся имена таблиц? linkeeFileName не дает много значимой информации, но я считаю, что сопоставляю ее правильно! - person Ravmcgav; 17.05.2021
comment
Да, именно @Ravmcgav, вот что я имею в виду. Мне жаль слышать, что он не работает должным образом. Пожалуйста, не могли бы вы поделиться копией вашей фактической базы данных? Просто минимальный воспроизводимый пример для проверки ошибки, без данных, конечно, и только с таблицей, которая вызывает проблему. Является ли это возможным? Я думаю, это может быть полезно. - person jccampanero; 18.05.2021
comment
да, пожалуйста, попробуйте воспроизвести - дайте мне знать, как я могу помочь! - person Ravmcgav; 19.05.2021

Совет Jcc выглядит довольно солидно. Можете ли вы также попробовать/подтвердить/доработать некоторые из следующих вопросов?

  1. Во-первых, вы сказали, что код на ВАШЕМ Mac, но путь к файлу принадлежит ДРУГОМУ пользователю. Вы каким-то образом неявно или явно ссылаетесь на папку, которая недоступна на вашем Mac, и, следовательно, вы не можете получить доступ к недопустимому пути к папке? Jackcess, вероятно, будет в порядке, создав файл в папке, но если фрагмент пути к родительской папке для экспорта отсутствует, возможно, он не может или не создает необходимые подпапки для создания файла и выдает ошибку неявно?

  2. Есть ли дополнительная конфигурация, необходимая Lambda для доступа к путям к папкам в предыдущем комментарии, учитывая, что я предполагаю, что она работает в облачном стеке?

  3. Требует ли jackes инициализировать/создать файл на месте, прежде чем он откроет его для записи в файл..? Не похоже, что это из API.

4. Можете ли вы временно жестко закодировать новый файл (table_name + dateOfExtraction + .csv), чтобы он был чем-то простым, например, новым файлом (steve.csv). Мне особенно любопытно посмотреть, обновляется ли ваше сообщение об ошибке соответствующим образом, чтобы жаловаться, что он не может получить доступ к steve.csv в этой папке.

person Atmas    schedule 08.05.2021