打印流 PrintStream與PrintWriter
??如果要想通過程序?qū)崿F(xiàn)內(nèi)容的輸出,核心的本質(zhì)一定要依靠OutputStream類完成,但是OutputStream有一個(gè)很大的缺點(diǎn):數(shù)據(jù)輸出操作功能有限:public void write?(byte[] b) throws IOException,所有的數(shù)據(jù)一定要轉(zhuǎn)為字節(jié)數(shù)組后才能輸出,如果現(xiàn)在項(xiàng)目中需要輸出long、double或者Date,這種情況下就必須將這些數(shù)據(jù)變?yōu)樽止?jié)的形式來處理,這樣的處理其實(shí)是非常麻煩的,所以在最初的開發(fā)中為了解決此類的重復(fù)操作,往往由開發(fā)者自行定義一些功能類已簡(jiǎn)化輸出過程。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintUtil util = new PrintUtil(new FileOutputStream(file));
util.println("姓名:小強(qiáng)子");
util.print("年齡:");
util.print(78);
}
}
class PrintUtil implements AutoCloseable {//實(shí)現(xiàn)數(shù)據(jù)常用的輸出功能
private OutputStream output;//不管現(xiàn)在如何進(jìn)行輸出操作,核心使用的就是OutputStream
public PrintUtil(OutputStream output) {
this.output = output;
}
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");
}
public void print(long num) {
this.print(String.valueOf(num));
}
public void println(long num) {
this.println(String.valueOf(num));
}
@Override
public void close() throws IOException {
if (output != null) {
output.close();
}
}
}
??在整個(gè)操作過程之中打印流的設(shè)計(jì)思想的本質(zhì)在于:提高已有類的功能,例如:OutputStream是唯一可實(shí)現(xiàn)輸出的操作標(biāo)準(zhǔn)類,所以應(yīng)該以其為核心根本,但是這個(gè)類的輸出的操作功能有限,所以不方便進(jìn)行輸出各個(gè)類型的數(shù)據(jù),那么就為它做出了一層包裝,所以此時(shí)采用的設(shè)計(jì)思想就是“裝飾設(shè)計(jì)模式”。
??既然已經(jīng)發(fā)現(xiàn)了原始的OutputStream功能的不足,所以為了解決輸出問題,在java.io包中提供了打印流:PrintStream、PrintWriter。
- PrintStream:
public class PrintStream extends FilterOutputStream implements Appendable, Closeable
??構(gòu)造方法:public PrintStream?(OutputStream out)
- PrintWriter:
public class PrintWriter extends Writer
??構(gòu)造方法:public PrintWriter?(OutputStream out)

??下面使用PrintWriter來實(shí)現(xiàn)數(shù)據(jù)的輸出操作。
范例:數(shù)據(jù)輸出
import java.io.*;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintWriter util = new PrintWriter(new FileOutputStream(file));
util.println("姓名:小強(qiáng)子");
util.print("年齡:");
util.print(78);
util.close();
}
}
??從JDK1.5開始,PrintWriter類中追加了格式化輸出的操作支持:
????public PrintWriter format?(String format, Object... args)
范例:格式化輸出
import java.io.*;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintWriter util = new PrintWriter(new FileOutputStream(file));
String name="張三";
int age=20;
double salary=10000.00;
util.printf("姓名:%s、年齡:%s、月收入:%s",name,age,salary);
util.close();
}
}
??比起直接使用OutputStream類,那么使用PrintWriter、PrintStream類的處理操作會(huì)更加簡(jiǎn)單。以后只要是程序進(jìn)行內(nèi)容輸出時(shí)全部使用打印流。
System類對(duì)IO的支持
??System類是一個(gè)系統(tǒng)類,而且是一個(gè)非常常用的系統(tǒng)類,而在該類中提供了和輸入輸出有關(guān)的三個(gè)常量:
- 標(biāo)準(zhǔn)輸出(顯示器):
public static final PrintStream out; - 錯(cuò)誤輸出:
public static final PrintStream err; - 標(biāo)準(zhǔn)輸入(鍵盤):public static final InputStream in;
范例:觀察輸出
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
try {
Integer.valueOf("a");
}catch (Exception e){
System.out.println(e);//白色信息:java.lang.NumberFormatException: For input string: "a"
System.err.println(e);//紅色信息:java.lang.NumberFormatException: For input string: "a"
}
}
}
??System.out和System.err都是同一種類型的,如果使用的是IntelliJ IDEA在進(jìn)行System.err輸出時(shí)會(huì)使用紅色字體,System.out使用白色字體。
??最早設(shè)置兩個(gè)輸出的操作的目的:System.out是輸出那些希望用戶可以看見的信息,System.err是輸出那些不希望用戶看見的信息,如果有需要,也可以修改輸出的位置:
- 修改out的輸出位置:
public static void setOut?(PrintStream out) - 修改err的輸出位置:
public static void setErr?(PrintStream err)
范例:修改System.err位置
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn_err_print.txt";//定義操作的文件
File file = new File(dirPath);
System.setErr(new PrintStream(new FileOutputStream(file)));
try {
Integer.valueOf("a");
}catch (Exception e){
System.out.println(e);
System.err.println(e);//輸出到文件中
}
}
}
??在System類里面還提供了一個(gè)in的常量,而這個(gè)常量對(duì)應(yīng)的是標(biāo)準(zhǔn)輸入設(shè)備鍵盤的輸入處理,可以實(shí)現(xiàn)鍵盤數(shù)據(jù)輸入。
范例:實(shí)現(xiàn)鍵盤輸入
import java.io.InputStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
InputStream in=System.in;//此時(shí)的輸入流為鍵盤輸入
System.out.print("請(qǐng)輸入信息:");
byte[] data=new byte[1024];//長(zhǎng)度限制
int len=in.read(data);
System.out.println("輸入的內(nèi)容為:"+new String(data,0,len));
in.close();
//請(qǐng)輸入信息:asdasda
//輸入的內(nèi)容為:asdasda
}
}
??但是這樣的鍵盤輸入處理本身是有缺陷的:如果現(xiàn)在的長(zhǎng)度不足,只能接收部分?jǐn)?shù)據(jù),所以這個(gè)輸入就有可能需要進(jìn)行重復(fù)的輸入流數(shù)據(jù)接收,而且在接收時(shí)還會(huì)涉及到輸入中文,如果對(duì)于中文處理不當(dāng),則也有可能造成亂碼問題。
BufferedReader類
??BufferedReader類提供的是一個(gè)緩沖字符輸入流的概念,也就是說利用BufferedReader類可以很好的解決輸入流數(shù)據(jù)讀取問題,這個(gè)類是在最初(JDK1.5之前,1.5后出了一個(gè)更很強(qiáng)大的類代替此類)的時(shí)候提供的最完善的數(shù)據(jù)輸入的處理,之所以使用這個(gè)類來處理,是因?yàn)榇祟愔刑峁┯幸粋€(gè)重要的方法:
- 讀取一行數(shù)據(jù):
public String readLine() throws IOException

