try(FileReader reader = new FileReader("input.txt")) {
int c;
while ((c = reader.read()) != -1)
System.out.print((char)c);
} catch (Exception ignored) { }
在这段代码中,我逐字符读取一个字符。以某种方式一次将a读入一个char数组是否更有效率?换句话说,在读取数组时会发生任何优化吗?
例如,在此代码中,我有一个名为char
的arr
数组,我一直读到其中,直到没有剩下要读取的内容为止。效率更高吗?
try(FileReader reader = new FileReader("input.txt")) {
int size;
char[] arr = new char[100];
while ((size = reader.read(arr)) != -1)
for (int i = 0; i < size; i++)
System.out.print(arr[i]);
} catch (Exception ignored) { }
该问题适用于读/写两个字符/字节。
取决于读者。答案可能是肯定的。无论是Reader还是InputStream都是真正的“原始”驱动程序(不只是包装另一个阅读器或inputstream的驱动程序,而是实际上正在与OS进行通信以获取数据的驱动程序)-可以很好地实现单字符[ C0]方法,方法是要求操作系统读取单个字符。
最后,您有一个磁盘,磁盘以块为单位返回数据。因此,如果您要求1个字节,则您有2种选择作为计算机:
向磁盘查询包含要读取的字节的块。将块存储在内存中一段时间。返回一个字节;在接下来的片刻中,如果来自同一块的字节请求更多,请从内存中存储的数据中返回,根本不用去询问磁盘。注意:这需要内存!谁分配?多少内存还可以?棘手的问题。操作系统倾向于提供低级工具,并且不喜欢仅仅为这些问题中的任何一个选择值。
向磁盘查询包含要读取的字节的块。从该块中找到所需的1个字节。忽略其余数据,仅返回该一个字节。如果稍后需要该块中的另一个字节...再次向磁盘询问整个块,然后重复此例程。
您获得的两种模型中的哪一种取决于许多因素:例如:它是哪种磁盘,您拥有什么操作系统,正在使用什么底层Java阅读器。但是,您可能会以第二种模式结束,这很可能是合理的,因为您可能会说,通常这是令人难以置信的缓慢,因为您最终会读取同一块4000多次而不是仅读取一次。
所以,如何解决这个问题?好吧,java也不知道操作系统在做什么,所以最安全的选择是让java
进行缓存。这样,您就不必依赖操作系统在做什么。您可以自己编写,所以不要:
read()
您可以做:
for (int i = in.read(); i != -1; i = in.read()) { processOneChar((char) i); }
更多代码,但是现在第二种情况(同一块被从磁盘读取很多次)不再发生;您已授予操作系统自由以最多4096个字符的价值返回给您的数据。
或者,使用Java内置的:BufferedX:
char[] buffer = new char[4096]; while (true) { int r = in.read(buffer); if (r == -1) break; for (int i = 0; i < r; i++) processOneChar(buffer[i]); }
BufferedReader br = new BufferedReader(in); for (int i = br.read(); i != -1; i = br.read()) { processOneChar((char) i); }
的实现保证了Java将负责制作一些合理大小的缓冲区,以避免从磁盘上重新读取同一块。
NB:请注意,不应使用您正在使用的FileReader构造函数。它使用平台默认编码(任何时候将字节转换为字符,都会涉及编码),并且平台默认编码是无法测试的错误的秘诀,这些错误非常糟糕。请改用BufferedReader
,或者最好使用新的API:
new FileReader(file, StandardCharsets.UTF_8)
请注意:
NB:写入时适用相同的逻辑;诸如SSD之类的磁盘一次只能写入一个完整的块。现在,不仅要像蜜糖糖一样缓慢地写入,而且由于它们得到的写入次数有限,您还破坏了磁盘。