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
评论说明你逻辑有问题。所以我建议用简单的英语写出逻辑,然后重写代码。
我被一个问题困了好几天了,不知道该怎么办。
目的是上传一个文件到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
评论说明你逻辑有问题。所以我建议用简单的英语写出逻辑,然后重写代码。