java 中的大文件读取不一致

Large file reading inconsistency in java

我被一个问题困了好几天了,不知道该怎么办。

目的是上传一个文件到Google云存储,但是因为它是一个大文件,我想要一些效率,我使用一个线程来读取它,我预先将文件分成几块2个月。这些块存储在一个小队列中(大约 2 到 5 个插槽)并且可以由我的上传者 class(发出 PUT 请求的人)

访问

但是(因为总是有一个)块在每台计算机上都不一致。我尝试了很多东西,BufferedInputStream、PushBackInputStream、FileChannel(带或不带 MappedByteBuffer)无事可做,受影响的计算机在读取过程中某处失败,最后一部分(小于正常块)总是大于预期(所以总读取的字节数超过了原始计算的文件大小)。

我不知道为什么,但在某些计算机(大量计算机)上,文件似乎在读取过程中变大了。 我错过了什么 ?我究竟做错了什么 ?我可以截断剩余的字节吗?但是如果它突然比预期的要小怎么办? 我没有想法,所以我请求你的:)

哦,小技巧,由于上传过程中的恢复能力,我必须能够恢复阅读,所以它减少了 class 我可以使用的数量(标记支持,或位置以防万一文件频道)。

如果您对 CPU 和内存优化有任何建议,也欢迎您:)(不是全部,但剩下的只是用 q 实现的 BlockingQueue)

这是我Reader的一段往事: http://paste.awesom.eu/Teraglehn/pw09&ln

有趣的部分:

public void run() {
    try {
        byte[] chunk = new byte[chunkSize];
        int read;
        int r;
        long skipped;
        while (!shouldStop && !finishReading && !stopped) {
            if(size()>=maxSize){
                continue;
            }
            read = 0;
            System.out.println("[available1] "+available);
            System.out.println("[available2] "+inputStream.available());
            if(pendingFix !=0){
                System.out.println(String.format("Fix of %d bytes asked", pendingFix));
                clear();
                if (pendingFix > 0 ) {
                    pendingFix = Math.min(pendingFix, (int) available);
                    skipped = inputStream.skip((long) pendingFix);
                    if(skipped != pendingFix){
                        throw new IOException(String.format("Ask fix of %d bytes has not been completely done (%d bytes actually skipped for unknown reason)", pendingFix, skipped));
                    }
                    incrementCursor(pendingFix);
                }else {
                    decrementCursor(Math.min(cursor, -pendingFix));
                    inputStream.reset();
                    skipped = inputStream.skip(cursor);
                    if(skipped != cursor){
                        throw new IOException(String.format("Ask fix of %d bytes has not been completely done (%d bytes actually back skipped for unknown reason)", pendingFix, cursor-skipped));
                    }
                }
                pendingFix = 0;
            }
            while(read < chunkSize){
                r = inputStream.read(chunk, read, chunkSize-read);
                if(r<0) {
                    read = (read > 0)? read : r;
                    break;
                }
                else {
                    read +=r;
                }
            }

            if(pendingFix!=0) continue;
            if(read != chunkSize){ // Probably end of file
                if(read == -1){
                    finishReading = true;
                }else if(available == read){
                    System.out.println("Partial chunk (end)");
                    incrementCursor(read);
                    put(Arrays.copyOfRange(chunk, 0, read));
                    finishReading = true;
                }else {
                    throw new IOException(String.format("Only %d bytes have been read on %d bytes asked for unknown reason, %d bytes available", read, chunkSize, available));
                }
            }else {
                System.out.println("Full chunk (running)");
                put(chunk.clone());
                incrementCursor(read);
            }
        }
    }catch(IOException e){
        this.interrupt();
        errors.add(e);
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    stopped = true;
}

PS : 这一切都很有趣,我一个会话一个会话上传,一个会话是一个包含一个或多个大文件的文件夹,它总是最后一个失败的文件....

当所有事情都按特定方式发生时,你创造了一个混乱的局面,但如果事情没有按照你的预期进行,它就会失败。您使用的 available() 这很可能是错误的或至少是无用的。

你的读取循环也是错误的,因为它正在填充 chunk 数组,但假设每次读取都完全填充它(如果没有,前面的字节将被覆盖)。

你的// Probably end of file评论说明你逻辑有问题。所以我建议用简单的英语写出逻辑,然后重写代码。