用 Java 將控制台輸出寫入文本文件
一、概述
將輸出打印到控制台以進行調試或向用戶顯示信息是很常見的。但是,有時可能需要將控制台輸出保存到文本文件中以供進一步分析或記錄之用。
在本教程中,我們將探索如何將控制台輸出重定向到 Java 中的文本文件。
2. 準備
當我們談論將控制台輸出寫入文本文件時,可能有兩種情況:
- 僅文件 – 將所有輸出重定向到一個文件。控制台不會打印任何輸出。
- 控制台和文件——輸出被寫入控制台和文件。
我們將在本教程中介紹這兩種情況。
在我們進入編碼部分之前,讓我們準備一些要寫入控制台的文本。為了更容易測試,我們將三行放在一個字符串列表中:
final static List<String> OUTPUT_LINES = Lists.newArrayList(
"I came",
"I saw",
"I conquered");
稍後,我們將討論如何將控制台的輸出重定向到文件。因此,我們將使用單元測試斷言來驗證文件是否包含預期內容。
JUnit 5的臨時目錄特性允許我們創建一個文件,將數據寫入文件,並在驗證後自動刪除文件。因此,我們將在測試中使用它。
接下來,讓我們看看如何進行重定向。
3.輸出只到文件
通常,我們使用System.out.println()
將文本打印到控制台。 System.out
是一個PrintStream
,默認情況下是標準輸出。 System
類提供了setOut()
方法,允許我們用我們自己的PrintStream
對象之一替換默認的“ out
”。
由於我們要將數據寫入文件,我們可以從 FileOutputStream 創建一個PrintStream
FileOutputStream.
接下來,讓我們創建一個測試方法,看看這個想法是否可行:
@Test
void whenReplacingSystemOutPrintStreamWithFileOutputStream_thenOutputsGoToFile(@TempDir Path tempDir) throws IOException {
PrintStream originalOut = System.out;
Path outputFilePath = tempDir.resolve("file-output.txt");
PrintStream out = new PrintStream(Files.newOutputStream(outputFilePath), true);
System.setOut(out);
OUTPUT_LINES.forEach(line -> System.out.println(line));
assertTrue(outputFilePath.toFile().exists(), "The file exists");
assertLinesMatch(OUTPUT_LINES, Files.readAllLines(outputFilePath));
System.setOut(originalOut);
}
在測試中,我們首先備份默認的System.out.
然後,我們構造一個PrintStream
out
,它包裝了一個FileOutputStream.
接下來,
我們將默認的System.out
替換為我們的“ out
”。
這些操作使System.out.println()
將數據打印到文件file-output.txt
而不是控制台。我們已經使用assertLinesMatch()
方法驗證了文件內容。
最後,我們將System.out
恢復為默認值。
如果我們運行測試,它就會通過。此外,沒有輸出打印到控制台。
4. 創建DualPrintStream
類
現在,讓我們看看如何將數據打印到控制台和文件。也就是說,我們需要兩個PrintStream
對象。
由於System.setOut()
只接受一個PrintStream
參數,我們不能傳遞兩個PrintStream
.
但是,我們可以創建一個新的PrintStream
子類來攜帶一個額外的PrintStream
對象:
class DualPrintStream extends PrintStream {
private final PrintStream second;
public DualPrintStream(OutputStream main, PrintStream second) {
super(main);
this.second = second;
}
...
}
DualPrintStream
擴展了PrintStream.
此外,我們可以將一個額外的PrintStream
對象(second)
傳遞給構造函數。然後,我們必須覆蓋PrintStream
的close(), flush(),
和write()
方法,以便second PrintStream
可以應用相同的操作:
class DualPrintStream extends PrintStream {
...
@Override
public void close() {
super.close();
second.close();
}
@Override
public void flush() {
super.flush();
second.flush();
}
@Override
public void write(byte[] buf, int off, int len) {
super.write(buf, off, len);
second.write(buf, off, len);
}
@Override
public void write(int b) {
super.write(b);
second.write(b);
}
@Override
public void write(byte[] b) throws IOException {
super.write(b);
second.write(b);
}
}
現在,讓我們檢查它是否按預期工作:
@Test
void whenUsingDualPrintStream_thenOutputsGoToConsoleAndFile(@TempDir Path tempDir) throws IOException {
PrintStream originalOut = System.out;
Path outputFilePath = tempDir.resolve("dual-output.txt");
DualPrintStream dualOut = new DualPrintStream(Files.newOutputStream(outputFilePath), System.out);
System.setOut(dualOut);
OUTPUT_LINES.forEach(line -> System.out.println(line));
assertTrue(outputFilePath.toFile().exists(), "The file exists");
assertLinesMatch(OUTPUT_LINES, Files.readAllLines(outputFilePath));
System.setOut(originalOut);
}
當我們運行它時它通過了,這意味著文本已經寫入文件。此外,我們可以在控制台中看到這三行。
5.結論
在本文中,我們學習了通過替換默認的System.out
來使System.out.println()
將數據打印到文件中。
與往常一樣,此處提供的所有代碼片段都可以在 GitHub 上找到。