简体   繁体   English

Java InputStream读取问题

[英]Java InputStream reading problem

I have a Java class, where I'm reading data in via an InputStream我有一个 Java class,我正在通过 InputStream 读取数据

    byte[] b = null;
    try {
        b = new byte[in.available()];
        in.read(b);
    } catch (IOException e) {
        e.printStackTrace();
    }

It works perfectly when I run my app from the IDE (Eclipse).当我从 IDE (Eclipse) 运行我的应用程序时,它运行良好。

But when I export my project and it's packed in a JAR, the read command doesn't read all the data.但是当我导出我的项目并将其打包在 JAR 中时,读取命令不会读取所有数据。 How could I fix it?我该如何解决?

This problem mostly occurs when the InputStream is a File (~10kb).当 InputStream 是文件 (~10kb) 时,通常会出现此问题。

Thanks!谢谢!

Usually I prefer using a fixed size buffer when reading from input stream.通常我更喜欢在从输入 stream 读取时使用固定大小的缓冲区。 As evilone pointed out, using available() as buffer size might not be a good idea because, say, if you are reading a remote resource, then you might not know the available bytes in advance.正如 evilone 指出的那样,使用 available() 作为缓冲区大小可能不是一个好主意,因为例如,如果您正在读取远程资源,那么您可能事先不知道可用字节。 You can read the javadoc of InputStream to get more insight.您可以阅读InputStream的 javadoc 以获得更多信息。

Here is the code snippet I usually use for reading input stream:这是我通常用于读取输入 stream 的代码片段:

byte[] buffer = new byte[BUFFER_SIZE];

int bytesRead = 0;
while ((bytesRead = in.read(buffer)) >= 0){
  for (int i = 0; i < bytesRead; i++){
     //Do whatever you need with the bytes here
  }
}

The version of read() I'm using here will fill the given buffer as much as possible and return number of bytes actually read.我在这里使用的 read() 版本将尽可能地填充给定的缓冲区并返回实际读取的字节数。 This means there is chance that your buffer may contain trailing garbage data, so it is very important to use bytes only up to bytesRead .这意味着您的缓冲区可能包含尾随垃圾数据,因此仅使用最多bytesRead的字节非常重要。

Note the line (bytesRead = in.read(buffer)) >= 0 , there is nothing in the InputStream spec saying that read() cannot read 0 bytes. 请注意(bytesRead = in.read(buffer)) >= 0行, InputStream 规范中没有任何内容说 read() 无法读取 0 字节。 You may need to handle the case when read() reads 0 bytes as special case depending on your case.根据您的情况,您可能需要处理 read() 读取 0 字节作为特殊情况的情况。 For local file I never experienced such case;对于本地文件,我从未遇到过这种情况; however, when reading remote resources, I actually seen read() reads 0 bytes constantly resulting the above code into an infinite loop.但是,在读取远程资源时,我实际上看到 read() 不断读取 0 个字节,导致上述代码进入无限循环。 I solved the infinite loop problem by counting the number of times I read 0 bytes, when the counter exceed a threshold I will throw exception.我通过计算读取 0 字节的次数来解决无限循环问题,当计数器超过阈值时,我将抛出异常。 You may not encounter this problem, but just keep this in mind:)你可能不会遇到这个问题,但请记住这一点:)

I probably will stay away from creating new byte array for each read for performance reasons.出于性能原因,我可能不会为每次读取创建新的字节数组。

read() will return -1 when the InputStream is depleted.当 InputStream 耗尽时read()将返回-1 There is also a version of read which takes an array, this allows you to do chunked reads.还有一个带有数组的read版本,这允许您进行分块读取。 It returns the number of bytes actually read or -1 when at the end of the InputStream.它在 InputStream 结束时返回实际读取的字节数或-1 Combine this with a dynamic buffer such as ByteArrayOutputStream to get the following:将此与动态缓冲区(例如ByteArrayOutputStream )结合起来,得到以下结果:

InputStream in = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] input = new byte[4096];
while ( -1 != ( read = in.read( input ) ) ) {
    buffer.write( input, 0, read );
}
input = buffer.toByteArray()

This cuts down a lot on the number of methods you have to invoke and allows the ByteArrayOutputStream to grow its internal buffer faster.这大大减少了您必须调用的方法数量,并允许 ByteArrayOutputStream 更快地增长其内部缓冲区。

File file = new File("/path/to/file");

try {
   InputStream is = new FileInputStream(file);
   byte[] bytes = IOUtils.toByteArray(is);

   System.out.println("Byte array size: " + bytes.length);
} catch (IOException e) {
   e.printStackTrace();
}

Below is a snippet of code that downloads a file (*. Png, *. Jpeg, *. Gif, ...) and write it in BufferedOutputStream that represents the HttpServletResponse.下面是下载文件(*.Png、*.Jpeg、*.Gif、...)并将其写入代表 HttpServletResponse 的 BufferedOutputStream 的代码片段。

BufferedInputStream inputStream = bo.getBufferedInputStream(imageFile);
try {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int bytesRead = 0;
    byte[] input = new byte[DefaultBufferSizeIndicator.getDefaultBufferSize()];
    while (-1 != (bytesRead = inputStream.read(input))) {
        buffer.write(input, 0, bytesRead);
    }
    input = buffer.toByteArray();

    response.reset();
    response.setBufferSize(DefaultBufferSizeIndicator.getDefaultBufferSize());
    response.setContentType(mimeType);
    // Here's the secret. Content-Length should equal the number of bytes read.
    response.setHeader("Content-Length", String.valueOf(buffer.size()));
    response.setHeader("Content-Disposition", "inline; filename=\"" + imageFile.getName() + "\"");

    BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), DefaultBufferSizeIndicator.getDefaultBufferSize());
    try {
        outputStream.write(input, 0, buffer.size());
    } finally {
        ImageBO.close(outputStream);
    }
} finally {
    ImageBO.close(inputStream);
}

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM