Java ZipInputStream提取错误

Java ZipInputStream提取错误,java,inputstream,zipinputstream,Java,Inputstream,Zipinputstream,下面是从只包含单个文件的zip文件中提取文件的一些代码。但是,提取的文件与通过WinZip或其他zip实用程序提取的相同文件不匹配。如果文件包含奇数个字节(因为我的缓冲区大小为2,一旦读取失败,我就会中止),我预计它可能会关闭一个字节。但是,在分析(使用WinMerge或Diff)使用下面的代码提取的文件与通过Winzip提取的文件时,Java提取中有几个区域缺少字节。有人知道我为什么或如何解决这个问题吗 package zipinputtest; import java.io.Buffere

下面是从只包含单个文件的zip文件中提取文件的一些代码。但是,提取的文件与通过WinZip或其他zip实用程序提取的相同文件不匹配。如果文件包含奇数个字节(因为我的缓冲区大小为2,一旦读取失败,我就会中止),我预计它可能会关闭一个字节。但是,在分析(使用WinMerge或Diff)使用下面的代码提取的文件与通过Winzip提取的文件时,Java提取中有几个区域缺少字节。有人知道我为什么或如何解决这个问题吗

package zipinputtest;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipInputStream;

public class test2 {
    public static void main(String[] args) {
        try {
            ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip"));
            File outputfile = new File("C:\\temp\\sample3.bin");
            OutputStream os = new BufferedOutputStream(new FileOutputStream(outputfile));
            byte[] buffer2 = new byte[2];
            zis.getNextEntry();
            while(true) {
                if(zis.read(buffer2) != -1) {
                    os.write(buffer2);
                }
                else break;
            }
            os.flush();
            os.close();
            zis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
我能够使用此图像生成错误(将其和zip另存为sample3.zip并在其上运行代码),但是任何足够大的二进制文件都应该显示差异


您可以使用更逐字逐句的方式来检查是否读取和写入了所有字节,例如

  public int extract(ZipInputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[BUFFER_SIZE];
    int total = 0;
    int read;
    while ((read = in.read(buffer)) != -1) {
      total += read;
      out.write(buffer, 0, read);
    }
    return total;
  }
如果在
write()
中未使用
read
参数,则该方法假定如果
缓冲区未完全填满,则将写出
缓冲区的全部内容,这可能是不正确的

OutputStream
可以在
extract()
方法内部或外部刷新和关闭。调用
close()
就足够了,因为它还调用
flush()


在任何情况下,Java的“标准”I/O代码,如
Java.util.zip
包,已经过广泛的测试和使用,因此它不太可能有如此基本的错误,导致如此容易地丢失字节

您可以使用更逐字逐句的方式来检查是否读取和写入了所有字节,例如

  public int extract(ZipInputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[BUFFER_SIZE];
    int total = 0;
    int read;
    while ((read = in.read(buffer)) != -1) {
      total += read;
      out.write(buffer, 0, read);
    }
    return total;
  }
while (true) {
    if(zis.read(buffer2) != -1) {
        os.write(buffer2);
    }
    else break;
}
如果在
write()
中未使用
read
参数,则该方法假定如果
缓冲区未完全填满,则将写出
缓冲区的全部内容,这可能是不正确的

OutputStream
可以在
extract()
方法内部或外部刷新和关闭。调用
close()
就足够了,因为它还调用
flush()

在任何情况下,Java的“标准”I/O代码,如
Java.util.zip
包,已经过广泛的测试和使用,因此它不太可能有如此基本的错误,导致如此容易地丢失字节

while (true) {
    if(zis.read(buffer2) != -1) {
        os.write(buffer2);
    }
    else break;
}
常见问题。你忽略了计数。应该是:

int count;
while ((count = zis.read(buffer2)) != -1)
{
    os.write(buffer2, 0, count);
}
注意:

  • 缓冲区大小为2是荒谬的。使用8192或更多
  • flush()
    之前的
    close()
    是多余的
  • 常见问题。你忽略了计数。应该是:

    int count;
    while ((count = zis.read(buffer2)) != -1)
    {
        os.write(buffer2, 0, count);
    }
    
    注意:

  • 缓冲区大小为2是荒谬的。使用8192或更多
  • flush()
    之前的
    close()
    是多余的

  • OP, Read 实际上告诉你有多少字节已经是Read,所以他可以用它来检查文件大小。你知道C++中的CULL()是否也调用了FLUSER()的调用?如果是这样,我将停止使用Flash作为C++,而java是我使用的唯一语言。我希望C++中任何一个现代的实现都可以调用C++中的FLUSE.@ PTENUMPRO200,其中<代码>关闭()/<代码>。Java的
    FilterInputStream.close()
    调用
    flush()
    ,因为可能存在应用程序端缓冲区。在关闭之前,任何I/O库都不应该刷新任何应用程序缓存,但我对C++ I/O库的耐心和兴趣是严格限制的。我在考虑STD::OFFROW,我检查了,结果是,CeleIE()调用了FrHuSE()。所以我想我不需要再调用flush()。这基本上是公共厕所的协议…当你完成后,不要冲厕所,只要关上门…很容易记住。开玩笑。。。OP, Read 实际上告诉你有多少字节已经是Read,所以他可以用它来检查文件大小。你知道C++中的CULL()是否也调用了FLUSER()的调用?如果是这样,我将停止使用Flash作为C++,而java是我使用的唯一语言。我希望C++中任何一个现代的实现都可以调用C++中的FLUSE.@ PTENUMPRO200,其中<代码>关闭()/<代码>。Java的
    FilterInputStream.close()
    调用
    flush()
    ,因为可能存在应用程序端缓冲区。在关闭之前,任何I/O库都不应该刷新任何应用程序缓存,但我对C++ I/O库的耐心和兴趣是严格限制的。我在考虑STD::OFFROW,我检查了,结果是,CeleIE()调用了FrHuSE()。所以我想我不需要再调用flush()。这基本上是公共厕所的协议…当你完成后,不要冲厕所,只要关上门…很容易记住。开玩笑。。。我使用缓冲区大小2来演示这个问题。无法产生缓冲区大小为1的差异。完整版本的代码也将被设置为提取.zip中的所有文件,而不是仅提取1个文件。尽量使问题小而简洁。谢谢EJP和PNS。我今天大部分时间都在试着调试这个问题。你们俩为我节省了更多的调试时间。我唯一的问题是,为什么缓冲区不会被完全填满,除非它是文件的最后一次读取?不管怎样,我都会用柜台,只是好奇而已。为什么会有人坐呢?
    InputStream.read()
    的契约不需要它。这就是它返回计数的原因。考虑一个套接字:在套接字接收缓冲区中得到了任何内容。考虑Zip:你可以得到任何可以解压缩的东西:但是协议是可行的,下一个解压缩块可能不适合当前的缓冲区。这是有道理的。ZipInputStream从FileInputStream接收数据块。尽管在除最后一种情况外的所有情况下,FileInputStream都有更多的数据要发送,但由于某些原因,它不会每次都填满缓冲区。我在想,为了提高效率,总是填满缓冲区是有意义的