在我看到的从文件中读取的每个Java实现中,我几乎总是看到用于逐行读取的文件读取器。我的想法是,这将是非常低效的,因为它需要每行系统调用。
我一直在做的是使用输入流并直接获取字节。在我的实验中,这明显更快。我的测试是一个1MB的文件。
//Stream method
try {
Long startTime = new Date().getTime();
InputStream is = new FileInputStream("test");
byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);
//System.out.println(text);
Long endTime = new Date().getTime();
System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));
}
catch (Exception e) {
e.printStackTrace();
}
//Reader method
try {
Long startTime = new Date().getTime();
BufferedReader br = new BufferedReader(new FileReader("test"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
String text = sb.toString();
Long endTime = new Date().getTime();
System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));
}
catch (Exception e) {
e.printStackTrace();
}
这给出了以下结果:
Text length: 1054631, Total time: 9
Text length: 1034099, Total time: 22
那么,为什么人们使用读者而不是流?
如果我有一个接受文本文件并返回包含所有文本的String的方法,那么使用流做它是否更好?
答案 0 :(得分:9)
您正在将苹果与香蕉进行比较。即使使用bufferedReader,一次读取一行也会降低效率,而不是尽可能快地抓取数据。请注意,不鼓励使用可用,因为它在所有情况下都不准确。当我开始使用密码流时,我自己发现了这一点。
答案 1 :(得分:3)
FileReader
通常与BufferedReader
一起使用,因为通常逐行读取文件是有意义的,特别是如果文件具有明确定义的记录结构,其中每个记录对应于线。
此外,FileReader
可以简化处理字符编码和转换的部分工作,如javadocs中所述:
读取字符文件的便捷类。此类的构造函数假定默认字符编码和默认字节缓冲区大小是合适的... FileReader用于读取字符流。
答案 2 :(得分:3)
尝试增加BufferedReader
缓冲区大小。例如:
BufferedReader br = new BufferedReader(new FileReader("test"),2000000);
如果你选择合适的缓冲区大小,你会更快。
然后在带有Reader
的示例中,您花时间填充StringBuilder。如果需要处理行,则必须逐行读取文件。但是,如果您只需要读取字符串中的文本,那么请使用public int read(char[] cbuf)
读取更大的文本块,并将块写入使用适当大小初始化的StringWriter
中。
选择使用InputStream
或Reader
不取决于效果。通常,在阅读文本数据时使用Reader
,因为使用阅读器可以更轻松地处理字符集。
另一点,你的代码在这里
byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);
不正确。 documentation告诉
请注意,虽然InputStream的某些实现将返回流中的总字节数,但许多实现不会。使用此方法的返回值来分配用于保存此流中所有数据的缓冲区是绝对正确的。
所以要注意,你需要修理它。