這篇文章主要是針對使用普通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