为什么没有InputStream完全填充数组?

时间:2014-07-16 21:46:42

标签: java io stream

老兄,我正在使用以下代码读取一个大文件(2MB或更多)并与数据做生意。
我必须为每个数据读取调用读取128Byte 在第一次我使用这个代码(没问题,效果很好)。

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);
}

然后我尝试了这个问题出现的代码(错误!有时奇怪的反应)

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;}
}

上面的代码不能一直运行,我确信有多少数据可用,但有时会读取(read)127或125或123。有什么问题?
我还找到了一个使用DataInputStream#readFully(buff:byte[]):void的代码也可以使用,但我只是想知道为什么秒数解决方案在数据可用时不会填充数组数据。
谢谢伙计。

1 个答案:

答案 0 :(得分:2)

咨询FileInputStream的javadoc(我假设您正在阅读文件):

  

将此输入流中最多len个字节的数据读入一个字节数组。如果len不为零,则该方法将阻塞直到某些输入可用;否则,不读取任何字节,返回0。

这里的关键是该方法仅阻止某些数据可用。返回的值可以显示实际读取的字节数。您可能读取少于128个字节的原因可能是由于驱动器/实现定义的行为缓慢。

对于正确的读取序列,您应检查read()是否不等于-1(流结束)并写入缓冲区,直到读取了正确的数据量。

正确实施代码的示例:

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);
    }
}

修改

请勿尝试使用available()作为数据可用性的指标(我知道这听起来很奇怪),再次使用javadoc:

  

返回此输入流可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。当文件位置超出EOF时返回0。下一次调用可能是同一个线程或另一个线程。单个读取或跳过这么多字节不会阻塞,但可以读取或跳过更少的字节。

     

在某些情况下,非阻塞读取(或跳过)可能会在速度很慢时被阻止,例如在通过慢速网络读取大型文件时。

关键是估算,不会使用估算值。