【问题标题】:FileOutputStream.close is really slow when writing large file写入大文件时 FileOutputStream.close 真的很慢
【发布时间】:2011-12-12 13:36:41
【问题描述】:

我有一个方法可以使用此代码通过 TCP 套接字接收文件:

FileOutputStream fileStream = new FileOutputStream(filename.getName());
while (totalRead < size) {
    if (size - totalRead > CHUNKSIZE) {
        read = getInputStream().read(buffer, 0, CHUNKSIZE);
    } else {
        read = getInputStream().read(buffer, 0, size - totalRead);
    }
    totalRead += read;
    fileStream.write(buffer, 0, read);
    fileStream.flush();

    if (System.currentTimeMillis() > nextPrint) {
        nextPrint += 1000;
        int speed = (int) (totalRead / (System.currentTimeMillis() - startTime));
        double procent = ((double)totalRead / size) * 100;
        gui.setStatus("Reciving: " + filename + " at " + speed + " kb/s, " + procent + "% complete");
    }
}
gui.setStatus("Reciving: " + filename + " complete.");
fileStream.close();

FileOutputStream.close 在接收大文件时需要很长时间,这是为什么呢?如您所见,我在每个收到的块处刷新流..

【问题讨论】:

  • “真的很长时间”有多长?如果在close()之前查看操作系统中的文件大小,它是什么样子的?
  • 在收到 500Mb 文件时关闭大约需要 30 秒。收到文件时我可以看到文件“增长”,因此它在每次刷新时都写入磁盘。
  • 但是在您调用 close 之前它是否正确地获得了最终大小?我的猜测是,它还没有真的在操作系统级别刷新它,但我不能肯定地说。
  • 您的复制循环比必要的复杂得多。你所需要的只是'while ((count = in.read(buffer)) > 0) out,write(buffer, 0, count);'

标签: java fileoutputstream


【解决方案1】:

根据操作系统,flush() 不会强制将数据写入操作系统。在 FileOutputStream 的情况下,write() 将所有数据传递给操作系统,因此 flush() 什么也不做。 close() 可以确保文件实际写入磁盘(或不取决于操作系统)。写数据的时候可以看看磁盘是否还在忙。

需要 30 秒的 500 MB 文件意味着您正在写入 17 MB/s。这听起来像是一个非常慢的磁盘或网络共享/驱动器上的文件。


你可以试试这个

File file = File.createTempFile("deleteme", "dat"); // put your file here.
FileOutputStream fos = new FileOutputStream(file);
long start = System.nanoTime();
byte[] bytes = new byte[32 * 1024];
for (long l = 0; l < 500 * 1000 * 1000; l += bytes.length)
    fos.write(bytes);
long mid = System.nanoTime();
System.out.printf("Took %.3f seconds to write %,d bytes%n", (mid - start) / 1e9, file.length());
fos.close();
long end = System.nanoTime();
System.out.printf("Took %.3f seconds to close%n", (end - mid) / 1e9);

打印

Took 0.116 seconds to write 500,006,912 bytes
Took 0.002 seconds to close

您可以从这个系统上的速度看出它即使在关闭时也不会写入数据。即驱动器不是那么快。

【讨论】:

  • flush()FileOutputStream 不执行任何操作。它仅对缓冲流有用。
  • 嗯,有道理。当我在家里尝试相同的代码时,close() 只用了几分之一秒,所以我猜学校的“问题”,close() 花了 30~ 秒,是因为网络安装的主文件夹。跨度>
  • 不,FileOutputStream.close 不能保证所有字节都准确地写入磁盘。但是您可以保证所有字节都写入操作系统缓冲区。如果操作系统崩溃,例如电源故障,您已经从 close() 返回的 FileOutputStream 可能会丢失数据。
  • 如果你关闭了文件,程序可能会死掉并且你不会丢失数据,除非出现其他问题。
【解决方案2】:

我在使用文件流时也看到了同样的情况。我发现如果您以读写方式打开文件,它会缓存所有内容并且在您关闭或处置之前不会写入。冲洗没有写。但是,如果您的写入扩展了文件的大小,它将自动刷新。

在每次写入时自动刷新打开。

【讨论】:

    猜你喜欢
    • 2016-10-29
    • 2018-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2012-07-16
    相关资源
    最近更新 更多