如何决定从输入流中读取多少字节



我正在尝试从InputStream读取。我在下面写了代码

byte[] bytes = new byte[1024 * 32];
                while (bufferedInStream.read(bytes) != -1) {
                    bufferedOutStream.write(bytes);
                }

我不明白的是,在一次迭代中我应该读取多少字节?流包含一个保存在磁盘上的文件。

我在这里读过,但我真的不理解这篇文章。

假设有一股水流从管道流入浴缸。然后你用水桶从浴缸里取水,然后拿着水桶去花园给草坪浇水。浴缸是缓冲区。当你穿过草坪时,缓冲区已经满了,所以当你回来时,有一桶水可以再拿。

如果浴缸很小,那么当你拿着水桶行走时,它可能会溢出,所以你会失去水。如果你有一个大浴缸,那么它不太可能溢出来。所以缓冲区越大就越方便。当然,更大的浴缸要花更多的钱,占用更多的空间。

程序中的缓冲区会占用内存空间。你不想仅仅因为方便就占用所有可用内存作为缓冲区。

通常,在读取函数中,您可以指定要读取的字节数。所以即使你有一个小的缓冲区,你也可以这样做(伪代码):

const int bufsize = 50;
buf[bufsize];
unsigned read;
while ((read = is.read(buf, bufsize)) != NULL) {
   // do something with data - up to read bytes
}

在上面的代码中,bufzise是要读入缓冲区的MAXIMUM数据。

如果您的读取函数不允许您指定要读取的最大字节数,那么您需要提供一个足够大的缓冲区,以接收尽可能大的读取量。

因此,最佳缓冲区大小是特定于应用程序的。只有应用程序开发人员才能知道数据的特性。流入浴缸的水流有多快。你们能负担得起多大的浴缸(嵌入式应用程序),你们能多快地把水桶从浴缸里拿过花园再拿回来。

这取决于可用内存、文件大小和其他因素。你最好测量一下。

PS:你的代码是错误的。bufferedInStream.read(bytes)可能不会填充所有缓冲区,而只填充部分缓冲区。此方法返回实际的字节数作为结果。

byte[] bytes = new byte[1024 * 32];
int size;
while ((size = bufferedInStream.read(bytes)) != -1) {
    bufferedOutStream.write(bytes, 0, size);
}

以下是我的建议(假设我们只处理输入流,而不是如何写入输出流):

  1. 如果您的用例对高读取性能没有任何要求,请使用FileInputStream。例如:
FileInputStream fileInputStream = new FileInputStream("filePath");
byte[] bytes = new byte[1024];
int size;
while ((size = fileInputStream.read(bytes)) != -1) {
   outputStream.write(bytes, 0, size);
}
  1. 为了获得更好的读取性能,请使用BufferedInputStream并坚持其默认缓冲区大小,一次读取单个字节。例如:
byte[] bytes = new byte[1];
BufferedInputStream bufferedInputStream = 
                       new BufferedInputStream(fileInputStream("filePath"))
int size;
while ((size = bufferedInputStream.read(bytes)) != -1) {
    outputStream.write(bytes, 0, size);
}
  1. 为了获得更高的性能,请尝试调整BufferedInputStream的缓冲区大小,并一次读取一个字节。例如:
byte[] bytes = new byte[1];
BufferedInputStream bufferedInputStream = 
                       new BufferedInputStream(fileInputStream("filePath"), 16048)
int size;
while ((size = bufferedInputStream.read(bytes)) != -1) {
    outputStream.write(bytes, 0, size);
}
  1. 如果您需要更多,请使用BufferedInputStream之上的缓冲区。例如:
byte[] bytes = new byte[1024];
BufferedInputStream bufferedInputStream = 
                       new BufferedInputStream(fileInputStream("filePath"), 16048)
int size;
while ((size = bufferedInputStream.read(bytes)) != -1) {
    outputStream.write(bytes, 0, size);
}

您基本上有一个指定长度的字节容器(1024*32)

然后,inputStream将尽可能多地填充,可能是整个容器,在整个迭代中迭代,直到它到达文件的末尾,此时它将只填充剩余的字节,并在下一次迭代(它不能读取任何内容的迭代)返回-1

所以你基本上是复制&以1024*32字节大小的块从输入粘贴到输出

希望它能帮助你理解代码

顺便说一句,在最后一次迭代中,如果输入流小于1024*32,则输出不仅将接收文件的最后部分,而且还将接收上一次迭代未填充的字节的前一次迭代内容的重复。

这个想法不是使用缓冲的输入流一次读取整个文件内容。您可以使用缓冲的输入流读取与字节[]数组大小一样多的字节。您消耗读取的字节,然后继续从文件中读取更多字节。因此,你不需要知道文件大小来读取它

这篇文章将更有帮助,因为它解释了为什么应该用缓冲输入流包装文件输入流

为什么使用BufferedInputStream逐字节读取文件的速度比使用FileInputStream快?

最新更新