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();
    }
}

该文件保持打开状态。

如果有多个线程,则必须在 write 方法中进行同步(但无论如何都必须考虑这一点)。

如果文件保持打开状态,则可能存在以下问题:

  • 从理论上讲,您可能会用完文件句柄。这些可能是有限的(ulimit -a例如,参见 Linux 系统):每个记录器使用一个句柄。

  • 如果使用FileWriter不带缓冲的 a,则每次调用write. 这可能会很慢。

  • 如果在 aBufferedWriter上使用 a 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 应用程序,您可以closeServletContextListener(method contextDestroyed) 中调用该方法。

最大的性能提升可能是BufferedWriter. 如果您为每个写操作打开/关闭它,这个优势就会丢失,因为close必须调用flush. 因此,将打开文件与缓冲结合起来会非常快。

于 2013-07-08T19:04:00.063 回答
0

我不确定记录器框架如何管理文件连接,但我可以建议您的一种方法是将其缓存fileWriter一个static实例中,而不关闭它。这样,您的程序将保持对该文件的实时引用,并且不会创建新的连接以再次写入。

FileWriter这种方法的一个缺点是,即使没有写入活动,文件也会被保存。这意味着,FileWriter锁定文件,当文件被锁定时,没有其他进程可以在文件上写入。

于 2013-07-08T18:31:03.190 回答