[TOC]
# éå½:æ åIO
>*æ å I/O*è¿ä¸ªæ¯è¯åèUnixä¸çæ¦å¿µï¼æç¨åºæä½¿ç¨çåä¸ä¿¡æ¯æµï¼è¿ç§ææ³å¨å¤§å¤æ°æä½ç³»ç»ä¸ï¼ä¹æç¸ä¼¼å½¢å¼çå®ç°ï¼ã
ç¨åºçææè¾å
¥é½å¯ä»¥æ¥èªäº*æ åè¾å
¥*ï¼å
¶ææè¾åºé½å¯ä»¥æµå*æ åè¾åº*ï¼å¹¶ä¸å
¶ææé误信æ¯åå¯ä»¥åéå°*æ åé误*ã*æ å I/O* çæä¹å¨äºç¨åºä¹é´å¯ä»¥å¾å®¹æå°è¿æ¥èµ·æ¥ï¼ä¸ä¸ªç¨åºçæ åè¾åºå¯ä»¥ä½ä¸ºå¦ä¸ä¸ªç¨åºçæ åè¾å
¥ãè¿æ¯ä¸ä¸ªé常强大çå·¥å
·ã
## 仿 åè¾å
¥ä¸è¯»å
éµå¾ªæ å I/O 模åï¼Java æä¾äºæ åè¾å
¥æµ `System.in`ãæ åè¾åºæµ `System.out` åæ åéè¯¯æµ `System.err`ã卿¬ä¹¦ä¸ï¼ä½ å·²ç»äºè§£å°å¦ä½ä½¿ç¨ `System.out`å°æ°æ®åå°æ åè¾åºã `System.out` å·²ç»é¢å
å
è£
[^1]æäº `PrintStream` å¯¹è±¡ãæ åéè¯¯æµ `System.err` ä¹é¢å
å
è£
为 `PrintStream` 对象ï¼ä½æ¯æ åè¾å
¥æµ `System.in` æ¯åççæ²¡æç»è¿å
è£
ç `InputStream`ãè¿æå³ç尽管å¯ä»¥ç´æ¥ä½¿ç¨æ åè¾åºæµ `System.in` åæ åéè¯¯æµ `System.err`ï¼ä½æ¯å¨è¯»å `System.in` ä¹åå¿
é¡»å
对å
¶è¿è¡å
è£
ã
æä»¬é叏䏿¬¡ä¸è¡å°è¯»åè¾å
¥ã为äºå®ç°è¿ä¸ªåè½ï¼å° `System.in` å
è£
æ `BufferedReader` æ¥ä½¿ç¨ï¼è¿è¦æ±æä»¬ç¨ `InputStreamReader` æ `System.in` 转æ¢[^2]æ `Reader` ãä¸é¢è¿ä¸ªä¾åå°é®å
¥çæ¯ä¸è¡æ¾ç¤ºåºæ¥ï¼
```java
// standardio/Echo.java
// How to read from standard input
import java.io.*;
import onjava.TimedAbort;
public class Echo {
public static void main(String[] args) {
TimedAbort abort = new TimedAbort(2);
new BufferedReader(
new InputStreamReader(System.in))
.lines()
.peek(ln -> abort.restart())
.forEach(System.out::println);
// Ctrl-Z or two seconds inactivity
// terminates the program
}
}
```
`BufferedReader` æä¾äº `lines()` æ¹æ³ï¼è¿åç±»åæ¯ `Stream` ãè¿æ¾ç¤ºåºæµæ¨¡åçççµæ´»æ§ï¼ä»
ä½¿ç¨æ åè¾å
¥å°±è½å¾å¥½å°å·¥ä½ã `peek()` æ¹æ³éå¯ `TimeAbort`ï¼åªè¦ä¿è¯è³å°æ¯éä¸¤ç§æè¾å
¥å°±è½å¤ä½¿ç¨åºä¿æå¼å¯ç¶æã
## å°`System.out` è½¬æ¢æ `PrintWriter`
`System.out` æ¯ä¸ä¸ª `PrintStream`ï¼è `PrintStream` æ¯ä¸ä¸ª`OutputStream`ã `PrintWriter` æä¸ä¸ªæ `OutputStream` ä½ä¸ºåæ°çæé å¨ãå æ¤ï¼å¦æä½ éè¦çè¯ï¼å¯ä»¥ä½¿ç¨è¿ä¸ªæé 卿 `System.out` è½¬æ¢æ `PrintWriter` ã
```java
// standardio/ChangeSystemOut.java
// Turn System.out into a PrintWriter
import java.io.*;
public class ChangeSystemOut {
public static void main(String[] args) {
PrintWriter out =
new PrintWriter(System.out, true);
out.println("Hello, world");
}
}
```
è¾åºç»æï¼
```
Hello, world
```
è¦ä½¿ç¨ `PrintWriter` 带æä¸¤ä¸ªåæ°çæé å¨ï¼å¹¶è®¾ç½®ç¬¬äºä¸ªåæ°ä¸º `true`ï¼ä»è使è½èªå¨å·æ°å°è¾åºç¼å²åºçåè½ï¼å¦åï¼å¯è½æ æ³çå°æå°è¾åºã
## éå®åæ å I/O
Javaç `System` ç±»æä¾äºç®åç `static` æ¹æ³è°ç¨ï¼ä»èè½å¤éå®åæ åè¾å
¥æµãæ åè¾åºæµåæ åé误æµï¼
- setInï¼InputStreamï¼
- setOutï¼PrintStreamï¼
- setErr(PrintStream)
妿æä»¬çªç¶éè¦å¨æ¾ç¤ºå¨ä¸å建大éçè¾åºï¼èè¿äºè¾åºæ»å¨çé度太快以è³äºæ æ³é
读æ¶ï¼éå®åè¾åºå°±æ¾å¾æ ¼å¤æç¨ï¼å¯æè¾åºå
容éå®åå°æä»¶ä¸ä¾åç»æ¥çãå¯¹äºæä»¬æ³é夿µè¯ç¹å®çç¨æ·è¾å
¥åºåçå½ä»¤è¡ç¨åºæ¥è¯´ï¼éå®åè¾å
¥å°±å¾æä»·å¼ãä¸ä¾ç®åæ¼ç¤ºäºè¿äºæ¹æ³ç使ç¨ï¼
```java
// standardio/Redirecting.java
// Demonstrates standard I/O redirection
import java.io.*;
public class Redirecting {
public static void main(String[] args) {
PrintStream console = System.out;
try (
BufferedInputStream in = new BufferedInputStream(
new FileInputStream("Redirecting.java"));
PrintStream out = new PrintStream(
new BufferedOutputStream(
new FileOutputStream("Redirecting.txt")))
) {
System.setIn(in);
System.setOut(out);
System.setErr(out);
new BufferedReader(
new InputStreamReader(System.in))
.lines()
.forEach(System.out::println);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
System.setOut(console);
}
}
}
```
该ç¨åºå°æä»¶ä¸å
容载å
¥å°æ åè¾å
¥ï¼å¹¶ææ åè¾åºåæ åé误éå®åå°å¦ä¸ä¸ªæä»¶ãå®å¨ç¨åºçå¼å§ä¿åäºæå对 `System.out` 对象çå¼ç¨ï¼å¹¶ä¸å¨ç¨åºç»ææ¶å°ç³»ç»è¾åºæ¢å¤å°äºè¯¥å¯¹è±¡ä¸ã
I/Oéå®åæä½çæ¯åèæµè䏿¯å符æµï¼å æ¤ä½¿ç¨ `InputStream` å `OutputStream`ï¼è䏿¯ `Reader` å `Writer`ã
## æ§è¡æ§å¶
ä½ ç»å¸¸éè¦å¨Javaå
é¨ç´æ¥æ§è¡æä½ç³»ç»çç¨åºï¼å¹¶æ§å¶è¿äºç¨åºçè¾å
¥è¾åºï¼Javaç±»åºæä¾äºæ§è¡è¿äºæä½çç±»ã
ä¸é¡¹å¸¸è§ç任塿¯è¿è¡ç¨åºå¹¶å°è¾åºç»æåéå°æ§å¶å°ãæ¬èå
å«äºä¸ä¸ªå¯ä»¥ç®åæ¤ä»»å¡çå®ç¨å·¥å
·ã
å¨ä½¿ç¨è¿ä¸ªå·¥å
·æ¶å¯è½ä¼äº§ç两ç§ç±»åçé误ï¼å¯¼è´å¼å¸¸çæ®éé误ââ对äºè¿äºé误æä»¬åªéè¦éæ°æåºä¸ä¸ª `RuntimeException` å³å¯ï¼ä»¥åè¿ç¨èªèº«çæ§è¡è¿ç¨ä¸å¯¼è´çé误ââæä»¬éè¦ç¨åç¬çå¼å¸¸æ¥æ¥åè¿äºé误ï¼
```java
// onjava/OSExecuteException.java
package onjava;
public class OSExecuteException extends RuntimeException {
public OSExecuteException(String why) {
super(why);
}
}
```
为äºè¿è¡ç¨åºï¼æä»¬éè¦ä¼ éç» `OSExecute.command()` ä¸ä¸ª `String command`ï¼æä»¬å¯ä»¥å¨æ§å¶å°é®å
¥åæ ·çæä»¤è¿è¡ç¨åºã该å½ä»¤ä¼ éç» `java.lang.ProcessBuilder` çæé å¨ï¼éè¦å°å
¶ä½ä¸º `String` 对象çåºåï¼ï¼ç¶åå¯å¨çæç `ProcessBuilder` 对象ã
```java
// onjava/OSExecute.java
// Run an operating system command
// and send the output to the console
package onjava;
import java.io.*;
public class OSExecute {
public static void command(String command) {
boolean err = false;
try {
Process process = new ProcessBuilder(
command.split(" ")).start();
try (
BufferedReader results = new BufferedReader(
new InputStreamReader(
process.getInputStream()));
BufferedReader errors = new BufferedReader(
new InputStreamReader(
process.getErrorStream()))
) {
results.lines()
.forEach(System.out::println);
err = errors.lines()
.peek(System.err::println)
.count() > 0;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
if (err)
throw new OSExecuteException(
"Errors executing " + command);
}
}
```
ä¸ºäºæè·å¨ç¨åºæ§è¡æ¶äº§ççæ åè¾åºæµï¼æä»¬å¯ä»¥è°ç¨ `getInputStream()`ãè¿æ¯å 为 `InputStream` æ¯æä»¬å¯ä»¥ä»ä¸è¯»åä¿¡æ¯çæµã
è¿éè¿äºè¡åªæ¯è¢«æå°äºåºæ¥ï¼ä½æ¯ä½ ä¹å¯ä»¥ä» `command()` æè·åè¿åå®ä»¬ã
该ç¨åºçé误被åéå°äºæ åé误æµï¼å¯ä»¥è°ç¨ `getErrorStream()` æè·ã妿åå¨ä»»ä½é误ï¼å®ä»¬é½ä¼è¢«æå°å¹¶ä¸æåº `OSExcuteException` ï¼ä»¥ä¾¿è°ç¨ç¨åºå¤çè¿ä¸ªé®é¢ã
ä¸é¢æ¯å±ç¤ºå¦ä½ä½¿ç¨ `OSExecute` ç示ä¾ï¼
```java
// standardio/OSExecuteDemo.java
// Demonstrates standard I/O redirection
// {javap -cp build/classes/main OSExecuteDemo}
import onjava.*;
public class OSExecuteDemo {}
```
è¿éä½¿ç¨ `javap` åç¼è¯å¨ï¼éJDKåå¸ï¼æ¥åç¼è¯ç¨åºï¼ç¼è¯ç»æï¼
```
Compiled from "OSExecuteDemo.java"
public class OSExecuteDemo {
public OSExecuteDemo();
}
```
[^1]: è¯è
注ï¼è¿éç¨å°äº**è£
饰卿¨¡å¼**ã
[^2]: è¯è
注ï¼è¿éç¨å°äº**éé
卿¨¡å¼**ã