Java:BufferedInputStream的available()方法存在问题
我正在处理以下用于将大文件拆分为一组较小文件的代码:Java:BufferedInputStream的available()方法存在问题,java,file-io,Java,File Io,我正在处理以下用于将大文件拆分为一组较小文件的代码: FileInputStream input = new FileInputStream(this.fileToSplit); BufferedInputStream iBuff = new BufferedInputStream(input); int i = 0; FileOutputStream output = new FileOutputStream(fileA
FileInputStream input = new FileInputStream(this.fileToSplit);
BufferedInputStream iBuff = new BufferedInputStream(input);
int i = 0;
FileOutputStream output = new FileOutputStream(fileArr[i]);
BufferedOutputStream oBuff = new BufferedOutputStream(output);
int buffSize = 8192;
byte[] buffer = new byte[buffSize];
while (true) {
if (iBuff.available() < buffSize) {
byte[] newBuff = new byte[iBuff.available()];
iBuff.read(newBuff);
oBuff.write(newBuff);
oBuff.flush();
oBuff.close();
break;
}
int r = iBuff.read(buffer);
if (fileArr[i].length() >= this.partSize) {
oBuff.flush();
oBuff.close();
++i;
output = new FileOutputStream(fileArr[i]);
oBuff = new BufferedOutputStream(output);
}
oBuff.write(buffer);
}
} catch (Exception e) {
e.printStackTrace();
}
FileInputStream input=newfileinputstream(this.fileToSplit);
BufferedInputStream iBuff=新的BufferedInputStream(输入);
int i=0;
FileOutputStream输出=新的FileOutputStream(fileArr[i]);
BufferedOutputStream oBuff=新的BufferedOutputStream(输出);
int buffSize=8192;
字节[]缓冲区=新字节[buffSize];
while(true){
if(iBuff.available()=此.partSize){
oBuff.flush();
oBuff.close();
++一,;
输出=新的FileOutputStream(fileArr[i]);
oBuff=新的缓冲输出流(输出);
}
对象写入(缓冲区);
}
}捕获(例外e){
e、 printStackTrace();
}
这是我看到的奇怪行为。。。当我使用3GB文件运行这段代码时,初始的iBuff.available()调用返回一个大约210000000的值,代码工作正常。当我在12GB文件上运行此代码时,初始的iBuff.available()调用只返回200000000的值(这比拆分文件大小500000000小,并导致处理出错)
我认为behvaior中的这种差异与32位windows上的这一事实有关。我将在4.5 GB和3.5 GB文件上运行更多测试。如果3.5文件有效,而4.5文件无效,这将进一步证实这是一个32位对64位的问题,因为4GB将是阈值。如果您阅读javadoc,它会非常清楚地指出: 返回可以使用的字节数 可以从此输入流中读取 无阻塞(由我添加强调) 所以很明显,你想要的不是这个方法提供的。因此,根据底层的InputStream,您可能会更早地遇到问题(例如,通过网络的流,服务器不返回文件大小-您必须读取完整的文件并对其进行缓冲,才能返回“正确的”可用()计数,这将花费大量时间-如果您只想读取头怎么办?) 因此,正确的处理方法是更改解析方法,使其能够处理文件的各个部分。就我个人而言,我看不出有什么理由在这里使用available()-只要调用read()并在read()返回时立即停止-1就可以了。如果您想确保每个文件确实包含块大小字节,则可能会变得更复杂—如果这种情况很重要,只需添加一个内部循环即可
int blockSize = XXX;
byte[] buffer = new byte[blockSize];
int i = 0;
int read = in.read(buffer);
while(read != -1) {
out[i++].write(buffer, 0, read);
read = in.read(buffer);
}
available并不是衡量还有多少数据需要读取,而是衡量在EOF或阻塞等待输入之前保证能够读取多少数据 在最后的决胜决胜局中,我们的胜负悬殊
BufferedInputStream iBuff = new BufferedInputStream(input);
int i = 0;
FileOutputStream output;
BufferedOutputStream oBuff=0;
try{
int buffSize = 8192;
int offset=0;
byte[] buffer = new byte[buffSize];
while(true){
int len = iBuff.read(buffer,offset,buffSize-offset);
if(len==-1){//EOF write out last chunk
oBuff.write(buffer,0,offset);
break;
}
if(len+offset==buffSize){//end of buffer write out to file
try{
output = new FileOutputStream(fileArr[i]);
oBuff = new BufferedOutputStream(output);
oBuff.write(buffer);
}finally{
oBuff.close();
}
++i;
offset=0;
}
offset+=len;
}//while
}finally{
iBuff.close();
}
您根本不应该使用
InputStream.available()
函数。只有在非常特殊的情况下才需要
您也不应该创建大于1MB的字节数组。这是浪费记忆。普遍接受的方法是从源文件中读取一个小数据块(4KB到1MB),然后只存储目标文件中读取的字节数。直到到达源文件的末尾为止。@ratchet和@Voo都是正确的。 至于发生了什么。 int最大值为2147483647()。 14千兆字节是15032385536,显然不适合整数。
请注意,根据API Javadoc()和@Voo所述,这根本不会破坏方法契约(只是这不是您想要的) available()的正确用法很少,这不是其中之一。你不需要那么多垃圾。记住这一点:
int count;
byte[] buffer = new byte[8192]; // or more
while ((count = in.read(buffer)) > 0)
out.write(buffer, 0, count);
这是Java中复制流的标准方法。下面是一些分割文件的代码。如果性能对您至关重要,您可以试验缓冲区大小
package so6164853;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Formatter;
public class FileSplitter {
private static String printf(String fmt, Object... args) {
Formatter formatter = new Formatter();
formatter.format(fmt, args);
return formatter.out().toString();
}
/**
* @param outputPattern see {@link Formatter}
*/
public static void splitFile(String inputFilename, long fragmentSize, String outputPattern) throws IOException {
InputStream input = new FileInputStream(inputFilename);
try {
byte[] buffer = new byte[65536];
int outputFileNo = 0;
OutputStream output = null;
long writtenToOutput = 0;
try {
while (true) {
int bytesToRead = buffer.length;
if (bytesToRead > fragmentSize - writtenToOutput) {
bytesToRead = (int) (fragmentSize - writtenToOutput);
}
int bytesRead = input.read(buffer, 0, bytesToRead);
if (bytesRead != -1) {
if (output == null) {
String outputName = printf(outputPattern, outputFileNo);
outputFileNo++;
output = new FileOutputStream(outputName);
writtenToOutput = 0;
}
output.write(buffer, 0, bytesRead);
writtenToOutput += bytesRead;
}
if (output != null && (bytesRead == -1 || writtenToOutput == fragmentSize)) {
output.close();
output = null;
}
if (bytesRead == -1) {
break;
}
}
} finally {
if (output != null) {
output.close();
}
}
} finally {
input.close();
}
}
public static void main(String[] args) throws IOException {
splitFile("d:/backup.zip", 1440 << 10, "d:/backup.zip.part%04d");
}
}
包so6164853;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.OutputStream;
导入java.util.Formatter;
公共类文件剥离器{
私有静态字符串printf(字符串fmt、对象…args){
格式化程序格式化程序=新格式化程序();
formatter.format(fmt,args);
返回格式化程序.out().toString();
}
/**
*@param outputPattern请参见{@link Formatter}
*/
公共静态void splitFile(String inputFilename、long fragmentSize、String outputPattern)引发IOException{
InputStream输入=新文件InputStream(inputFilename);
试一试{
字节[]缓冲区=新字节[65536];
int outputFileNo=0;
OutputStream输出=null;
长写输出=0;
试一试{
while(true){
int bytesToRead=buffer.length;
if(bytesToRead>fragmentSize-WritentOutput){
bytesToRead=(int)(fragmentSize-writentooput);
}
int bytesRead=input.read(缓冲区,0,bytesToRead);
如果(字节读取!=-1){
if(输出==null){
字符串outputName=printf(outputPattern,outputFileNo);
outputFileNo++;
output=新文件OutputStream(outputName);
writentooput=0;
}
输出写入(缓冲区,0,字节读取);
writentooput+=字节读取;
}
if(输出!=null&&(bytesRead==-1 | | writentooput==fragmentS