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つのソリューションがあり、それらはさまざまなパフォーマンスを持っているので、あなたに最も適したものを選ぶことができます.

ファイルにインデックスを付ける

このルール ファイルの逆インデックスを作成し、ファイルを変更するすべての操作に対してそれを最新の状態に保つことができます。もちろん、単語インデックスは 1 つのファイルに限定され、その中の唯一の単語は一意の UUID になります。RandomAccess ファイルを使用して、特定のオフセットからすばやく read() を実行できます。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

この特定の問題を解決するために正規表現を使用することはありません。ファイル全体をメモリにロードし、処理し、再書き込みする必要があります。それは本質的に悪いことではありませんが、十分な大きさのファイルがある場合は、ストリーム ベースのソリューションの方がおそらく優れています。

あなたがすることは、入力ファイルを一度に 1 行ずつ処理し、次のブール値を維持することです。

  • true目的のルールの宣言ヘッダーに一致する行を見つけると、 になります。
  • で、一致する行を見つけると にfalseなります。trueend

ブール値が に設定されている間に発生したすべての行を破棄しtrue、他のすべての行を一時出力ファイル (たとえば、で作成) に書き込みますFile#createTempFile

各行で、ブール値がtrueの場合は無視します。それ以外の場合は、一時出力ファイルに書き込みます。

プロセスの最後に、 を使用して入力ファイルを一時出力ファイルで上書きしますFile#renameTo

このソリューションには、アトミックであるという追加の利点があることに注意してください。処理中にエラーが発生した場合でも、入力ファイルが部分的に書き込まれるリスクはありません。完全に上書きされるか、まったく上書きされないため、予期しないIOExceptions から保護されます。

次のコードは、それを実装する方法を示しています。これは必ずしも完全な実装ではありませんが、定型コードの途中で失われたアルゴリズムを説明する必要があります。

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 に答える