使用Java Scanner时,是否需要将InputStream参数包装到InputStreamReader中?然后进入 BufferedReader?

问题描述 投票:0回答:1

参考thisthis问答,考虑到Java的Scanner同时支持字符编码和缓冲,是否需要将

InputStream
包装成
InputStreamReader
,然后再将其传递给Scanner?如果是这样,是否需要先将
InputStreamReader
包装成
BuffereedReader

换句话说,是否存在以下代码不是多余的场景。

FileInputStream inputStream = new FileInputStream(fileName);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedStreamReader = new BufferedReader(inputStreamReader);
Scanner scanner = new Scanner(bufferedStreamReader);

我正在学习 Java(从 Python),并试图更好地理解所有各种 IO 类的相似点、差异和用例。

(编辑1):我知道我们可以使用

FileReader
将前两行替换为一行 - 但这就是
FileReader
本身在内部所做的事情,所以这个例子(和这个问题)的目的是理解不同 IO 类的底层关系 - 因此显式调用
FileInputStream
use。

(编辑2):这个 Java 教程实际上做了这种包装。

java java.util.scanner bufferedreader java-io inputstreamreader
1个回答
0
投票

这是一个有争议的问题;你很少需要扫描仪(它并没有真正按照你想象的那样做。它按照它的规格说明做,但是,阅读它。它是怪异 - 它不是特别适合,嗯,任何东西,真的)。而且您不需要此代码 - 这是旧的文件 API。有新的了:

Path p = Path.of("/path/to/some/dir/someFileInDir.txt");
p = p.getParent().resolve("someOtherFile.txt");

try (var in = Files.newBufferedReader(p)) {
  while (true) {
    String line = in.readLine();
    if (line == null) break;
  }
}

当然,你可以用

Files.newBufferedReader(Path.of("/path/to/file.txt"))
来写它。

其价值:

  • FileInputStream
    不缓冲。如果您调用
    .read()
    (即“请读取 1 个字节”方法),它将向底层操作系统请求仅一个字节。在现代 SSD 上,这意味着操作系统将读取整个块,然后丢弃除您想要的 1 个字节之外的所有内容。是的,如果您或您使用的任何代码有意调用
    .read()
    ,则应该将它们包装在缓冲区中,但是如果您只是要使用足够大的字节数组(4096 左右就足够了,更不用说更多了),没有必要。
  • .read(byte[])
  • 也没有。
  • InputStreamReader
  • 确实
    ,默认 1024。
  • 所以,答案是:你找到的代码
大部分

没用,但 1024 有点低。 BufferedInputStream 默认为 8192,这是一个更好的数字。尽管如此,与从非缓冲基于块的源请求单个字节相比,1024 的性能提高了约 1024 倍。假设这些块的长度为 8192 字节,如果没有中间缓冲区,Scanner 只会慢 8 倍左右。假设 100% 的瓶颈是“从磁盘读取”部分。可能是这样,磁盘速度很慢。 这都是相关的

if

你正在手动滚动你不应该的缓冲堆栈(使用Scanner - 检查API,那里有很多,通常你可以一次性制作你需要的东西,尽管你不能制作扫描仪一次),并使用

Files.newBufferedX
,但你不应该使用。
    

© www.soinside.com 2019 - 2024. All rights reserved.