Java 高階程式設計-輸入與輸出支援
學習阿里雲大學零基礎學Java系列 Java高階程式設計
1. 列印流
如果現在要想通過程式實現內容的輸出,核心的本質一定要依靠OutputStream類完成,但是OutputStream類有一個最大的缺點,這個類中的資料輸出操作功能有限(public void write(byte[] b) throws IOException),所有的資料一定要轉為位元組陣列後才可輸出,於是假設說現在專案裡可能輸出long、double、Date,再這樣的情況下就必須將這些資料變為位元組的形式來處理,這樣的處理一定是非常麻煩,所以在開發之中為了避免此類重複操作,往往會由開發者自行定義一些功能類來簡化輸出過程。
範例:列印流設計思想
package IOKnowledge;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author sunlh
*
*/
class PrintUtil implements AutoCloseable {// 實現一些常用資料的輸出
private OutputStream output;// 不管現在如何進行輸出操作,核心使用的就是OutputStream
public PrintUtil(OutputStream output) {// 由外部來決定輸出的位置
this.output = output;
}
public void print(long num) {
this.print(String.valueOf(num));
}
public void println(long num) {
this.println(String.valueOf(num));
}
public void print(String str) {// 輸出字串
try {
this.output.write(str.getBytes());// 輸出
} catch (IOException e) {
e.printStackTrace();
}
}
public void println(String str) {
this.print(str + "\r\n");
}
@Override
public void close() throws Exception {
this.output.close();
}
}
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("d:" + File.separator + "hello" + File.separator + "mldn.txt");// 定義操作檔案
PrintUtil pu = new PrintUtil(new FileOutputStream(file));
pu.println("姓名,小強子");
pu.print("年齡,");
pu.println(78);
pu.close();
}
}
在整個操作過程中列印流的設計思想的本質在於:提高已有類的功能,例如:OutputStream是唯一可以實現輸出的操作標準來,所以應該以其為核心根本,但是這個類輸出的操作功能有限,所以不方便進行輸出各個資料型別,那麼就為它做出了一層包裝,所以此時採用的設計思想就是“裝飾設計模式”。
但是既然所有的開發者都已經發現了原始中的OutputStream功能的不足,設計者也一定可以發現,所以為了解決輸出問題,在java.io包裡面提供有列印流:PrintStream、PrintWriter。
PrintStream | PrintWriter |
---|---|
public class PrintStream extends FilterOutputStream implements Appendable, Closeable |
public class PrintWriter extends Writer |
JDK1.0 | JDK1.1 |
public PrintStream(OutputStream out) |
public PrintWriter(OutputStream out) ,public PrintWriter(Writer out) |
下面使用PrintWriter來實現資料的輸出操作
範例:資料輸出
package IOKnowledge;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
*
* @author sunlh
*
*/
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("d:" + File.separator + "hello" + File.separator + "mldn.txt");// 定義操作檔案
PrintWriter pu = new PrintWriter(new FileOutputStream(file));
pu.println("姓名,小強");
pu.print("年齡,");
pu.println(78);
pu.close();
}
}
從JDK1.5開始PrintWriter類裡面追加有格式化輸出的操作支援:public PrintWriter printf(String format, Object… args)
public static void main(String[] args) throws Exception {
File file = new File("d:" + File.separator + "hello" + File.separator + "mldn.txt");// 定義操作檔案
PrintWriter pu = new PrintWriter(new FileOutputStream(file));
String name = "小強子";
int age = 78;
double salary = 72343.23423;
pu.printf("姓名:%s,年齡:%d,收入:%9.2f", name, age, salary);
pu.close();
}
比起直接使用OutputStream類,使用PrintWriter、PrintStream類的處理操作會更加簡單。以後只要是程式進行內容輸出的時候全部使用列印流。
2. System類對IO的支援
System類是一個系統類,而且是一個從頭到尾一直都在使用的系統類,而在這個系統類中提供有三個常量:
- 標準輸出(顯示器):
public static final PrintStream out
- 錯誤輸出:
public static final PrintStream err
- 標準輸入(鍵盤):
public static final InputStream in
範例:觀察輸出
public static void main(String[] args) throws Exception {
try {
Integer.parseInt("a");
} catch (Exception e) {
System.out.println(e);
System.err.println(e);
}
}
java.lang.NumberFormatException: For input string: "a"
java.lang.NumberFormatException: For input string: "a"(紅色)
System.out和System.err都是同一種類型的,如果現在使用的是Eclipse則在進行使用System.err輸出的時候會使用紅色字型,而在使用System.out的時候使用黑色字型。
最早設定兩個輸出操作是有目的的:System.out是輸出那些希望使用者可以看見的資訊,System.err是輸出那些不希望使用者看見的資訊,如果有需要可以修改輸出的位置:
- 修改out的輸出位置:
public static void setOut(PrintStream out)
- 修改err的輸出位置:
public static void setErr(PrintStream err)
範例:修改System.err的輸出位置
public static void main(String[] args) throws Exception {
System.setErr(new PrintStream(new FileOutputStream(new File("d:" + File.separator + "hello" + File.separator + "mldn.txt"))));
try {
Integer.parseInt("a");
} catch (Exception e) {
System.out.println(e);
System.err.println(e);// 輸出到檔案裡
}
}
在System類裡面還提供有一個in的常量,而這個常量對應的是標準輸入裝置鍵盤的輸入處理,可以實現鍵盤資料輸入。
範例:實現鍵盤輸入
public static void main(String[] args) throws Exception {
InputStream input = System.in;// 此時的輸入流為鍵盤輸入
System.out.println("請輸入資訊:");
byte [] data = new byte[1024];
int len = input.read(data);
System.out.println("輸入內容為:" + new String(data, 0, len));
}
但是這樣的鍵盤輸入處理本身是有缺陷的:如果你現在的長度不足,那麼只能夠接收部分資料,所以這個輸入就有可能需要進行重複的輸入流資料接收,而且在接收的時候有可能牽扯到輸入中文的情況,如果中文處理不當,有可能造成亂碼。
3. BufferedReader快取輸入流
BufferedReader類提供的是一個緩衝字元輸入流i的概念,也就是說利用BufferedReader類可以很好的解決輸入流資料的讀取問題,這個類是在最初的時候提供的最完善的資料輸入的處理(JDK1.5之前,JDK1.5之後出了一個功能更強大的類代替此類),之所以使用這個類來處理,是因為這個類之中提供有一個更重要的處理方法。
- 讀取一行資料:
public String readLine() throws IOException
下面將利用這個類實現鍵盤輸入資料的標準化定義
public static void main(String[] args) throws IOException {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("請輸入資訊:");
String msg = input.readLine();// 接收輸入資訊
System.out.println("輸入內容為:" + msg);
}
在以後實際的開發過程之中經常會遇見輸入資料的情況,而所有輸入資料的型別都是通過String描述的,那麼這樣就方便了接收者進行各種處理。
範例:接收整型輸入並且驗證
public static void main(String[] args) throws IOException {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("請輸入您的年齡:");
String msg = input.readLine();// 接收輸入資訊
if(msg.matches("\\d{1,3}")) {// 是否由數字所組成
int age = Integer.parseInt(msg);
System.out.println("年齡為:" + age);
} else {
System.out.println("請輸入正確的年齡數字");
}
對於現在的Java開發由鍵盤輸入資料的情況並不多,但是作為一些基礎的邏輯訓練還是可以使用鍵盤輸入的,而鍵盤輸入資料的標準做法(JDK1.5)就是上面的實現操作。實際開發中所有的輸入資料全部都是字串,方便驗證與複雜處理。
4. Scanner掃描流
java.util.Scanner是從JDK1.5之後追加的一個程式類,其主要的目的是為了解決輸入流的訪問問題的,可以理解為BufferedReader類的替代功能類。在Scanner類裡面有如下幾種操作方法:
- 構造:
public Scanner(InputStream source)
- 判斷是否有資料:
public boolean hasNext()
- 取出資料:
public String next()
- 設定分隔符:
public Scanner useDelimiter(String pattern)
範例:使用Scanner實現鍵盤資料輸入
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入年齡:");
if(scanner.hasNextInt()) {// 判斷是否有整數輸入
int age = scanner.nextInt();// 直接獲取數字
System.out.println("年齡:" + age);
} else {
System.out.println("請輸入正確年齡");
}
scanner.close();
}
Scanner的處理更為簡單
範例:輸入一個字串
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入資訊:");
if(scanner.hasNext()) {// 判斷是否有輸入,直接空格不算輸入
String msg = scanner.next();// 直接獲取輸入內容
System.out.println("輸入的內容:" + msg);
}
scanner.close();
}
使用Scanner輸入資料還有一個最大的特點是可以直接利用正則進行驗證判斷
範例:輸入一個人的生日
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入生日日期:");
if(scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {// 判斷輸入格式
String msg = scanner.next("\\d{4}-\\d{2}-\\d{2}");// 直接獲取輸入內容,可以加驗證
System.out.println("輸入的內容:" + new SimpleDateFormat("yyyy-MM-dd").parse(msg));
}
scanner.close();
}
Scanner的整體設計要好於BufferedReader,而且要比直接使用InputStream類讀取要方便
如果要讀取一個文字檔案中的所有內容資訊,如果採用的是InputStream類,那麼就必須依靠記憶體輸出流進行臨時資料儲存,還需要判斷的內容是否需要換行,最後輸出。
範例:使用Scanner讀取
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(new File("d:" + File.separator + "hello" + File.separator + "mldn.txt"));
System.out.println("請輸入生日日期:");
scanner.useDelimiter("\n");// 設定讀取分隔符(換行符)
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
}
在開發過程中,如果程式需要輸出資料一定使用列印流,輸入資料一定使用Scanner(BufferedReader)。