java - 将 accessdb 表导出到 csv

标签 java ms-access aws-lambda ucanaccess jackcess

一直在编写一段 Java 代码,将一些表从 accessdb 导出到 CSV。我想将此代码部署为 Lambda 函数。我尝试过使用 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:给定文件不存在:C:\Users\john.doe.ctr\Desktop\Work\table_name

我正在 Mac 上运行我的代码,此文件路径来自为我提供数据库的用户。这是某种权限错误吗?我应该只使用 UCanAccess 吗?我无法使用任何 UCanAccess 命令行工具,我必须在 lambda 中运行它。 System.out.println(db.getTableNames()); 行完全按照预期工作,并打印 accessdb 中所有表名的列表。

最佳答案

代码中可能存在多个问题。

首先,您使用 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_namelinked table 引起的。 。创建链接表时,您需要定义链接信息的路径:在您的情况下,此信息可能存储在 C:\Users\john.doe.ctr\Desktop\Work\table_name > 在您客户的原始计算机中。

如果您有 MS Access 程序,您可以借助 Linked Table Manager 来验证这是否是实际问题。 .

如果您没有 MS Access 程序,您可以use the Database class以及。请考虑以下示例:

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 的便捷实现。接口(interface),可能通过扩展 CustomLinkResolver 。该接口(interface)基本上使您能够将链接表的位置映射到不同的路径。请考虑评论this test获取此类实现的方便示例。

例如,考虑这样的事情:

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

我希望您能理解,请适当调整路径和代码。

关于java - 将 accessdb 表导出到 csv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67322909/

相关文章:

java - 没有默认构造函数的 Autowire Bean,使用配置注释

java - 从 java 连接到 MS Access

ms-access - msaccess如何在没有gui的情况下在后台运行

javascript - AWS Lambda 和 Node.js 函数未被调用

python - “SSL: CERTIFICATE_VERIFY_FAILED” 发布 MQTT、AWS IoT 时出错

java - 使用 Nd4j 计算协方差矩阵

java - 不使用默认构造函数反序列化 JSON

java - AWS Lambda Java,连接到MySQL RDS

java - 为什么我们应该在 WSDL 中有 SOAP 位置?

mysql - MS Access 和 MySQL 之间的 SQL 查询差异