3

This should be very simple, and I've searched Google, but didn't see anyone mentioning the issue I've noticed. Everything that I've seen does the same basic thing. Like this:

byte [] buffer = new byte[256];
int bytesRead = 0;
while((bytesRead = input.read(buffer)) != -1)
{
    output.write(buffer, 0, bytesRead);
}

I know read() returns -1 when EOF is reached, but what if the file is smaller than the buffer or even the same size? Fox example, a 200 byte file is being read in. I assume it read the 200 bytes, but returns -1. That matches the javadocs, but it also means the write() is never called. I would have expected to actually tell me it read the 200 bytes, and on the next iteration to return -1.

How can I get around this "issue"?

Amac
  • 57
  • 1
  • 1
  • 3
  • Show how `input` is created and what happens to it before this call to `read()`. – erickson Feb 14 '12 at 22:58
  • As it stands, this question is "incomplete." – erickson Feb 15 '12 at 00:32
  • possible duplicate of [Easy way to write contents of a Java InputStream to an OutputStream](http://stackoverflow.com/questions/43157/easy-way-to-write-contents-of-a-java-inputstream-to-an-outputstream) – rds Jul 16 '15 at 20:10

5 Answers5

12

FYI, Guava has ByteStreams.copy(InputStream, OutputStream), which you can either use directly, or look at how it solves this problem.

Iulian Popescu
  • 2,595
  • 4
  • 23
  • 31
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Guava, I had not heard of this. I've found a lot Google Java libraries are very useful. I took a look at the code for copy(), and it is essentially doing what I am, but write() never gets called in my case. I'll take a look at my code again. This is how I expected it to work. Just like everyone that has commented is saying. – Amac Feb 14 '12 at 22:06
7

Your code

byte [] buffer = new byte[256];
int bytesRead = 0;
while((bytesRead = input.read(buffer)) != -1) {
    output.write(buffer, 0, bytesRead);
}

works OK.

For example imagine you have a file with 300 chars (600 bytes):

Step 1. buffer will read 256 bytes and rewrites them to output; 344 left to EOF

Step 2. buffer will read 256 bytes and rewrites them to output; 88 left to EOF

Step 3. buffer will read 88 bytes (byteRead == 88) and rewrites them to output; EOF left

Step 4. EOF (input.read(buffer) returns -1)

... edit

Above steps are not theory. I get this by rewriting actual file content with this code:

static void rewrite() throws IOException {
    InputStream input = new FileInputStream("file1.txt");
    OutputStream output = new FileOutputStream("file2.txt");
    byte[] buffer = new byte[256];
    int bytesRead = 0;
    while ((bytesRead = input.read(buffer)) != -1) {
        System.out.println(bytesRead);
        output.write(buffer, 0, bytesRead);
    }
}

maybe something else is wrong with your configuration.

msi
  • 2,609
  • 18
  • 20
  • This is what I would expect, but it is appearing to me that it is return -1 at step 3. I'll step through my code again, but I've done it a few times already with the same result. – Amac Feb 14 '12 at 21:49
1

At least two calls to read() would be required to detect the end of a non-empty stream. One to read the content, then another to return EOF.

As an example, if the buffer were 256 bytes, and the file only 200 bytes, a call to read(byte[]) would return 200 (or a sequence of call results would sum to 200), then subsequent calls would return -1 to signal EOF.

It's not totally clear how you've interpreted the Javadoc for InputStream, but it says clearly that it returns the number of bytes read, and returns -1 only when there were no more data to be read.

If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte. If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b.

Further:

Returns: The total number of bytes read into the buffer, or -1 [if] there [are] no more data because the end of the stream has been reached.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 2 reads? This is what I expected, but that's not the case. If my file is smaller than the buffer that I use, it returns -1 on the first call to raad(). It technically has reached EOF, so it's doing what the javadoc says. However, it doesn't say anything about the 200 bytes it did read. Using the while loop like I posted, write() is never called. – Amac Feb 14 '12 at 21:47
  • @user1209868 Then you have a bug elsewhere in your code. (Your post doesn't show the complete history of the stream, from opening a file to this point where read returns -1.) As quoted above, the documentation clearly specifies if any bytes can be read, a non-negative count is returned; the Javadoc does **not** say that -1 will be returned if some bytes are read. Either your stream is empty to begin with, or some preceding operation has consumed the data it held. – erickson Feb 14 '12 at 22:57
0

read() returns the number of bytes read until the complete file has been read. It only returns -1 once no more bytes can be read.

From the java documentation (1.4)

If no byte is available because the stream is at end of file, the value -1 is returned; otherwise, at least one byte is read and stored into b.

It actually does what you want it to do. It reads the 200 bytes (or whatever is left in the file and is smaller than the buffer you supplied) and returns -1 on the next iteration.

mcdeck
  • 126
  • 1
  • 4
  • I understand what the javadoc says. When I call read(), it fills the buffer until it reaches EOF (my buffer is larger than the file). And like the documentation says, it returns -1. It is doing this, but shouldn't it first tell me that it read the 200 bytes, and then on subsequent calls to read() return -1. – Amac Feb 14 '12 at 21:55
  • @user1209868 It returns -1 when it has read nothing but EOF, and not before. If it reads something it returns a read count. – user207421 Feb 15 '12 at 01:22
0

I assume it read the 200 bytes, but returns -1

No. It reads the 200 bytes and returns 200. This is perfectly clear from the Javadoc, and you could also have tried it easily enough.

user207421
  • 305,947
  • 44
  • 307
  • 483