范例:實(shí)現(xiàn)鍵盤數(shù)據(jù)輸入
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
System.out.print("請(qǐng)輸入信息:");
String msg=reader.readLine();
System.out.println("輸入的內(nèi)容為:"+msg);
reader.close();
//請(qǐng)輸入信息:123
//輸入的內(nèi)容為:123
}
}
??在以后的實(shí)際開發(fā)中經(jīng)常會(huì)遇到輸入數(shù)據(jù)的情況,所有輸入數(shù)據(jù)的類型都是通過String描述的,那么這樣就方便了接收者進(jìn)行各種處理。
范例:接收整型輸入并且驗(yàn)證
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
System.out.print("請(qǐng)輸入您的年齡:");
String msg=reader.readLine();
if(msg.matches("\\d{1,3}")){
int age=Integer.valueOf(msg);
System.out.println("您輸入的年齡:"+msg);
}else{
System.err.println("輸入錯(cuò)誤,你輸入的內(nèi)容:"+msg);
}
reader.close();
}
}
??現(xiàn)在Java開發(fā)由鍵盤輸入數(shù)據(jù)的情況并不多見,但是作為一些基礎(chǔ)的邏輯訓(xùn)練還是可以使用鍵盤輸入數(shù)據(jù)的,而鍵盤輸入數(shù)據(jù)的標(biāo)準(zhǔn)做法(JDK1.5之前)就是上面的實(shí)現(xiàn)操作。實(shí)際開發(fā)中所有輸入的數(shù)據(jù)全部為字符串,可以方便驗(yàn)證與進(jìn)行復(fù)雜處理。
Scanner類
??java.util.Scanner是從JDK1.5之后追加的一個(gè)程序類,其主要的目的解決輸入流的訪問問題的,可以理解為BufferedReader的替代類,在Scanner類中有如下幾種操作方法:
- 構(gòu)造方法:
public Scanner?(InputStream source) - 判斷是否有數(shù)據(jù):
public boolean hasNext() - 取出數(shù)據(jù):
public String next() - 設(shè)置分隔符:
public Scanner useDelimiter?(String pattern)
范例:使用Scanner實(shí)現(xiàn)鍵盤輸入字符串
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("請(qǐng)輸入您的姓名:");
if (sc.hasNext()) {
System.out.println("您輸入的姓名:" + sc.next());//換行不算輸入
} else {
System.err.println("輸入有誤,未獲取到內(nèi)容");
}
}
}
范例:使用Scanner實(shí)現(xiàn)鍵盤數(shù)字輸入
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("請(qǐng)輸入您的年齡:");
if (sc.hasNextInt()) {//判斷是否有整數(shù)輸入
int age = sc.nextInt();//可以直接獲取數(shù)字
System.out.println("您輸入的年齡:" + age);
}else{
System.err.println("輸入有誤,未獲取到內(nèi)容");
}
}
}
??使用Scanner輸入數(shù)據(jù)還有一個(gè)最大的的特點(diǎn)是可以直接利用正則進(jìn)行驗(yàn)證判斷。
范例:輸入一個(gè)人的生日
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String birthdayRegex="\\d{4}-\\d{2}-\\d{2}";
Scanner sc = new Scanner(System.in);
System.out.println("請(qǐng)輸入您的生日:");
if (sc.hasNext(birthdayRegex)) {
System.out.println("您輸入的生日:" + sc.next());//換行不算輸入
} else {
System.err.println("輸入有誤,未獲取到內(nèi)容");
}
}
}
范例:使用Scanner讀取文件信息
import java.io.File;
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";//定義操作的文件
File file = new File(dirPath);
Scanner sc = new Scanner(file);
sc.useDelimiter("\r\n");//默認(rèn)以空格作為換行,設(shè)置以\r\n為換行符
while (sc.hasNext()) {
System.out.println(sc.next());
}
}
}
??現(xiàn)在可以發(fā)現(xiàn)Scanner的整體設(shè)計(jì)要好于BufferedReader,而且要比InputStream類讀取更方便。在以后的開發(fā)中,如果程序需要輸出數(shù)據(jù),則要使用打印流,輸入數(shù)據(jù)使用Scanner或BufferedReader。