Java输入流读取缓冲区
假设我正在尝试从Java InputStream读取,如下所示:Java输入流读取缓冲区,java,inputstream,zipinputstream,Java,Inputstream,Zipinputstream,假设我正在尝试从Java InputStream读取,如下所示: ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip")); zis.getNextEntry(); byte[] buffer2 = new byte[2]; int count = zis.read(buffer2)); if(count != -1) //process... else...//something
ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip"));
zis.getNextEntry();
byte[] buffer2 = new byte[2];
int count = zis.read(buffer2));
if(count != -1) //process...
else...//something wrong, abort
while (zis.getNextEntry() != null) {
DataInputStream dis = new DataInputStream(new BufferedInputStream(zis));
boolean done = false;
do {
short s = dis.readShort();
int i = dis.readInt();
...
} while (!done);
}
我正在解析一个二进制文件,在本例中,我将缓冲区设置为2,因为我想读取下一个简短的内容。如果我想读取其他类型的下一个int等等,我会将缓冲区设置为大小4。问题是有时zis.read(buffer)不会填充缓冲区,即使我知道有足够的未读数据填充缓冲区。我可以简单地将整个文件内容转储到一个数组中并对其进行解析,但最后我实现了自己的流读取器来完成这项工作,这似乎是在重新发明轮子。我还可以实现一个read()函数来检查读取计数,如果小于buffersize,则请求更多数据来填充缓冲区,但这既低效又难看。有更好的方法吗 这是此处发布的问题的后续问题:
您需要检查字节计数并继续读取,直到您获得所需的所有信息
zis.getNextEntry();
byte[] buffer2 = new byte[2];
int count = 0;
while (count < 2) {
int bytesRead = zis.read(buffer2, count, 2 - count));
if(bytesRead != -1) {
count += bytesRead;
}
else...//something wrong, abort
}
//process...
zis.getnextery();
字节[]缓冲区2=新字节[2];
整数计数=0;
而(计数<2){
int bytesRead=zis.read(buffer2,count,2-count));
如果(字节读取!=-1){
计数+=字节读取;
}
否则…//出问题了,中止
}
//过程。。。
ZipInputStream符合InputStream定义的合同。允许并记录read(字节[…])方法返回-1表示流结束,或返回(1…请求的长度)之间的任何值
API以这种方式定义是有充分理由的,它使实现能够在数据可用时立即返回部分数据,而无需在等待数据可用时长时间阻塞(想想SocketInputStream)
如果需要最少的数据量,则需要反复调用read,直到读取了继续处理所需的数据量为止
至于“这既低效又难看”,通过大容量读取方法读取少量数据会产生自身的开销,并且可能在您显示的代码中也会为您读取的每个数据实体创建一个垃圾字节[]。对于读取少量字节,您可以简单地使用read()方法返回单个字节,该方法通过简单的实用程序方法实现,例如:
static short readShort(InputStream in) throws IOException {
short s = 0;
for (int i=0; i<2; ++i) {
int read = in.read();
if (read < 0)
throw new IOException("unexpected end of stream");
s = (short) ((s << 8) | read);
}
return s;
}
static short readShort(InputStream-in)引发IOException{
短s=0;
对于(int i=0;i
有更好的方法吗
嗯,ZipInputStream
最终继承自InputStream
,因此您应该能够使用BufferedInputStream
和DataInputStream
包装它,并使用readShort
和readInt
等方法读取数据
大概是这样的:
ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip"));
zis.getNextEntry();
byte[] buffer2 = new byte[2];
int count = zis.read(buffer2));
if(count != -1) //process...
else...//something wrong, abort
while (zis.getNextEntry() != null) {
DataInputStream dis = new DataInputStream(new BufferedInputStream(zis));
boolean done = false;
do {
short s = dis.readShort();
int i = dis.readInt();
...
} while (!done);
}
注意:您不应该关闭dis
流,因为这会导致zis
关闭。(显然,需要在外部级别关闭zis
,以避免资源泄漏。)
堆栈中的BufferedInputStream
确保不会对底层流执行大量小读取…这将是不好的
唯一的可能是,它的方法对于二进制数据是如何表示的有特别的想法;例如,数字是双二进制的。如果这是一个问题,考虑将整个ZIP条目读入字节数组,并将其封装在<代码> ByteBuffer < /COD>
中:“问题是有时ZIS.Read(缓冲器)。即使我知道有足够的未读数据来填充缓冲区,也不会填充缓冲区”-你确定吗?这不应该发生。“我还可以实现一个read()函数来检查读取计数,如果小于buffersize,则请求更多数据来填充缓冲区,但这既低效又难看。”-丑陋与否,这就是I/O的工作方式。脱离主题,但可能对您有用(我最近才了解到):不要使用“new FileInputStream(…)”,使用“Files.newInputStream(java.nio.file.Path,java.nio.file.OpenOption…)相反,为了避免出现上述问题,例如:@f1sh,请参阅我之前链接的帖子。@PentiumPro200,已经有一种read
方法,在读取请求的数据量之前进行阻塞,只是在ZipInputStream
上没有这种方法。InputStream
被设计为被其他InputStream
包裹。下面的内容似乎是:是您的用例的最佳解决方案。如果您不想逐个原语地读取原语,那么总会有。@SeanBright很好的捕获。我在这方面做得很超前,忘记了修改。现在修复了。感谢Stephen C,将ZipInputStream包装在BufferedInputStream和DataInputStream中似乎是最佳解决方案。值得注意的是,DataInputStream有一个readFully函数,它完全符合我的要求。它会一直阻塞,直到请求的数据量被累积。非常好!