read()方法是阻塞的。
什么是native code?
read()一次只能读一个字节,就像write(int b)一次只能写一个字节一样低效,所以有了增强版方法:
public int read(byte b[]) throws IOException { };
public int read(byte b[], int off, int len) throws IOException { };
read一个stream,通常的情况是不能保证一定成功也不能保证就一定失败,通常是你要读1024个字节,但只读了512个,之后网络断了,或者剩下的还在路上, 为了接近这个问题,可以这样:
int bytesRead = 0;
int bytesToRead = 1024;
byte[] input = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
bytesRead += in.read(input, bytesRead, bytesToRead - bytesRead);
}
循环的读,直到完成。
上面的代码有一个bug,没有考虑当数据读完,流返回-1的情况,
int bytesRead = 0;
int bytesToRead = 1024;
byte[] input = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
int result = in.read(input, bytesRead, bytesToRead - bytesRead);
if (result == -1) break; // end of stream
bytesRead += result;
}
如果不想被阻塞到那里一直等,可以用方法available()看下有多少数据可以读了。
int bytesAvailable = in.available();
byte[] input = new byte[bytesAvailable];
int bytesRead = in.read(input, 0, bytesAvailable);
// continue with rest of program immediately...
但,注意,available()返回的值可能是0!如果流到了末尾,available()返回0.
read(bytes,offset,length) 当流结束时返回-1,可如果本身流的长度是0,那它会返回0.
skip()可以跳过不想读的字节。
File是可以随机访问的,可以跳过任何字节,通过重新定位File pointer,不必每个字节都处理。
通过下面几个方法,可以回退和重新读读过的数据。
public void mark(int readAheadLimit)
public void reset() throws IOException
public boolean markSupported()
mark()当前位置,reset()回到mark的位置,并非每一个stream都支持mark,使用前要markSupported()。
在这里作者吐槽了java的设计,认为很poor,非面向对象,认为应该单独写一个Interface,把这几个方法封装进去,由那些支持mark的stream来实现接口,而非现在的写在abstract base类里面,在使用前要用markSupported()判断。