【问题标题】:Fastest way to read/write an array from/to a file?从文件读取/写入数组的最快方法?
【发布时间】:2012-09-11 18:31:55
【问题描述】:

我知道这里和网上有几个类似的主题,但我想我似乎做错了什么。我的任务很简单 - 将一个大整数数组(int [] 或 ArrayList 或您认为最好的)写入(然后读取)到文件中。越快越好。我的具体数组中有大约 450 万个整数,当前时间例如(以毫秒为单位):

  • 生成树:14851.13071
  • 生成数组:2237.4661619999997
  • 保存数组:89250.167617
  • 加载数组:114908.08185799999

这是不可接受的,我想时间应该少得多。我究竟做错了什么?我不需要世界上最快的方法,但将这些时间缩短到大约 5 - 15 秒(欢迎减少但不是强制性的)是我的目标。

我当前的代码:

long start = System.nanoTime();

Node trie = dawg.generateTrie("dict.txt");
long afterGeneratingTrie = System.nanoTime();
ArrayList<Integer> array = dawg.generateArray(trie);
long afterGeneratingArray = System.nanoTime();

try
{
    new ObjectOutputStream(new FileOutputStream("test.txt")).writeObject(array);
}
catch (Exception e)
{
    Logger.getLogger(DawgTester.class.getName()).log(Level.SEVERE, null, e);
}
long afterSavingArray = System.nanoTime();

ArrayList<Integer> read = new ArrayList<Integer>();
try
{
    read = (ArrayList)new ObjectInputStream(new FileInputStream("test.txt")).readObject();
}
catch (Exception e)
{
    Logger.getLogger(DawgTester.class.getName()).log(Level.SEVERE, null, e);
}
long afterLoadingArray = System.nanoTime();

System.out.println("Generating trie: " + 0.000001 * (afterGeneratingTrie - start));
System.out.println("Generating array: " + 0.000001 * (afterGeneratingArray - afterGeneratingTrie));
System.out.println("Saving array: " + 0.000001 * (afterSavingArray - afterGeneratingArray));
System.out.println("Loading array: " + 0.000001 * (afterLoadingArray - afterSavingArray));

【问题讨论】:

  • 我知道但我不知道我应该数组还是数组列表。

标签: java arrays file io


【解决方案1】:

不要使用 java 序列化。它非常强大和强大,但不是特别快速(或紧凑)。使用简单的DataOutputStream 并调用writeInt()。 (确保在DataOutputStreamFileOutputStream 之间使用BufferedOutputStream)。

如果您想在读取时预先调整数组大小,请将您的第一个 int 写入数组长度。

【讨论】:

  • 1.我应该使用 int [] 还是 ArrayList?还是没关系? --- 2. 你能提供一些代码示例吗?恐怕我可能会混淆某些东西并最终导致代码缓慢/损坏。
  • @NPS - 如果您需要将数据存储在某种列表结构中, int[] 将是最快/最节省内存的。但是,如果您最终使用的是另一种数据结构,那么直接使用它可能会更快。
  • 1.我需要任何像数组一样工作的东西,即占用一个(可能很小的)内存块并具有索引访问权限。 --- 2. 我想我设法使用了你的建议,但再告诉我一件事 - 我应该分别在每个数组元素上调用 writeInt(),即调用 450 万次吗?
  • @NPS - 是的,您可以为每个数组元素调用 writeInt()(并且可以选择首先为数组长度调用)。
  • 谢谢,这大大缩短了我的加载/保存时间,现在它们都在 0.25 - 0.3 秒左右。不过我很惊讶 - 我认为保存整个块的 1 次操作会比保存每个元素的 4.5M 次操作更快,但我猜在我的情况下,前者不是单个块和 1 次操作。 :P
【解决方案2】:

类似下面的内容可能是一个相当快的选择。如果您担心减少开销,您还应该使用实际数组 int[] 而不是 ArrayList&lt;Integer&gt;

final Path path = Paths.get("dict.txt");
...
final int[] rsl = dawg.generateArray(trie);
final ByteBuffer buf = ByteBuffer.allocateDirect(rsl.length << 2);

final IntBuffer buf_i = buf.asIntBuffer().put(rsl).flip();
try (final WritableByteChannel out = Files.newByteChannel(path,
    StandardOpenOptions.WRITE, StandardOpenOptions.TRUNCATE_EXISTING)) {
  do {
    out.write(buf);
  } while (buf.hasRemaining());
}

buf.clear();
try (final ReadableByteChannel in = Files.newByteChannel(path,
    StandardOpenOptions.READ)) {
  do {
    in.read(buf);
  } while (buf.hasRemaining());
}
buf_i.clear();
buf_i.get(rsl);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    相关资源
    最近更新 更多