一直在编写一段 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_name
是 linked 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/