6

我有一个包含 15 万条记录的数据库。我想尽快将其写入文件。我尝试了很多方法,但似乎都很慢。我怎样才能让它更快?

我以 40k 为单位读取这些记录。所以首先我读了 40k,然后又读了 40k,依此类推。

读取记录后,此过程返回一个包含 40k 行的 StringBuilder。然后我们将这个 StringBuilder 写入一个文件。

private static void write(StringBuilder sb, Boolean append) throws Exception {
    File file = File.createTempFile("foo", ".txt");

    FileWriter writer = new FileWriter(file.getAbsoluteFile(), append);
    PrintWriter out = new PrintWriter(writer);
    try {
        out.print(sb);           
        out.flush();
        writer.flush();
    } finally {
        writer.close();
        out.close();
    }
}

我读了另一个例子,但它同样慢:Fastest way to write huge data in text file Java

我也用 NIO api 试过:

private static void write(StringBuilder sb, Boolean append)) throws Exception {
    FileChannel rwChannel = new FileOutputStream("textfile.txt", true).getChannel();
    ByteBuffer bb = ByteBuffer.wrap(sb.toString().getBytes("UTF-8"));
    rwChannel.write(bb);
    rwChannel.close();
}

将大量数据写入/附加到文件中的最佳方法是什么?

4

5 回答 5

8

你不需要PrintWriter这里。如果您有任何类型的Writer(例如 a FileWriter),您可以简单地调用append(sb)它。而且你不需要flushclose意味着冲洗。

private static void write(StringBuilder sb, Boolean append) throws Exception {
  File file = File.createTempFile("foo", ".txt");

  try(FileWriter writer = new FileWriter(file.getAbsoluteFile(), append)) {
      writer.append(sb);
  }
}

在我的系统上,我遇到了使用 aChannel而不是a 的小幅性能改进OutputStream

private static void write0a(StringBuilder sb, Boolean append) throws Exception {
  File file = File.createTempFile("foo", ".txt");

  try(Writer writer = Channels.newWriter(new FileOutputStream(
      file.getAbsoluteFile(), append).getChannel(), "UTF-8")) {
    writer.append(sb);
  }
}

然而,这些只是轻微的改进。我在这里看不到太多可能性,因为所有代码最终都会调用相同的例程。真正可以提高您的性能的是在调用期间保持 Writer 活着,而不是刷新每条记录。

于 2013-09-10T14:13:16.307 回答
5

如果你有大量的数据,最好不要将它存储到 StringBuilder 中,然后将它一次写入文件。

这是最好的场景:

1) 在开始处理数据之前创建 FileInputStream

FileOutputStream fos = new FileOutputStream("/path/of/your/file");

2)从此文件创建和OutputStreamWriter

OutputStreamWriter w = new OutputStreamWriter(fos, "UTF-8");

3)创建BufferedWriter(提高文件写入性能)

BufferedWriter bw = new BufferedWriter(w);

4)将 bw 传递给您的进程函数,然后刷新/关闭

bw.flush();
bw.close();

StringBuilder 和 BufferedWriter 的功能几乎相同,因此您不需要对代码进行太多更改。这种情况的唯一缺点是,您的进程将涉及数据写入文件的所有时间,但如果您不在不同的线程中处理数据,这不是问题。

这样,数据量多大都无所谓

于 2013-09-10T12:39:29.230 回答
1

您正在使用 FileWriter(或第二个示例中的 FileOutputStream)。这些没有缓冲!所以他们分别写单个字符。字节到磁盘。

这意味着,您应该将 FileWriter 包装在 BufferedWriter 中(或将 FileOutputSystem 包装在 BufferedOutputSystem 中)。

private static void write(StringBuilder sb, Boolean append) throws Exception {
    File file = File.createTempFile("foo", ".txt");
    Writer writer = new BufferedWriter(new FileWriter(file.getAbsoluteFile(), append));
    PrintWriter out = new PrintWriter(writer);
    try {
        out.print(sb);           
        out.flush();
        writer.flush();
    } finally {
        writer.close();
        out.close();
    }
}
于 2013-09-10T12:26:06.683 回答
0

您正在打开文件,写一行,然后关闭它。在这里需要时间的是打开和关闭。找到一种保持输出文件打开的方法。

于 2013-09-10T12:50:14.703 回答
-1

你试过Apache IO,性能还是一样吗?

于 2013-09-10T12:55:56.110 回答