开发者

Java InputStream reading problem

I have a Java class, where I'm reading data in via an 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 th开发者_如何学Goe IDE (Eclipse).

But when I export my project and it's packed in a JAR, the read command doesn't read all the data. How could I fix it?

This problem mostly occurs when the InputStream is a File (~10kb).

Thanks!


Usually I prefer using a fixed size buffer when reading from input 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. You can read the javadoc of InputStream to get more insight.

Here is the code snippet I usually use for reading input 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. 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.

Note the line (bytesRead = in.read(buffer)) >= 0, there is nothing in the InputStream spec saying that read() cannot read 0 bytes. You may need to handle the case when read() reads 0 bytes as special case depending on your case. 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. 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. 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. There is also a version of read which takes an array, this allows you to do chunked reads. It returns the number of bytes actually read or -1 when at the end of the InputStream. Combine this with a dynamic buffer such as ByteArrayOutputStream to get the following:

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.


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.

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