简体   繁体   English

将 accessdb 表导出到 csv

[英]Export accessdb tables to csv

Been working on a snippet of java code to export a few tables from an accessdb to CSVs.一直在研究 java 代码片段,以将一些表从 accessdb 导出到 CSV。 I want to deploy this code as a Lambda function.我想将此代码部署为 Lambda function。 I've tried using Jackcess, but the following我试过使用 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();
        }

throws the error: java.io.FileNotFoundException: given file does not exist: C:\Users\john.doe.ctr\Desktop\Work\table_name引发错误: java.io.FileNotFoundException: given file does not exist: C:\Users\john.doe.ctr\Desktop\Work\table_name

I am running my code on a mac, this filepath is from the user that provided me with the DB.我在 Mac 上运行我的代码,这个文件路径来自为我提供数据库的用户。 Is that some kind of permissions error?这是某种权限错误吗? Should I just use UCanAccess instead?我应该只使用 UCanAccess 吗? I can't use any of the UCanAccess command line tools, I have to run this in a lambda.我不能使用任何 UCanAccess 命令行工具,我必须在 lambda 中运行它。 The System.out.println(db.getTableNames()); System.out.println(db.getTableNames()); line works exactly as expected, and prints a list of all of the tablenames in the accessdb.行完全按预期工作,并打印 accessdb 中所有表名的列表。

There can be several problems in the code.代码中可能存在几个问题。

The first, you are using LocalDateTime.now().toString() as part of the filename of the CSV file in which the information will be saved.首先,您使用LocalDateTime.now().toString()作为将保存信息的 CSV 文件的文件名的一部分。 It will give you something like:它会给你类似的东西:

2021-05-02T23:42:03.282

In some operating systems - you mentioned MacOS but it should allow you to create a file with that name - this name can be a possible cause of problems;在某些操作系统中-您提到了 MacOS,但它应该允许您创建具有该名称的文件-该名称可能是导致问题的原因; please consider use something less error prone like System.currentTimeMillis :请考虑使用不太容易出错的东西,例如System.currentTimeMillis

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

Having said that, please, be aware that in the AWS Lambda function you probably will need to store your results in external storage, typically S3: you have the ability to write to the filesystem but it is usually of relevance when working with temporary files, not with persistent storage.话虽如此,请注意,在 AWS Lambda function 中,您可能需要将结果存储在外部存储中,通常是 S3:您可以写入文件系统,但在处理临时文件时通常是相关的,不是持久存储。 Please, consider for instance the following code snippet.请考虑以下代码片段。

// 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();
}

From a totally different perspective, the problem can be caused because table_name is a linked table .从完全不同的角度来看,问题可能是因为table_name是一个链接表 When you create a linked table, you need to define the path to the linked information: in your case, probably this information is stored in C:\Users\john.doe.ctr\Desktop\Work\table_name in the original computer of your client.创建链接表时,您需要定义链接信息的路径:在您的情况下,此信息可能存储在您的原始计算机中的C:\Users\john.doe.ctr\Desktop\Work\table_name客户。

If you have the MS Access program, you can verify if that is the actual problem with the help of Linked Table Manager .如果您有 MS Access 程序,您可以在Linked Table Manager的帮助下验证这是否是实际问题。

If you do not have the MS Access program, you can use the Database class as well.如果您没有 MS Access 程序,您也可以使用Database class Please, consider the following example:请考虑以下示例:

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

If the table is linked you need two things: on one hand, the linked information itself and, on the other, you need to provide a convenient implementation of the LinkResolver interface, probably by extending CustomLinkResolver .如果表是链接的,您需要两件事:一方面,链接信息本身,另一方面,您需要提供LinkResolver接口的方便实现,可能通过扩展CustomLinkResolver This interface basically provides you the ability to map the location of a linked table to a different path.这个接口基本上为您提供了将链接表的位置指向不同路径的能力。 Please, consider review this test for a convenient example of such as implementation.请考虑查看此测试以获取诸如实现之类的方便示例。

For instance, think in something like this:例如,想想这样的事情:

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);
  }
}

Then, use it in your code:然后,在您的代码中使用它:

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

I hope you get the idea, please, adapt the paths and, in general, the code as appropriate.我希望你明白,请调整路径,一般来说,适当地调整代码。

Jccs advice looks pretty solid. Jccs 的建议看起来很可靠。 Can you try/confirm/elaborate on some of the following, too?您也可以尝试/确认/详细说明以下一些内容吗?

  1. One thing is you said you the code on YOUR mac but the filepath is from ANOTHER user.一件事是你说你的mac上的代码,但文件路径来自另一个用户。 Are you somehow implicitly or explicitly referencing a folder that's not available on your Mac and hence you can't access an invalid folder path?您是否以某种方式隐式或显式引用了 Mac 上不可用的文件夹,因此您无法访问无效的文件夹路径? Jackcess would probably be OK creating a file in a folder, but if a chunk of the parent folder path for the export is missing, maybe it can't or doesn't build up the necessary sub-folders to create the file and throws error implicitly? Jackcess 可能可以在文件夹中创建文件,但是如果缺少用于导出的父文件夹路径的一部分,则它可能无法或没有构建必要的子文件夹来创建文件并引发错误隐含的?

  2. Is there extra configuration the Lambda needs to access the folder paths at play in the previous comment given that I imagine it runs in a cloud stack?考虑到我想象它在云堆栈中运行,Lambda 是否需要访问前面评论中正在播放的文件夹路径?

  3. Does jackess require you initial/create the file in place before it opens it for file writing..? jackess 是否需要您在打开文件以进行文件写入之前初始化/创建文件? Doesn't seem like it from the API. API 看起来不像。

4.Can you temporarily hardcode new File("table_name" + dateOfExtraction + ".csv")" to instead be something simple like new File("steve.csv"). I am specifically curious to see if your error message updates accordingly to complain it can't access steve.csv in that folder. 4.你能不能暂时硬编码 new File("table_name" + dateOfExtraction + ".csv")" 而不是像 new File("steve.csv") 这样简单的东西。我特别想知道你的错误消息是否相应更新抱怨它无法访问该文件夹中的 steve.csv。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM