Java 查找并替换MS Access表行中不工作的文本
给定一个目录,我的应用程序使用jackcessapi遍历并加载Java 查找并替换MS Access表行中不工作的文本,java,javafx,task,jackcess,Java,Javafx,Task,Jackcess,给定一个目录,我的应用程序使用jackcessapi遍历并加载.mdbmsaccessdbs。在每个数据库中,都有一个名为GCMT\u CMT\u PROPERTIES的表,其中有一个名为CMT\u data的列,其中包含一些文本。我还有一个Mapper对象(它本质上类似于Map,但允许重复键),当从字符串中替换某个单词时,我将其用作字典 因此,例如,如果mapper包含fox->dog,那么句子:“fox jumps”变成“dog jumps” 我将为这个项目设计如下: 1. Given a
.mdb
msaccessdbs。在每个数据库中,都有一个名为GCMT\u CMT\u PROPERTIES
的表,其中有一个名为CMT\u data
的列,其中包含一些文本。我还有一个Mapper
对象(它本质上类似于Map
,但允许重复键),当从字符串中替换某个单词时,我将其用作字典
因此,例如,如果mapper
包含fox->dog
,那么句子:“fox jumps”
变成“dog jumps”
我将为这个项目设计如下:
1. Given a directory, traverse all subdirectories and load all .mdb files into a File[].
2. For each db file in File[], create a Task<Void> called "TaskMdbUpdater" and pass it the db file.
3. Dispatch and run each task as it is created (see 2. above).
更新1:
为了验证我的自定义StringUtils.findAndReplace
逻辑,我执行了以下单元测试(在JUnit中),该测试正在通过:
@Test
public void simpleReplacementTest() {
// Construct a test mapper/dictionary
List<aMap> aMaps = new ArrayList<aMap>();
aMaps.add(new aMap(new String[] {"fox", "dog"})); // {K, V} = K -> V
Mapper mapper = new Mapper(aMaps);
// Perform replacement
String corpus = "The fox jumps";
String updatedCorpus = StringUtils.findAndReplace(corpus, mapper);
assertEquals("The dog jumps", updatedCorpus);
}
这是我日志中的一个小练习。正如你所看到的,在打开桌子之后,它似乎没有做任何事情,这让我有点困惑:
INFO (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Located the following directories under specified MOIS parent which contains an .mdb file:
[01_Parent_All_Safe_Test[ RV_DMS_0041RV_DMS_0001RV_DMS_0003RV_DMS_0005RV_DMS_0007RV_DMS_0012RV_DMS_0013RV_DMS_0014RV_DMS_0016RV_DMS_0017RV_DMS_0018RV_DMS_0020RV_DMS_0023RV_DMS_0025RV_DMS_0028RV_DMS_0029RV_DMS_0031RV_DMS_0033RV_DMS_0034RV_DMS_0035RV_DMS_0036RV_DMS_0038RV_DMS_0039RV_DMS_0040 ]]
...
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Created new task: NAMEMAP.logic.TaskMdbUpdater@4cfe46fe
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Created new worker: Thread[Thread-22,5,main]
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Set worker Thread[Thread-22,5,main] as daemon
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Dispatching worker: Thread[Thread-22,5,main]
...
DEBUG (16-02-2017 17:28:00) [Thread-22] NAMEMAP.logic.TaskMdbUpdater.call(): Opened database: RV_DMS_0023.mdb
DEBUG (16-02-2017 17:28:00) [Thread-22] NAMEMAP.logic.TaskMdbUpdater.call(): Opening table: GCMT_CMT_PROPERTIES
在这一点之后,日志中不再有任何条目,处理器在100%负载时出现峰值,直到我强制终止应用程序为止。这可能意味着程序会陷入无限while循环中-但是如果是这样,那么文件中不应该有日志条目吗
更新2
好的,通过将log
TRACE
打印到stdio
中,我进一步缩小了问题的范围。我的performFindAndReplaceOnString
似乎效率非常低,而且它永远不会超过这些dbs的第一行,因为它只是在磨磨长字符串。关于如何有效地为这个用例执行字符串替换,有什么建议吗 您是否确保在退出应用程序之前正确地.close()
数据库对象?我相信是这样的。如果我可以提请您注意类的调用方法任务的bupdater
,您可以看到我正在关闭在该方法开始时打开的数据库
对象<代码>。。。catch(NoSuchElementException e){e.printStackTrace();}db.close();}catch(异常e){e.printStackTrace();}返回null代码>您是否确认findAndReplace逻辑实际上正确修改了字符串?是的,我的单元测试通过了,请参阅上面的更新1^“关于如何有效地执行此用例的字符串替换的任何建议?”-一些想法。您是否确保.close()
在您的应用程序退出之前,数据库对象是否正确运行?我相信是这样。如果我可以提请您注意类的调用方法任务的bupdater
,您可以看到我正在关闭在该方法开始时打开的数据库
对象<代码>。。。catch(NoSuchElementException e){e.printStackTrace();}db.close();}catch(异常e){e.printStackTrace();}返回null代码>您是否确认findAndReplace逻辑实际上正确地修改了字符串?是的,我的单元测试通过了,请参阅上面的更新1^“关于如何有效地执行此用例的字符串替换的任何建议?”-一些想法。
/**
* Updates a given .mdb database according to specifications defined internally.
* @since 2.2
*/
public class TaskMdbUpdater extends Task<Void> {
private final String TABLE_NAME = "GCMT_CMT_PROPERTIES";
private final String COLUMN_NAME = "cmt_data";
private DatabaseBuilder dbPackage;
private Mapper mapper;
public TaskMdbUpdater(DatabaseBuilder dbPack, Mapper mapper) {
super();
this.dbPackage = dbPack;
this.mapper = mapper;
}
@Override
protected Void call() {
try {
// Controller.dprint("TaskMdbUpdater", "Worker: " + Thread.currentThread().getName() + " running");
// Open db and extract Table
Database db = this.dbPackage
.open();
Logger.debug("Opened database: {}", db.getFile().getName());
Table table = db.getTable(TABLE_NAME);
Logger.debug("Opening table: {}", table.getName());
Iterator<Row> tableRows = table.iterator();
// Controller.dprint("TaskMdbUpdater", "Updating database: " + db.getFile().getName());
int i=0;
try {
while( tableRows.hasNext() ) {
// Row is basically a<code> Map<Column_Name, Value> </code>
Row cRow = tableRows.next();
Logger.trace("Current row: {}", cRow);
// Controller.dprint(Thread.currentThread().getName(), "Database name: " + db.getFile().getName());
// Controller.dprint("TaskMdbUpdater", "existing row: " + cRow.toString());
String str = cRow.getString(COLUMN_NAME);
Logger.trace("Row {} column field contents (before find/replace): {}", i, str);
String newStr = performFindAndReplaceOnString(str);
Logger.trace("Row {} column field contents (after find/replace): {}", i, newStr);
cRow.put(COLUMN_NAME, newStr);
Logger.debug("Updating field in row {}", i);
Row newRow = table.updateRow(cRow); // <code>updateRow</code> returns the new, updated row. Ignoring this.
Logger.debug("Calling updateRow on table with modified row");
// Controller.dprint("TaskMdbUpdater", "new row: " + newRow.toString());
i++;
Logger.trace("i = {}", i);
}
} catch(NoSuchElementException e) {
// e.printStackTrace();
Logger.error("Thread has iterated past number of rows in table", e);
}
Logger.info("Iterated through {} rows in table {}", i, table.getName());
db.close();
Logger.debug("Closing database: {}", db.getFile().getName());
} catch (Exception e) {
// e.printStackTrace();
Logger.error("An error occurred while attempting to update row value", e);
}
return null;
}
/**
* @see javafx.concurrent.Task#failed()
*/
@Override
protected void failed() {
super.failed();
Logger.error("Task failed");
}
@Override
protected void succeeded() {
Logger.debug("Task succeeded");
}
private String performFindAndReplaceOnString(String str) {
// Logger.trace("OLD: [" + str + "]");
String updatedStr = null;
for(int i=0; i<mapper.getMappings().size(); i++) {
// loop through all parameter names in mapper to search for in str.
updatedStr = findAndReplace(str, this.mapper);
}
// Logger.trace("NEW: [" + updatedStr + "]");
return updatedStr;
}
}
INFO (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Located the following directories under specified MOIS parent which contains an .mdb file:
[01_Parent_All_Safe_Test[ RV_DMS_0041RV_DMS_0001RV_DMS_0003RV_DMS_0005RV_DMS_0007RV_DMS_0012RV_DMS_0013RV_DMS_0014RV_DMS_0016RV_DMS_0017RV_DMS_0018RV_DMS_0020RV_DMS_0023RV_DMS_0025RV_DMS_0028RV_DMS_0029RV_DMS_0031RV_DMS_0033RV_DMS_0034RV_DMS_0035RV_DMS_0036RV_DMS_0038RV_DMS_0039RV_DMS_0040 ]]
...
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Created new task: NAMEMAP.logic.TaskMdbUpdater@4cfe46fe
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Created new worker: Thread[Thread-22,5,main]
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Set worker Thread[Thread-22,5,main] as daemon
DEBUG (16-02-2017 17:27:59) [Thread-9] NAMEMAP.logic.TaskDatabaseTaskDispatcher.call(): Dispatching worker: Thread[Thread-22,5,main]
...
DEBUG (16-02-2017 17:28:00) [Thread-22] NAMEMAP.logic.TaskMdbUpdater.call(): Opened database: RV_DMS_0023.mdb
DEBUG (16-02-2017 17:28:00) [Thread-22] NAMEMAP.logic.TaskMdbUpdater.call(): Opening table: GCMT_CMT_PROPERTIES