将accessdb表导出到csv



一直在处理一段java代码,以便将一些表从accessdb导出到CSV。我想将此代码部署为Lambda函数。我试过使用Jackess,但下面的

        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:Usersjohn.doe.ctrDesktopWorktable_name

我在mac上运行我的代码,这个文件路径来自为我提供DB的用户。这是某种权限错误吗?我应该使用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_name是一个链表而引起的。创建链接表时,需要定义链接信息的路径:在您的情况下,这些信息可能存储在客户端原始计算机的C:Usersjohn.doe.ctrDesktopWorktable_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:Usersjohn.doe.ctrDesktopWorktable_name",
  "java-runtime/src/table_name.accdb"
);
db.setLinkResolver(linkResolver);
// Continue as usual

我希望你能理解这个想法,请适当地调整路径和代码。

Jccs的建议看起来相当可靠。你也可以试着/确认/详细说明下面的一些内容吗?
  1. 有一件事是你说你的mac上有代码,但文件路径来自另一个用户。您是否以某种方式隐式或显式引用了Mac上不可用的文件夹,因此无法访问无效的文件夹路径?jaccess在文件夹中创建文件可能是可以的,但如果导出的父文件夹路径中缺少一块,那么它可能无法或没有建立创建文件所需的子文件夹,并隐式地抛出错误?

  2. 考虑到Lambda在云堆栈中运行,它是否需要额外的配置来访问前面评论中的文件夹路径?

  3. jackess是否要求您在打开文件进行文件写入之前将文件初始化/创建到位。。?从API看来并不是这样。

4.是否可以临时硬编码新文件("table_name"+"dateOfExtraction+".csv"(";改为简单的新文件("steve.csv"(。我特别想看看你的错误消息是否会相应更新,抱怨它无法访问该文件夹中的steve.csv。

相关内容

  • 没有找到相关文章