使用Java中的Regex Expression删除文件的特​​定内容

时间:2013-03-21 14:49:25

标签: java regex

考虑到我有一个以下列格式存储规则的数据文件:

//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)规则。因此,我的问题是,如何选择和删除规则(可能使用正则表达式),然后从文件中删除此特定规则,而不更改其他任何规则。

3 个答案:

答案 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);
}