特殊操作流
1. 标準輸入流 & 标準輸出流
1.1 概述
- System類中有兩個靜态的成員變量
- public static final InputStream in:标準輸入流。通常該流對應于鍵盤輸入或由主機環境或使用者指定的 另一個輸入源
- public static final PrintStream out:标準輸出流。通常該流對應于顯示輸出或由主機環境或使用者指定的 另一個輸出目标
1.2 示例
//自己實作鍵盤錄入資料過于麻煩,是以Java體統了一個類供我們使用
Scanner sc = new Scanner(System.in);
2. 位元組列印流 & 字元列印流
2.1 概述
- PrintStream:位元組列印流
- PrintWriter:字元列印流
- 使用繼承父類的方法寫資料,檢視的時候會轉碼;使用自己的特有方法寫資料,檢視的資料原樣輸出
- 可以改變輸出語句的目的地
- public static void setOut(PrintStream out):重新配置設定“标準”輸出流
2.2 特點
- 隻負責輸出資料,不負責讀取資料
- 永遠不會抛出IOException
- 有自己特有的方法
2.3 構造方法
2.3.1 位元組列印流
方法名 | 說明 |
PrintStream(String fileName) | 使用指定的檔案名建立新的列印流 |
2.3.2 字元列印流
方法名 | 說明 |
PrintWriter(String fileName) | 使用指定的檔案名建立一個新的PrintWriter,不會自動執行重新整理 |
PrintWriter(Writer out, boolean autoFlush) | 建立一個新的PrintWriter out:字元輸出流 autoFlush: 一個布爾值,如果 為真,則println 、print 或format方法将重新整理輸出緩沖區 |
2.4 代碼示例
2.4.1 位元組列印流
import java.io.IOException;
import java.io.PrintStream;
//位元組列印流
public class Demo01 {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream("iodemo\\demo.txt");
//位元組輸出流的方法 寫資料
ps.write(97); //寫入的是a
//位元組列印流 特有方法寫資料
ps.print(97); // 寫的是多少 寫入的就是多少
ps.println(98);//換行
ps.print(99);
//釋放資源
ps.close();
}
}
2.4.2 字元列印流
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Demo02 {
public static void main(String[] args) throws IOException {
/* //第一種構造方法
PrintWriter pw = new PrintWriter("iodemo\\demo.txt");
pw.write("hello");
pw.write("\r\n");
pw.flush();
//println 自動換行
pw.println("world");
pw.flush();*/
//第二種構造方法 加一個參數必須為true 這種構造方法能實作自動重新整理
PrintWriter pw = new PrintWriter(new FileWriter("iodemo\\demo.txt"),true);
pw.println("hello");
/* 這一步相當于 第一種構造方法中
pw.write("hello");
pw.write("\r\n");
pw.flush();
*/
pw.println("world");
pw.close();
}
}
2.5 複制Java檔案(列印流改進版)
import java.io.*;
//複制Java檔案 (列印流改進)
/*
1.根據資料源建立字元緩沖輸入流對象
2.根據目的地建立字元列印流對象
3.讀寫資料,複制檔案
4.釋放資源
*/
public class Test01 {
public static void main(String[] args) throws IOException {
//由于列印流隻能寫資料 不能讀資料 是以讀資料還是使用 字元緩沖輸入流來進行
BufferedReader br = new BufferedReader(new FileReader("iodemo\\src\\com\\wang\\test\\Test01.java"));
//建立列印流對象
PrintWriter pw = new PrintWriter(new FileWriter("iodemo\\Test.java"),true);
//讀資料仍用 字元緩沖輸入流的方法
String line;
while ((line = br.readLine()) != null){
//寫資料采用列印字元流
pw.println(line);
/*
bw.write(String);
bw.nerLine();
bw.flush();
*/
}
//釋放資源
br.close();
pw.close();
}
}
3. 對象序列化流 & 對象反序列化流
3.1 概述
- 對象序列化:就是将對象儲存到磁盤中,或者在網絡中傳輸對象
- 這種機制就是使用一個位元組序清單示一個對象,該位元組序列包含:對象的類型、對象的資料和對象中存儲的屬性等資訊位元組序列寫到檔案之後,相當于檔案中持久儲存了一個對象的資訊
- 反之,該位元組序列還可以從檔案中讀取回來,重構對象,對它進行 反序列化
- 要實作序列化和反序列化就要使用對象序列化流和對象反序列化流
- ObjectOutputStream:對象序列化流
- ObjectInputStream:對象反序列化流
3.2 對象序列化流
3.2.1 概述
- 将Java對象的原始資料類型和圖形寫入OutputStream。 可以使用ObjectInputStream讀取(重構)對象。可以通過使用流的檔案來實作對象的持久存儲。 如果流是網絡套接字流,則可以在另一個主機上或另一個程序中重構對象
3.2.2 構造方法 & 方法
構造方法 | 說明 |
ObjectOutputStream(OutputStream out) | 建立一個寫入指定的OutputStream的 ObjectOutputStream |
方法名 | 說明 |
void writeObject(Object obj) | 将指定的對象寫入ObjectOutputStream |
3.2.3 代碼示例
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Demo03 {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("iodemo\\demo.txt"));
Student03 s1 = new Student03("張三", 18);
oos.writeObject(s1);
oos.close();
}
//NotSerializableException 抛出一個執行個體需要一個Serializable接口,序列化運作時或執行個體的類可能會抛出此異常
}
/* 寫入結果
�� sr com.wang.specialdemo.Student03������� I ageL namet Ljava/lang/String;xp t 張三
*/
import java.io.Serializable;
//如何解決NotSerializableException異常
//Serializable接口 僅僅是一個辨別接口 沒有方法需要重寫
public class Student03 implements Serializable {
private String name;
private int age;
public Student03() {
}
public Student03(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.2.4 注意事項
- 一個對象要想被序列化,該對象所屬的類必須必須實作Serializable 接口
- Serializable是一個标記接口,實作該接口,不需要重寫任何方法
3.3 對象反序列化流
3.3.1 前提
- ObjectInputStream反序列化前 先使用ObjectOutputStream編寫的原始資料和對象
3.3.2 構造方法 & 方法
構造方法 | 說明 |
ObjectInputStream(InputStream in) | 建立從指定的InputStream讀取的ObjectInputStream |
方法名 | 說明 |
Object readObject() | 從ObjectInputStream讀取一個對象 |
3.3.3 代碼示例
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
//對象反序列化流
public class Demo04 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("iodemo\\demo.txt"));
Object obj = ois.readObject();
//向下轉型
Student03 s = (Student03) obj;
System.out.println(s.getName() + "," + s.getAge());
//釋放資源
ois.close();
}
}
import java.io.Serializable;
//如何解決NotSerializableException異常
//Serializable接口 僅僅是一個辨別接口 沒有方法需要重寫
public class Student03 implements Serializable {
private String name;
private int age;
public Student03() {
}
public Student03(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.4 三個問題
3.4.1 serialVersionUID & transient的應用
- 用對象序列化流序列化了一個對象後,假如我們修改了對象所屬的類檔案,讀取資料會不會出問題呢?
- 會出現問題,抛出InvalidClassException異常
- 如果出現了問題,應該如何解決?
- 重新序列化
- 給對象所屬的類加一個 serialVersionUID
- 如何一個對象中的某個成員變量的值不想被系列化,又該如何實作?
- 給該成員變量加transient關鍵字修飾,該關鍵字标記的成員變量不參與序列化過程
- 不參與序列化過程的成員變量,輸出預設值
4. Properties 集合
4.1 概述
- 是一個Map體系的集合類
- Properties可以儲存到流中或從流中加載
- 屬性清單中的每個鍵及其對應的值都是一個字元串
4.2 作為Map集合使用<代碼示例>
import java.util.Properties;
import java.util.Set;
// Properties作為Map集合的使用
public class Test02 {
public static void main(String[] args) {
//建立集合對象 Properties 木有泛型 是一個Map體系的集合類
Properties prop = new Properties();
//存儲元素 key value
prop.put("11111","張三");
prop.put("22222","李四");
prop.put("33333","王五");
//周遊集合 輸出集合元素
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + "," + value);
}
}
}
4.3 特有方法
方法名 | 說明 |
Object setProperty(String key, String value) | 設定集合的鍵和值,都是String類型,底層調用 Hashtable方法 put |
String getProperty(String key) | 使用此屬性清單中指定的鍵搜尋屬性 |
Set stringPropertyNames() | 從該屬性清單中傳回一個不可修改的鍵集,其中鍵及其對應的值是字元串 |
4.3.1 代碼示例
import java.util.Properties;
import java.util.Set;
public class Demo05 {
public static void main(String[] args) {
Properties prop = new Properties();
//Object setProperty(String key, String value) 底層調用的是put方法
prop.setProperty("11111","張三");
prop.setProperty("22222","李四");
prop.setProperty("33333","王五");
System.out.println(prop); //{33333=王五, 11111=張三, 22222=李四}
//String getProperty(String key) 鍵找值
System.out.println(prop.getProperty("11111")); //張三
//Set<String> stringPropertyNames() 輸出鍵集
Set<String> names = prop.stringPropertyNames();
for (String key : names) {
String value = prop.getProperty(key);
System.out.println(key + "," + value);
}
}
4.4 結合IO流的方法
4.4.1 方法
方法名 | 說明 |
void load(InputStream inStream) | 從輸入位元組流讀取屬性清單(鍵和元素對) |
void load(Reader reader) | 從輸入字元流讀取屬性清單(鍵和元素對) |
void store(OutputStream out, String comments) | 将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合于使用 load(InputStream)方法的格式寫入輸出位元組流 |
void store(Writer writer, String comments) | 将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合使用 load(Reader)方法的格式寫入輸出字元流 |
4.4.2 代碼示例
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class Demo06 {
public static void main(String[] args) throws IOException{
myStore();
myLoad(); //{33333=王五, 11111=張三, 22222=李四}
}
private static void myLoad() throws IOException{
Properties prop = new Properties();
FileReader fr = new FileReader("iodemo\\demo.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("11111","張三");
prop.setProperty("22222","李四");
prop.setProperty("33333","王五");
FileWriter fw = new FileWriter("iodemo\\demo.txt");
//store();方法 集合元素 寫入檔案
prop.store(fw,null);
fw.close();
}
4.5 案例
4.5.1 遊戲次數
import java.util.Random;
import java.util.Scanner;
//猜數字遊戲
public class GuessGame {
public static void game(){
Random r = new Random();
int i = r.nextInt(100) + 1;
while (true){
Scanner sc = new Scanner(System.in);
System.out.println("請輸入你猜的數字");
int i1 = sc.nextInt();
if (i > i1){
System.out.println("小了");
}else if (i < i1){
System.out.println("大了");
}else{
System.out.println("恭喜你猜對了,正确答案為:" + i);
break;
}
}
}
}
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
//遊戲次數
/*
1.寫一個遊戲類,裡面有一個猜數字的小遊戲
2.寫一個測試類
3.從檔案中讀取資料到Properties集合,用load()方法實作
檔案已經存在:game.txt
裡面有一個資料值:count=0
4.通過Properties集合擷取到玩遊戲的次數
5.判斷次數是否到到2次了
如果到了,給出提示:遊戲試玩已結束,想玩請充值(www.itcast.cn)
如果不到3次:
次數+1,重新寫回檔案,用Properties的store()方法實作
玩遊戲
*/
public class Test {
public static void main(String[] args) throws IOException {
Properties pt = new Properties();
FileReader fr = new FileReader("iodemo\\demo.txt");
//load();方法 将檔案内容存儲到Properties集合中
pt.load(fr);
//釋放資源
fr.close();
//getProperty();方法 鍵找值
String count = pt.getProperty("count");
//值是數字 将String轉成Int類型
int number = Integer.parseInt(count);
if (number>=2){
System.out.println("你的免費遊戲次數不足,請充值648繼續暢玩");
}else {
GuessGame.game();
number++;
//将元素存儲到集合
pt.setProperty("count",String.valueOf(number));
FileWriter fw = new FileWriter("iodemo\\demo.txt");
//store();方法 将集合中元素寫入檔案
pt.store(fw,null);
fw.close();
}
}
}