1

ファイルにテキストを書き込むための Java コードを書きたい場合、通常は次のようになります。

File logFile = new File("/home/someUser/app.log");
FileWriter writer;

try {
    writer = new FileWriter(logFile, true);

    writer.write("Some text.");

    writer.close();
} catch (IOException e) {
    e.printStackTrace();
}

しかし、連続して大量の書き込み操作を行っている場合はどうなるでしょうか。毎秒数十、数百、さらには数千の書き込み操作をログに記録している場合はどうなりますか?

データベース (および JDBC) が「永続的な接続」(複数の呼び出しで開いたままになる接続) を許可するのと同じように、複数の呼び出しで開いたり閉じたりする必要のない「永続的なストリーム」を持つ方法はありwrite(String)ますか? もしそうなら、これはどのように機能しますか?注意が必要な落とし穴/注意事項は何ですか? 前もって感謝します!

4

2 に答える 2

1

この実装を見ると

class Logger {
    private final BufferedWriter w;

    public Logger(final File file) throws IOException {
        this.w = new BufferedWriter(new FileWriter(file));
        LoggerRegistry.register(this);
    }

    public void log(String s) throws IOException {
        synchronized (this.w) {
            this.w.write(s);
            this.w.write("\n");
        }
    }

    public void close() throws IOException {
        this.w.close();
    }
}

ファイルは開いたままです。

複数のスレッドがある場合は、書き込みメソッドで同期する必要があります (ただし、これはどのような場合でも考慮する必要があります)。

ファイルが開いたままの場合、次の問題が考えられます。

  • 理論的には、ファイル ハンドルが不足する可能性があります。これらは制限される場合があります ( ulimit -aLinux システムの例を参照)。各ロガーは 1 つのハンドルを消費します。

  • バッファリングなしでを使用するFileWriterと、 の呼び出しごとに I/O 呼び出しが発生しますwrite。これはかなり遅くなる可能性があります。

  • BufferedWriterの上にを使用する場合FileWriterは、プログラムの最後で適切に閉じられるようにする必要があります。そうしないと、バッファー内の残りのコンテンツがディスクに書き込まれない可能性があります。したがって、すべてのロガーを正しく閉じる必要があるプログラムの周りに try/finally ブロックが必要です。

したがって、すべてのロガーを登録する必要があります。これは簡略化されたバージョンです (スレッドセーフではありません)。

class LoggerRegistry {
    private final static List<Logger> loggers = new ArrayList<Logger>();

    public static void register(Logger l) {
        loggers.add(l);
    }

    public static void close() {
        for (Logger l : loggers) {
            try {
                l.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

これをメインプログラムで次のように使用します。

public static void main(String[] args) throws IOException {
    try {
        final Logger l = new Logger(new File("/tmp/1"));
        l.log("Hello");

        // ... 

    } finally {
        LoggerRegistry.close();
    }
}

Web アプリケーションがある場合は、closeメソッドをServletContextListener(method contextDestroyed) で呼び出すことができます。

最大のパフォーマンスの向上は、おそらくBufferedWriter. closeを呼び出す必要があるため、書き込み操作ごとに開いたり閉じたりすると、この利点が失われますflush。したがって、開いているファイルとバッファリングを組み合わせると、非常に高速になります。

于 2013-07-08T19:04:00.063 に答える
0

ロガー フレームワークがファイル接続をどのように管理するかはわかりませんが、インスタンスを閉じずにインスタンスにキャッシュすることをお勧めします。このようにして、プログラムはファイルへのライブ参照を保持し、再度書き込むための新しい接続を作成しません。fileWriterstatic

このアプローチの欠点の 1 つFileWriterは、書き込みアクティビティがない場合でもファイルが保持されることです。これは、がファイルFileWriterロックし、ロックされている間、他のプロセスがファイルに書き込むことができないことを意味します。

于 2013-07-08T18:31:03.190 に答える