我不会使用正则表达式来解决这个特殊问题——它需要将整个文件加载到内存中,处理它并重写它。这本来就不是坏事,但是如果您有足够大的文件,则基于流的解决方案可能会更好。
您要做的是一次处理一行输入文件并保持一个布尔值:
true
当您找到与所需规则的声明标题匹配的行时变为。
- 变成
false
当它的时候true
,你找到一条匹配的线end
。
丢弃布尔值设置为 时遇到的所有行true
,将所有其他行写入临时输出文件(例如,使用 创建的File#createTempFile
)。
对于每一行,如果您的布尔值为true
,请忽略它。否则,将其写入临时输出文件。
在该过程结束时,使用临时输出文件覆盖您的输入文件File#renameTo
。
请注意,此解决方案具有原子性的附加优势:如果在处理过程中发生错误,则不会有部分写入输入文件的风险。它将被完全覆盖或根本不覆盖,这可以保护您免受意外IOException
的影响。
以下代码演示了如何实现它。它不一定是一个完美的实现,但它应该说明算法 - 在所有样板代码中间的某个地方丢失。
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);
}