网站动画用什么程序做,产品设计毕业作品集,国内高清视频素材网站,中石油工程建设公司网站通过缓存InputStream可重复利用一个InputStream#xff0c;但是要缓存一整个InputStream内存压力可能是比较大的。如果第一次读取InputStream是用来判断文件流类型#xff0c;文件编码等用的#xff0c;往往不需要所有的InputStream的数据#xff0c;或许只需要前n个字节但是要缓存一整个InputStream内存压力可能是比较大的。如果第一次读取InputStream是用来判断文件流类型文件编码等用的往往不需要所有的InputStream的数据或许只需要前n个字节这样一来缓存一整个InputStream实际上也是一种浪费。 其实InputStream本身提供了三个接口 第一个InputStream是否支持mark默认不支持。 public boolean markSupported() { return false;
} 第二个mark接口。该接口在InputStream中默认实现不做任何事情。 public synchronized void mark(int readlimit) {} 第三个reset接口。该接口在InputStream中实现调用就会抛异常。 public synchronized void reset() throws IOException { throw new IOException(mark/reset not supported);
} 从三个接口定义中可以看出首先InputStream默认是不支持mark的子类需要支持mark必须重写这三个方法。 第一个接口很简单就是标明该InputStream是否支持mark。 调用mark方法会记下当前调用mark方法的时刻InputStream被读到的位置。 调用reset方法就会回到该位置。 举个简单的例子 String content BoyceZhang!;
InputStream inputStream new ByteArrayInputStream(content.getBytes()); // 判断该输入流是否支持mark操作
if (!inputStream.markSupported()) { System.out.println(mark/reset not supported!);
}
int ch;
boolean marked false;
while ((ch inputStream.read()) ! -1) { //读取一个字符输出一个字符 System.out.print((char)ch); //读到 e的时候标记一下 if (((char)ch e) !marked) { inputStream.mark(content.length()); //先不要理会mark的参数 marked true; } //读到!的时候重新回到标记位置开始读 if ((char)ch ! marked) { inputStream.reset(); marked false; }
}
//程序最终输出BoyceZhang!Zhang! 看了这个例子之后对mark和reset接口有了很直观的认识。 mark接口的参数readlimit作用 我们知道InputStream是不支持mark的。要想支持mark子类必须重写这三个方法我想说的是不同的实现子类mark的参数readlimit作用不尽相同。 常用的FileInputStream不支持mark。 1. 对于BufferedInputStreamreadlimit表示InputStream调用mark方法的时刻起在读取readlimit个字节之前标记的该位置是有效的。如果读取的字节数大于readlimit可能标记的位置会失效。 在BufferedInputStream的read方法源码中有这么一段 } else if (buffer.length marklimit) { markpos -1; /* buffer got too big, invalidate mark */ pos 0; /* drop buffer contents */ } else { /* grow buffer */ 为什么是可能会失效呢 因为BufferedInputStream读取不是一个字节一个字节读取的是一个字节数组一个字节数组读取的。 例如readlimit35第一次比较的时候buffer.length0没开始读readlimit 然后buffer数组一次读取48个字节。这时的read方法只会简单的挨个返回buffer数组中的字节不会做这次比较。直到读到buffer数组最后一个字节第48个后才重新再次比较。这时如果我们读到buffer中第47个字节就reset。mark仍然是有效的。虽然4735。 2. 对于InputStream的另外一个实现类ByteArrayInputStream我们发现readlimit参数根本就没有用调用mark方法的时候写多少都无所谓。 public void mark(int readAheadLimit) { mark pos;
} public synchronized void reset() { pos mark;
} 因为对于ByteArrayInputStream来说都是通过字节数组创建的内部本身就保存了整个字节数组mark只是标记一下数组下标位置根本不用担心mark会创建太大的buffer字节数组缓存。 3. 其他的InputStream子类没有去总结。原理都是一样的。 所以由于mark和reset方法配合可以记录并回到我们标记的流的位置重新读流很大一部分就可以解决我们的某些重复读的需要。 这种方式的优点很明显不用缓存整个InputStream数据。对于ByteArrayInputStream甚至没有任何的内存开销。 当然这种方式也有缺点就是需要通过干扰InputStream的读取细节也相对比较复杂。转载于:https://www.cnblogs.com/fswhq/p/InputStream.html