根據JAVA官方文檔的描述,mark(int readlimit)方法表示,標記當前位置,並保證在mark以后最多可以讀取readlimit字節數據,mark標記仍有效。如果在mark后讀取超過readlimit字節數據,mark標記就會失效,調用reset()方法會有異常。
但實際的運行情況卻和JAVA文檔中的描述並不完全相符。 有時候在BufferedInputStream類中調用mark(int readlimit)方法后,即使讀取超過readlimit字節的數據,mark標記仍有效,仍然能正確調用reset方法重置。
事實上,mark在JAVA中的實現是和緩沖區相關的。只要緩沖區夠大,mark后讀取的數據沒有超出緩沖區的大小,mark標記就不會失效。如果不夠大,mark后又讀取了大量的數據,導致緩沖區更新,原來標記的位置自然找不到了。
因此,mark后讀取多少字節才失效,並不完全由readlimit參數確定,也和BufferedInputStream類的緩沖區大小有關。 如果BufferedInputStream類的緩沖區大小大於readlimit,在mark以后只有讀取超過緩沖區大小的數據,mark標記才會失效。看下面的例子。
<span style=
"color: #ff0000;"
>ava代碼
package
packet1;
import
java.io.BufferedInputStream;
import
java.io.ByteArrayInputStream;
import
java.io.IOException;
/**
* @author WuDian
*
*/
public
class
MarkExample {
public
static
void
main(String[] args) {
try
{
// 初始化一個字節數組,內有5個字節的數據
byte
[] bytes={
1
,
2
,
3
,
4
,
5
};
// 用一個ByteArrayInputStream來讀取這個字節數組
ByteArrayInputStream in=
new
ByteArrayInputStream(bytes);
// 將ByteArrayInputStream包含在一個BufferedInputStream,並初始化緩沖區大小為2。
BufferedInputStream bis=
new
BufferedInputStream(in,
2
);
// 讀取字節1
System.out.print(bis.read()+
","
);
// 在字節2處做標記,同時設置readlimit參數為1
// 根據JAVA文檔mark以后最多只能讀取1個字節,否則mark標記失效,但實際運行結果不是這樣
System.out.println(
"mark"
);
bis.mark(
1
);
/*
* 連續讀取兩個字節,超過了readlimit的大小,mark標記仍有效
*/
// 連續讀取兩個字節
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
// 調用reset方法,未發生異常,說明mark標記仍有效。
// 因為,雖然readlimit參數為1,但是這個BufferedInputStream類的緩沖區大小為2,
// 所以允許讀取2字節
System.out.println(
"reset"
);
bis.reset();
/*
* 連續讀取3個字節,超過了緩沖區大小,mark標記失效。
* 在這個例子中BufferedInputStream類的緩沖區大小大於readlimit,
* mark標記由緩沖區大小決定
*/
// reset重置后連續讀取3個字節,超過了BufferedInputStream類的緩沖區大小
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
// 再次調用reset重置,拋出異常,說明mark后讀取3個字節,mark標記失效
System.out.println(
"reset again"
);
bis.reset();
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package
packet1;
import
java.io.BufferedInputStream;
import
java.io.ByteArrayInputStream;
import
java.io.IOException;
/**
* @author WuDian
*
*/
public
class
MarkExample {
public
static
void
main(String[] args) {
try
{
// 初始化一個字節數組,內有5個字節的數據
byte
[] bytes={
1
,
2
,
3
,
4
,
5
};
// 用一個ByteArrayInputStream來讀取這個字節數組
ByteArrayInputStream in=
new
ByteArrayInputStream(bytes);
// 將ByteArrayInputStream包含在一個BufferedInputStream,並初始化緩沖區大小為2。
BufferedInputStream bis=
new
BufferedInputStream(in,
2
);
// 讀取字節1
System.out.print(bis.read()+
","
);
// 在字節2處做標記,同時設置readlimit參數為1
// 根據JAVA文檔mark以后最多只能讀取1個字節,否則mark標記失效,但實際運行結果不是這樣
System.out.println(
"mark"
);
bis.mark(
1
);
/*
* 連續讀取兩個字節,超過了readlimit的大小,mark標記仍有效
*/
// 連續讀取兩個字節
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
// 調用reset方法,未發生異常,說明mark標記仍有效。
// 因為,雖然readlimit參數為1,但是這個BufferedInputStream類的緩沖區大小為2,
// 所以允許讀取2字節
System.out.println(
"reset"
);
bis.reset();
/*
* 連續讀取3個字節,超過了緩沖區大小,mark標記失效。
* 在這個例子中BufferedInputStream類的緩沖區大小大於readlimit,
* mark標記由緩沖區大小決定
*/
// reset重置后連續讀取3個字節,超過了BufferedInputStream類的緩沖區大小
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
System.out.print(bis.read()+
","
);
// 再次調用reset重置,拋出異常,說明mark后讀取3個字節,mark標記失效
System.out.println(
"reset again"
);
bis.reset();
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
</span>
|
運行結果如下:
Java代碼
1,mark
2,3,reset
2,3,4,reset again
java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(BufferedInputStream.java:416)
at packet1.MarkExample.main(MarkExample.java:51)
1,mark
2,3,reset
2,3,4,reset again
java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(BufferedInputStream.java:416)
at packet1.MarkExample.main(MarkExample.java:51) 同樣的,在調用mark(int readlimit)方法時,如果readlimit大於BufferedInputStream類緩沖區的大小,緩沖區會被擴大,那mark后最多就可以讀readlimit字節。
簡言之,BufferedInputStream類調用mark(int readlimit)方法后讀取多少字節標記才失效,是取readlimit和BufferedInputStream類的緩沖區大小兩者中的最大值,而並非完全由readlimit確定。這個在JAVA文檔中是沒有提到的。
JAVA中mark()和reset()用法的通俗理解
mark就像書簽一樣,在這個BufferedReader對應的buffer里作個標記,以后再調用reset時就可以再回到這個mark過的地方。mark方法有個參數,通過這個整型參數,你告訴系統,希望在讀出這么多個字符之前,這個mark保持有效。讀過這么多字符之后,系統可以使mark不再有效,而你不能覺得奇怪或怪罪它。這跟buffer有關,如果你需要很長的距離,那么系統就必須分配很大的buffer來保持你的mark。
//eg.
//reader is a BufferedReader
reader.mark(50);//要求在50個字符之內,這個mark應該保持有效,系統會保證buffer至少可以存儲50個字符
int a = reader.read();//讀了一個字符
int b = reader.read();//又讀了一個字符
//做了某些處理,發現需要再讀一次
reader.reset();
reader.read();//讀到的字符和a相同
reader.read();//讀到的字符和b相同