如何使用FilterReader确定字符流的长度?

9 浏览
0 Comments

如何使用FilterReader确定字符流的长度?

在谷歌搜索时,我发现使用java.io.File#length()可能会很慢。

FileChannel也有一个可用的size()方法。

在Java中是否有一种高效的方式来获取文件大小?

0
0 Comments

如何确定使用FilterReader的字符流的长度?

该问题的出现原因是,作者想要获取多个文件的文件大小,并且希望以最快的方式进行操作。作者进行了一些基准测试,并发现测试中还包括了一些其他的因素,比如反射、对象实例化等。作者认为这些因素会导致测试结果不准确,因此提出了这个问题。

为了解决这个问题,作者进行了一些修改后重新运行了代码。修改后的代码如下:

import java.io.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
public class FileSizeBench {
  private static File file;
  private static FileChannel channel;
  private static RandomAccessFile raf;
  
  public static void main(String[] args) throws Exception {
    int runs = 1;
    int iterations = 1;
    file = new File(args[0]);
    channel = new FileInputStream(args[0]).getChannel();
    raf = new RandomAccessFile(args[0], "r");
    HashMap times = new HashMap();
    times.put("file", 0.0);
    times.put("channel", 0.0);
    times.put("raf", 0.0);
    long start;
    for (int i = 0; i < runs; ++i) {
      long l = file.length();
      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != file.length()) throw new Exception();
      times.put("file", times.get("file") + System.nanoTime() - start);
      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != channel.size()) throw new Exception();
      times.put("channel", times.get("channel") + System.nanoTime() - start);
      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != raf.length()) throw new Exception();
      times.put("raf", times.get("raf") + System.nanoTime() - start);
    }
    for (Map.Entry entry : times.entrySet()) {
        System.out.println(
            entry.getKey() + " sum: " + 1e-3 * entry.getValue() +
            ", per Iteration: " + (1e-3 * entry.getValue() / runs / iterations));
    }
  }
}

通过运行修改后的代码,作者发现代码中的getResource方法占用了大约90%的时间。作者认为在获取包含Java字节码的文件的名称时,并不需要使用反射。因此,作者认为可以通过去除这部分代码来提高性能。

0
0 Comments

如何确定使用FilterReader时字符流的长度?

在这篇文章中的所有测试案例都存在缺陷,因为它们每次测试都访问相同的文件。所以磁盘缓存会起作用,从中受益的是第2和第3种方法。为了证明我的观点,我采用了GHAD提供的测试案例,并改变了枚举的顺序,下面是结果。

从结果来看,我认为File.length()才是真正的赢家。

测试的顺序决定了输出的顺序。你甚至可以看到在我的机器上执行的时间有所不同,但是当File.length()不是第一个且第一次访问磁盘时,它赢了。

---
LENGTH sum: 1163351, per Iteration: 4653.404
CHANNEL sum: 1094598, per Iteration: 4378.392
URL sum: 739691, per Iteration: 2958.764
---
CHANNEL sum: 845804, per Iteration: 3383.216
URL sum: 531334, per Iteration: 2125.336
LENGTH sum: 318413, per Iteration: 1273.652
--- 
URL sum: 137368, per Iteration: 549.472
LENGTH sum: 18677, per Iteration: 74.708
CHANNEL sum: 142125, per Iteration: 568.5

原因:在这篇文章中,测试案例存在缺陷,因为它们每次访问相同的文件,这导致了磁盘缓存的影响。测试方法2和方法3受益于磁盘缓存,因此它们的结果更好。

解决方法:为了避免磁盘缓存的影响,需要改变测试案例中访问文件的顺序。通过在使用FilterReader时更改枚举的顺序,可以得到更准确的结果。根据结果来看,调用File.length()方法可以得到最准确的字符流长度。

0
0 Comments

如何确定FilterReader的字符流长度?

在上述代码中,通过三种不同的方法获取文件的长度:LENGTH、CHANNEL和URL。根据运行次数和迭代次数的不同,三种方法的结果也有所差异。

在单次访问中,使用URL方法是最快的方式。但是在多次访问中,URL方法的性能反而不如LENGTH和CHANNEL方法。

代码中使用了File、FileInputStream、URL和InputStream等类和方法来获取文件的长度。其中,LENGTH方法直接使用File类的length()方法获取文件长度;CHANNEL方法通过FileInputStream获取通道,并使用size()方法获取文件长度;URL方法通过URL类的openStream()方法获取输入流,并使用available()方法获取文件长度。

在代码中,使用了多层循环来进行多次运行,每次运行都记录了每种方法的耗时,并计算出了总耗时和每次迭代的平均耗时。

根据结果来看,在单次访问中,使用URL方法是最快的;而在多次访问中,LENGTH方法的性能最佳。

但是需要注意的是,代码中使用的stream.available()方法并不是返回文件的长度,而是返回可读取的字节数。要获取文件的真实长度,需要实际读取文件并计算读取的字节数。

同时,代码中的测试结果并不完全准确,因为在低迭代次数下,后面的测试受到了操作系统的文件缓存影响;而在高迭代次数下,LENGTH和CHANNEL方法的性能更好,是因为它们执行了更少的操作。

因此,在进行性能测试时,应该清除缓存,以获得更准确的结果。

另外,代码中使用的stream.available()方法并不适合用于确定文件长度,特别是对于大文件来说。对于大文件,应该使用其他方式来获取文件长度。

根据实际需求和文件大小来选择合适的方法来确定FilterReader的字符流长度。

0