Java中偵測EOF
一、簡介
EOF(文件結束)表示我們正在讀取文件並已到達該文件末尾的情況。了解 EOF 檢測至關重要,因為在某些應用程式中,我們可能需要讀取設定檔、處理資料或驗證檔。在Java中,我們可以透過多種方式來偵測EOF。
在本教程中,我們將探討 Java 中 EOF 檢測的幾種方法。
2. 設定範例
但是,在繼續之前,我們首先建立一個包含用於測試的虛擬資料的範例文字檔案:
@Test
@Order(0)
public void prepareFileForTest() {
File file = new File(pathToFile);
if (!file.exists()) {
try {
file.createNewFile();
FileWriter writer = new FileWriter(file);
writer.write(LOREM_IPSUM);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
該方法必須在其他方法之前首先運行,因為它可以確保測試文件的存在。因此,我們加入@Order(0)
註釋。
3.使用FileInputStream
檢測EOF
在第一種方法中,我們將使用FileInputStream
,它是InputStream
的子類別。
有一個read()
方法,它透過逐字節讀取資料來運作,以便**在到達 EOF 時產生-1
值**。
讓我們將測試檔案讀取到檔案末尾並將資料儲存在ByteArrayOutputStream
物件中:
String readWithFileInputStream(String pathFile) throws IOException {
try (FileInputStream fis = new FileInputStream(pathFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int data;
while ((data = fis.read()) != -1) {
baos.write(data);
}
return baos.toString();
}
}
現在讓我們建立一個單元測試並確保測試通過:
@Test
@Order(1)
public void givenDummyText_whenReadWithFileInputStream_thenReturnText() {
try {
String actualText = eofDetection.readWithFileInputStream(pathToFile);
assertEquals(LOREM_IPSUM, actualText);
} catch (IOException e) {
fail(e.getMessage());
}
}
FileInputStream
的優點在於效率——它非常快。不幸的是,沒有方法可以讀取每行文本,因此在讀取文本文件的情況下,我們必須將byte
轉換為character
。
因此,該方法適合讀取二進位數據,並提供byte
byte
處理的靈活性。然而,如果我們想要以結構化格式讀取文字數據,則需要更多的數據轉換程式碼。
4. 使用BufferedReader
檢測 EOF
BufferedReader
是java.io
套件中的一個類,用於從輸入流讀取文字。 BufferedReader
工作方式是將資料緩衝或暫時儲存在記憶體中。
在BufferedReader,
有一個readline()
方法,它逐行讀取文件,如果到達 EOF,則傳回null
值:
String readWithBufferedReader(String pathFile) throws IOException {
try (FileInputStream fis = new FileInputStream(pathFile);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader reader = new BufferedReader(isr)) {
StringBuilder actualContent = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
actualContent.append(line);
}
return actualContent.toString();
}
}
這裡,文件的內容是由readLine()
方法逐行讀取的。然後,結果儲存在actualContent
變數中,直到它產生指示EOF 的null
值。
接下來我們來做一下測試,確保結果的準確性:
@Test
@Order(2)
public void givenDummyText_whenReadWithBufferedReader_thenReturnText() {
try {
String actualText = eofDetection.readWithBufferedReader(pathToFile);
assertEquals(LOREM_IPSUM, actualText);
} catch (IOException e) {
fail(e.getMessage());
}
}
由於我們有readLine()
方法,因此該技術非常適合讀取**CSV 等結構化格式的文字資料。**但是,它不適合讀取二進位資料。
5. 使用Scanner
檢測EOF
Scanner
是java.util
套件中的一個類,可用於讀取各種類型資料的輸入,例如文字、整數等。
Scanner
提供了一個hasNext()
方法來讀取檔案的全部內容,**直到它產生一個false
值,該值表示 EOF :**
String readWithScanner(String pathFile) throws IOException{
StringBuilder actualContent = new StringBuilder();
File file = new File(pathFile);
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
String line = scanner.nextLine();
actualContent.append(line);
}
return actualContent.toString();
}
只要hasNext()
計算結果為true
,我們就可以觀察scanner
如何讀取檔案。這意味著我們可以使用nextLine()
方法從掃描器檢索String
值,直到hasNext()
計算結果為false
,表示我們已到達 EOF。
讓我們測試一下以確保該方法正常工作:
@Test
@Order(3)
public void givenDummyText_whenReadWithScanner_thenReturnText() {
try {
String actualText = eofDetection.readWithScanner(pathToFile);
assertEquals(LOREM_IPSUM, actualText);
} catch (IOException e) {
fail(e.getMessage());
}
}
這種方法的優點是非常靈活,可以輕鬆讀取各種類型的數據,**但對於二進位數據來說不太理想**。但是,效能可能比BufferedReader,
且不適合讀取二進位資料。
6. 使用FileChannel
和ByteBuffer
檢測 EOF
FileChannel
和ByteBuffer
是 Java NIO(新 I/O)中的類,是對傳統 I/O 的改進。
FileChannel
函數用於處理檔案輸入和輸出操作,而ByteBuffer
則用於有效處理位元組數組形式的二進位資料。
對於 EOF 檢測,我們將使用這兩個類別 – FileChannel
來讀取文件, ByteBuffer
來儲存結果。我們使用的方法是讀取緩衝區直到它傳回值-1,這表示檔案末尾(EOF) :
String readFileWithFileChannelAndByteBuffer(String pathFile) throws IOException {
try (FileInputStream fis = new FileInputStream(pathFile);
FileChannel channel = fis.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate((int) channel.size());
while (channel.read(buffer) != -1) {
buffer.flip();
buffer.clear();
}
return StandardCharsets.UTF_8.decode(buffer).toString();
}
}
這次,我們不需要使用StringBuilder
,因為我們可以從轉換或解碼的ByteBuffer
物件中取得讀取檔案的結果。
讓我們再次測試以確保該方法有效:
@Test
@Order(4)
public void givenDummyText_whenReadWithFileChannelAndByteBuffer_thenReturnText() {
try {
String actualText = eofDetection.readFileWithFileChannelAndByteBuffer(pathToFile);
assertEquals(LOREM_IPSUM, actualText);
} catch (IOException e) {
fail(e.getMessage());
}
}
此方法在從文件讀取資料或向文件寫入資料時提供高效能,適合隨機訪問,並支援MappedByteBuffer
。然而,它的使用更加複雜,需要細緻的緩衝區管理。
它特別適合讀取二進位資料和需要隨機檔案存取的應用程式。
7. FileInputStream
vs. BufferedReader
vs. Scanner
vs. FileChannel
和ByteBuffer
下表總結了四種方法之間的比較,每種方法都有優點和缺點:
特徵 | FileInputStream | BufferedReader | Scanner | FileChannel 和ByteBuffer |
資料類型 | 二進位 | 結構化文字 | 結構化文字 | 二進位 |
表現 | 好的 | 好的 | 好的 | 出色的 |
靈活性 | 高的 | 中等的 | 高的 | 低的 |
使用方便 | 低的 | 高的 | 高的 | 低的 |
八、結論
在這篇文章中,我們學習了Java中EOF檢測的四種方法。
每種方法都有其優點和缺點。正確的選擇取決於我們應用程式的具體需求,無論是涉及讀取結構化文字資料還是二進位數據,以及效能在我們的用例中的重要性。
與往常一樣,完整的源代碼可以在 GitHub 上取得。