Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A better Java loop?

I have a piece of code to read a InputStream and write the content into an OutputStream:

BufferedInputStream in = new BufferedInputStream(...);
FileOutputStream outStream = new FileOutputStream outStream(...);

int read = in.read(buffer, 0, bufferSize);
while (read != -1) {
    outStream.write(buffer, 0, read);
    read = in.read(buffer, 0, bufferSize);
}

It works, but i don't like it since the variable read is declared out of the loop, and read() method is written twice. The revised version:

 for (int read = 0; read != -1; read = in.read(buffer, 0, bufferSize)) {
      outStream.write(buffer, 0, read);
 }

It looks better but not good enough because the first iteration is useless (and maybe harmful) with read=0.

Do you have a better solution?

like image 243
chance Avatar asked Dec 02 '22 02:12

chance


2 Answers

Personally I break the normal "no side-effect in a condition" rule for this sort of thing:

int bytesRead;
while ((bytesRead = in.read(buffer, 0, bufferSize)) != -1)
{
    outStream.write(buffer, 0, bytesRead);
}

EDIT: As noted, it does involve declaring read outside the loop, but it only calls read() once. I've never found it to be a problem - while I generally prefer to declare variables with as small a scope as possible, that's more a general cleanliness thing. If you want to limit the scope further you can put the whole thing in braces, or extract it to its own method, like Alan's approach. Here's how I'd implement it though:

public static void copyStream(InputStream input, OutputStream output)
    throws IOException {
  byte[] buffer = new byte[1024 * 16]; // Reasonable general size

  int bytesRead;
  while ((bytesRead = in.read(buffer, 0, buffer.length)) != -1) {
    outStream.write(buffer, 0, bytesRead);
  }
}

Alternatively you could provide the buffer length as a parameter. Note that this can now go off into a utility library, and you need never write the code again.

Alternatively, you could use the fact that it's already available in other utility libraries, such as Guava as ByteStreams.copy

like image 119
Jon Skeet Avatar answered Dec 16 '22 22:12

Jon Skeet


You can do it this way:

BufferedInputStream in = new BufferedInputStream(...);
FileOutputStream outStream = new FileOutputStream outStream(...);

while (true) { // can i use for(;;) in Java ???
    int read = in.read(buffer, 0, bufferSize);
    if (read == -1) break;
    outStream.write(buffer, 0, read);
}

It uses a break, though. Some people say break is bad/not so good style.

like image 39
gpeche Avatar answered Dec 16 '22 23:12

gpeche