考虑到我有一个以下列格式存储规则的数据文件:
//some header info
//more header info
//Rule: some_uuid_1234
rule "name"
data
data
data
end
//Rule: some_uuid_5678
rule "name2"
data
data
data
end
现在,我希望能够根据ID号给read(id)
或delete(id)
规则。因此,我的问题是,如何选择和删除规则(可能使用正则表达式),然后从文件中删除此特定规则,而不更改其他任何规则。
答案 0 :(得分:0)
只需将选择/删除功能中的<some_id>
替换为实际的真实ID号。
//Rule: <some_id>.+?rule.+?end
注意:不要忘记SingleLine选项。
答案 1 :(得分:0)
有两个我能想到的解决方案,它们的性能各不相同,所以你可以选择最适合你的方案。
您可以为此规则文件编写inverted index,并为修改该文件的任何操作保持更新。当然,您的单词索引将限制为一个文件,其中唯一的单词将是唯一的UUID。您可以使用RandomAccess文件从给定的偏移量快速读取()。 delete()操作可以覆盖目标规则,直到遇到单词“end”。此解决方案需要更多工作,但您可以立即检索值。
您也可以读取文件中的每一行,并将其与符合规则UUID的正则表达式匹配。继续阅读,直到你达到规则的“结束”并返回它。删除将涉及在您知道所需索引后覆盖规则。这个解决方案很容易编写,但性能会很差。有很多IO,可能成为瓶颈。 (你也可以将整个文件加载到内存中,并在整个字符串上运行一个正则表达式,具体取决于文件/字符串的大小。虽然这可能很快变得难看。)
无论您选择哪种解决方案,您可能还需要考虑文件级锁定以及它如何影响CRUD操作。如果此设计尚未实施,请考虑将规则移至数据库。
答案 2 :(得分:0)
我不会使用正则表达式来解决这个特殊问题 - 它需要将整个文件加载到内存中,处理它并重写它。这本身并不坏,但如果你有足够大的文件,基于流的解决方案可能会更好。
您要做的是一次处理一行输入文件并保持一个布尔值:
true
。false
时变为true
,并且您找到与end
匹配的行。丢弃布尔值设置为true
时遇到的所有行,将所有其他行写入临时输出文件(例如,使用File#createTempFile
创建)。
对于每一行,如果您的布尔值为true
,请忽略它。否则,将其写入临时输出文件。
在流程结束时,使用File#renameTo
使用临时输出文件覆盖输入文件。
请注意,此解决方案具有原子的附加优势:如果在处理过程中发生错误,则不会部分写入输入文件。它将被完全覆盖或根本不被覆盖,从而保护您免受意外IOException
的攻击。</ p>
以下代码演示了如何实现它。它不一定是一个完美的实现,但它应该说明算法 - 在所有样板代码的中间丢失。
public void deleteFrom(String id, File file) throws IOException {
BufferedReader reader;
String line;
boolean inRule;
File temp;
PrintWriter writer;
reader = null;
writer = null;
try {
// Streams initialisation.
temp = File.createTempFile("delete", "rule");
writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(temp), "utf-8")));
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
inRule = false;
// For each line in the file...
while((line = reader.readLine()) != null) {
// If we're parsing the rule to delete, we're only interested in knowing when we're done.
if(inRule) {
if(line.trim().equals("end"))
inRule = false;
}
// Otherwise, look for the beginning of the targetted rule.
else if(line.trim().equals("rule \"" + id + "\""))
inRule = true;
// Normal line, we want to keep it.
else
writer.println(line);
}
}
// Stream cleanup.
finally {
if(reader != null)
reader.close();
if(writer != null)
writer.close();
}
// We're done, copy the new file over the old one.
temp.renameTo(file);
}