我正在尝试使用Java库Jackcess从Access数据库中读取数据。该数据库有几个表和查询,其中一些是指向文件系统上Excel表的链接表。
我看到我可以使用LinkResolver
来拦截链接数据的解析,但它需要一个完整的数据库,而不仅仅是一个表的数据。
我可以轻松使用Apache POI打开Excel文件并提取必要的数据,但我不知道如何在LinkResolver中传递数据。
提供Excel文件位置或从Excel文件读取数据并将其传递回Jackcess以便成功加载链接数据的最简单方法是什么?
答案 0 :(得分:2)
目前,LinkResolver API仅用于从其他数据库加载“远程”表实例。它不是为任何类型的外部文件构建的通用API。您当然可以通过Jackcess项目提交功能请求。
更新:
自2.1.7版本起,jackcess提供了CustomLinkResolver实用程序,以便于从非访问数据库的文件中加载链接表(使用临时数据库)。
答案 1 :(得分:1)
我想出了以下初始实现的LinkResolver,它使用Excel文件中的内容构建临时数据库。它仍然缺少临时数据库的关闭处理和临时文件删除等功能,但它似乎可以用于基本目的。
/**
* Sample LinkResolver which reads the data from an Excel file
* The data is read from the first sheet and needs to contain a
* header-row with column-names and then data-rows with string/numeric values.
*/
public class ExcelFileLinkResolver implements LinkResolver {
private final LinkResolver parentResolver;
private final String fileNameInDB;
private final String tableName;
private final File excelFile;
public ExcelFileLinkResolver(LinkResolver parentResolver, String fileNameInDB, File excelFile, String tableName) {
this.parentResolver = parentResolver;
this.fileNameInDB = fileNameInDB;
this.excelFile = excelFile;
this.tableName = tableName;
}
@Override
public Database resolveLinkedDatabase(Database linkerDb, String linkeeFileName) throws IOException {
if(linkeeFileName.equals(fileNameInDB)) {
// TODO: handle close or create database in-memory if possible
File tempFile = File.createTempFile("LinkedDB", ".mdb");
Database linkedDB = DatabaseBuilder.create(Database.FileFormat.V2003, tempFile);
try (Workbook wb = WorkbookFactory.create(excelFile, null, true)) {
TableBuilder tableBuilder = new TableBuilder(tableName);
Table table = null;
List<Object[]> rows = new ArrayList<>();
for(org.apache.poi.ss.usermodel.Row row : wb.getSheetAt(0)) {
if(table == null) {
for(Cell cell : row) {
tableBuilder.addColumn(new ColumnBuilder(cell.getStringCellValue()
// column-names cannot contain some characters
.replace(".", ""),
DataType.TEXT));
}
table = tableBuilder.toTable(linkedDB);
} else {
List<String> values = new ArrayList<>();
for(Cell cell : row) {
if(cell.getCellTypeEnum() == CellType.NUMERIC) {
values.add(Double.toString(cell.getNumericCellValue()));
} else {
values.add(cell.getStringCellValue());
}
}
rows.add(values.toArray());
}
}
Preconditions.checkNotNull(table, "Did not have a row in " + excelFile);
table.addRows(rows);
} catch (InvalidFormatException e) {
throw new IllegalStateException(e);
}
return linkedDB;
}
return parentResolver.resolveLinkedDatabase(linkerDb, linkeeFileName);
}
}