这篇文章主要是针对使用普通InputStream和OutputStream读写时遇到问题的总结。
直接上代码:
String filePathForRead = "D:\\For Testing\\test.txt";
File fileForRead = new File(filePathForRead);
if (!fileForRead.exists()) {
System.out.println("File for reading not exists");
return;
}
InputStream inputStream = new FileInputStream(fileForRead);
String filePathForWrite = "D:\\For Testing\\test_write.txt";
File fileForWrite = new File(filePathForWrite);
OutputStream outputStream = new FileOutputStream(fileForWrite);
int bufferSize = 4;
System.out.println("BufferSize : " + bufferSize);
byte[] buffer = new byte[bufferSize ];
System.out.println("AvailableSize : " + inputStream.available());
while (inputStream.read(buffer) != -1) {
outputStream.write(buffer);
}
outputStream.close();
inputStream.close();
System.out.println("End");
以上述方式读写文件的问题显而易见,即
byte[] buffer = new byte[4];
......
while (inputStream.read(buffer) != -1) {
outputStream.write(buffer);
}
(为了方便说明,这里将缓冲数组大小看作bufferSize, 将可从读取文件中获取到的所有字节大小看作:availableSize,availableSize可以通过inputStream.available()方法获取)
如果availableSize不是bufferSize的整数倍,以outputStream.write(buffer)方式直接往outputstream中写时,最后一次循环时,缓冲数组中存有脏数据,导致outputStream中有多余的数据。如下图:
BufferSize : 4
AvailableSize : 41
End
所要读取文件中的内容:
test for IO.
test...
test...
testabcde
最后生成的文件中的内容:
test for IO.
test...
test...
testabcdebcd
Buffer数组内容分析:
....
....
倒数第二次:a,b,c,d
最后一次循环:e,b,c,d
最后一次循环中b,c,d这3个是脏数据。
所以应该在每次读取后清空Buffer数组,如下:
while (inputStream.read(buffer) != -1) {
outputStream.write(buffer);
buffer = new byte[bufferSizer];
}
但是这种方式有很大的问题:如果文件很大,字节很多,每次循环都重新分配一个字节数组的话,就会导致内存溢出。所以这是一种极为不成熟的修改方案。
解决方案:
InputStream.read(byte b[])这个方法:
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
关于这个方法返回值的说明:
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
这个方法返回 一个读取到buffer中字节的总数,如果没有数据则返回-1。
查看 public int read(byte b[], int off, int len)方法:
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
这个方法返回的i也确实是记录的读取到buffer数组的字节的数量。
再看看outputStream的write(byte b[], int off, int len),将b数组的 off 到 off + len -1 下标的数据写入到OutputStream
/**
* Writes len bytes from the specified byte array starting at offset off to this output
* stream.The general contract for write(b, off, len) is thatsome of the bytes in the array
* b are written to theoutput stream in order; element b[off] is the firstbyte written and
* b[off+len-1] is the last byte writtenby this operation.
*
*/
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
如下是解决方案代码:
String filePathForRead = "D:\\For Testing\\test.txt";
File fileForRead = new File(filePathForRead);
if (!fileForRead.exists()) {
System.out.println("File for reading not exists");
return;
}
InputStream inputStream = new FileInputStream(fileForRead);
String filePathForWrite = "D:\\For Testing\\test.txt";
File fileForWrite = new File(filePathForWrite);
OutputStream outputStream = new FileOutputStream(fileForWrite);
int bufferSize = 4;
System.out.println("BufferSize : " + bufferSize);
byte[] buffer = new byte[bufferSize];
int count = 0;
System.out.println("AvailableSize : " + inputStream.available());
while ((count = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, count);
}
outputStream.close();
inputStream.close();
}
结果:
BufferSize : 4
AvailableSize : 41
End
所要读取文件中的内容:
test for IO.
test...
test...
testabcde
最后生成的文件中的内容:
test for IO.
test...
test...
testabcde