0

考虑我有一个数据文件存储规则,格式如下:

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

4

3 回答 3

0

我能想到 2 种解决方案,它们的性能各不相同,因此您可以选择最适合您的一种。

索引文件

您可以为此规则文件编写一个倒排索引,并为修改该文件的任何操作保持更新。当然,您的单词索引将被限制在一个文件中,并且其中唯一的单词将是唯一的 UUID。您可以使用 RandomAccess 文件从给定的偏移量快速读取()。delete() 操作可以覆盖目标规则,直到遇到单词'end'。此解决方案需要更多工作,但您可以立即检索值。

使用正则表达式

您也可以读取文件中的每一行并将其与匹配您的规则 UUID 的正则表达式模式匹配。继续阅读,直到您到达规则的“结尾”并返回它。一旦您知道所需的索引,删除将涉及覆盖规则。这个解决方案很容易编写,但性能会很糟糕。有很多 IO,它可能会成为瓶颈。(您也可以将整个文件加载到内存中并在整个字符串上运行正则表达式,具体取决于文件/字符串的预期大小。不过,这可能会很快变得丑陋。)

无论您选择哪种解决方案,您可能还需要考虑文件级锁以及它如何影响 CRUD 操作。如果此设计尚未实施,请考虑将规则移至数据库。

于 2013-03-21T15:18:16.790 回答
0

只需用<some_id>实际的真实 ID 号替换您的选择/删除功能。

//Rule: <some_id>.+?rule.+?end

注意:不要忘记 SingleLine 选项。

于 2013-03-21T15:00:22.737 回答
0

我不会使用正则表达式来解决这个特殊问题——它需要将整个文件加载到内存中,处理它并重写它。这本来就不是坏事,但是如果您有足够大的文件,则基于流的解决方案可能会更好。

您要做的是一次处理一行输入文件并保持一个布尔值:

  • 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);
}
于 2013-03-21T15:22:26.930 回答