0

Dude, I'm using following code to read up a large file(2MB or more) and do some business with data.
I have to read 128Byte for each data read call.
At the first I used this code(no problem,works good).

InputStream is;//= something...
int read=-1;
byte[] buff=new byte[128];
while(true){
 for(int idx=0;idx<128;idx++){
  read=is.read(); if(read==-1){return;}//end of stream
  buff[idx]=(byte)read;
 }
 process_data(buff);
}

Then I tried this code which the problems got appeared(Error! weird responses sometimes)

InputStream is;//= something...
int read=-1;
byte[] buff=new byte[128];
while(true){
 //ERROR! java doesn't read 128 bytes while it's available
 if((read=is.read(buff,0,128))==128){process_data(buff);}else{return;}
}

The above code doesn't work all the time, I'm sure that number of data is available, but reads(read) 127 or 125, or 123, sometimes. what is the problem?
I also found a code for this to use DataInputStream#readFully(buff:byte[]):void which works too, but I'm just wondered why the seconds solution doesn't fill the array data while the data is available.
Thanks buddy.

4
  • 1
    Just a side note: white space don't cost nuthin', but poor code legibility can cost a lot. Consider putting each code statement on its own line. It deserves at least that much. Commented Jul 16, 2014 at 21:59
  • You know that with your second block of code, you're throwing out data. If 128 bytes are not read for whatever reason, you've reached the end of the data for instance, and only a partial buffer is read, that buffer if discarded. Myself, I'd use a BufferedInputStream. Commented Jul 16, 2014 at 22:01
  • @HovercraftFullOfEels I really don't get you by throwing out data, but for some reason that I don't know, the second approach doesn't work correct sometimes. Commented Jul 16, 2014 at 22:03
  • It's all in the API, please read it. Commented Jul 16, 2014 at 22:03

2 Answers 2

2

Consulting the javadoc for FileInputStream (I'm assuming since you're reading from file):

Reads up to len bytes of data from this input stream into an array of bytes. If len is not zero, the method blocks until some input is available; otherwise, no bytes are read and 0 is returned.

The key here is that the method only blocks until some data is available. The returned value gives you how many bytes was actually read. The reason you may be reading less than 128 bytes could be due to a slow drive/implementation-defined behavior.

For a proper read sequence, you should check that read() does not equal -1 (End of stream) and write to a buffer until the correct amount of data has been read.

Example of a proper implementation of your code:

InputStream is; // = something...

int read;
int read_total;

byte[] buf = new byte[128];

// Infinite loop    
while(true){
    read_total = 0;

    // Repeatedly perform reads until break or end of stream, offsetting at last read position in array
    while((read = is.read(buf, read_total, buf.length - offset)) != -1){
        // Gets the amount read and adds it to a read_total variable.
        read_total = read_total + read;
        
        // Break if it read_total is buffer length (128)
        if(read_total == buf.length){
            break;
        }
    }
    
    if(read_total != buf.length){
        // Incomplete read before 128 bytes
    }else{
        process_data(buf);
    }
}

Edit:

Don't try to use available() as an indicator of data availability (sounds weird I know), again the javadoc:

Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. Returns 0 when the file position is beyond EOF. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.

In some cases, a non-blocking read (or skip) may appear to be blocked when it is merely slow, for example when reading large files over slow networks.

The key there is estimate, don't work with estimates.

Sign up to request clarification or add additional context in comments.

3 Comments

many thanks, but I also checked the data availability using InputStream#available():int which returns the file size(before any read call), so what now? what is the purpose of data availability here?
Perfect bro, so would you explain the code you provided a little? is my first approach suck or bad? what is the differenc? does DataInputStream#readFully(buf:byte[]):void do the same thing you provided? thanks dude
@user2889419 Added comments to code. A DataInputStream does a completely different thing for a different purpose but looking at the documentation of the readFully() method, I believe it does something similar if not same (to the example above). Though I would avoid using that and stick to my example instead to keep code clean. (Reading bytes from a file using a DataInputStream seems really obscure and may possibly have a few downsides [that I am not aware of at the moment]).
0

Since the accepted answer was provided a new option has become available. Starting with Java 9, the InputStream class has two methods named readNBytes that eliminate the need for the programmer to write a read loop, for example your method could look like

public static void some_method( ) throws IOException  {
    InputStream is = new FileInputStream(args[1]);
    byte[] buff = new byte[128];
    while (true) {
        int numRead = is.readNBytes(buff, 0, buff.length);
        if (numRead == 0) {
            break;
        }
        // The last read before end-of-stream may read fewer than 128 bytes.
        process_data(buff, numRead);
    }
}

or the slightly simpler

public static void some_method( ) throws IOException  {
    InputStream is = new FileInputStream(args[1]);
    while (true) {
        byte[] buff = is.readNBytes(128);
        if (buff.length == 0) {
            break;
        }
        // The last read before end-of-stream may read fewer than 128 bytes.
        process_data(buff);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.