一直在处理一段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
我希望你能理解这个想法,请适当地调整路径和代码。
有一件事是你说你的mac上有代码,但文件路径来自另一个用户。您是否以某种方式隐式或显式引用了Mac上不可用的文件夹,因此无法访问无效的文件夹路径?jaccess在文件夹中创建文件可能是可以的,但如果导出的父文件夹路径中缺少一块,那么它可能无法或没有建立创建文件所需的子文件夹,并隐式地抛出错误?
考虑到Lambda在云堆栈中运行,它是否需要额外的配置来访问前面评论中的文件夹路径?
jackess是否要求您在打开文件进行文件写入之前将文件初始化/创建到位。。?从API看来并不是这样。
4.是否可以临时硬编码新文件("table_name"+"dateOfExtraction+".csv"(";改为简单的新文件("steve.csv"(。我特别想看看你的错误消息是否会相应更新,抱怨它无法访问该文件夹中的steve.csv。