1. 程式人生 > >Java 高階程式設計-輸入與輸出支援

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();
     }

在開發過程中,如果程式需要輸出資料一定使用列印流,輸入資料一定使用ScannerBufferedReader)。