day12_面向對象(緩衝流、轉換流、序列化流和打印流)
一.緩衝流
1.緩衝流的作用
緩衝流也叫高效流,它是對普通流的增強,增強再性能方面
2.緩衝流的分類
字節輸入流 ——> 緩衝字節輸入流
InputStream ——> BufferedInputStream
字節輸出流 ——> 緩衝字節輸出流
OutputStream ——> BufferedOutputStream
字符輸入流 ——> 緩衝字符輸入流
Reader ——> BufferedReader
字符輸出流 ——> 緩衝字符輸出流
Writer ——> BufferedWriter
3.字節緩衝流的介紹和使用
a.字節緩衝流的構造
public BufferedInputStream(InputStream in);緩衝流創建需要普通流
public BufferedOutputStream(OutputStream out);緩衝流創建需要普通流
b.字節緩衝流的高效測試
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
//調用
long start = System.currentTimeMillis();
copy03();
long end = System.currentTimeMillis();
System.out.println("耗時:" + (end - start) + "毫秒...");
}
//定義方法:複製文件
//使用緩衝流
//定義方法:複製文件
//使用緩衝流 耗時:169毫秒...
public static void copy03()throws IOException {
//1.緩衝字節輸入流
// FileInputStream fis = new FileInputStream("1.avi");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.avi"));
//2.緩衝字節輸出流
// FileOutputStream fos = new FileOutputStream("copy.avi");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
//3.複製,採用字節數組
byte[] bs = new byte[1024 * 100];
int len = 0;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
//4.釋放資源
bos.close();
// fos.close();
bis.close();
// fis.close();
}
//定義方法:複製文件
//使用緩衝流 耗時:4111毫秒...
public static void copy02()throws IOException {
//1.緩衝字節輸入流
// FileInputStream fis = new FileInputStream("1.avi");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.avi"));
//2.緩衝字節輸出流
// FileOutputStream fos = new FileOutputStream("copy.avi");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
//3.複製
int b = 0;
while ((b = bis.read()) != -1) {
bos.write(b);
}
//4.釋放資源
bos.close();
// fos.close();
bis.close();
// fis.close();
}
//定義方法:複製文件
//使用普通流
public static void copy01() throws IOException {
//1.字節輸入流
FileInputStream fis = new FileInputStream("1.avi");
//2.字節輸出流
FileOutputStream fos = new FileOutputStream("copy.avi");
//3.一個一個字節慢慢來
int b = 0;
while ((b = fis.read()) != -1) {
fos.write(b);
}
//4.關閉
fos.close();
fis.close();
}
}
4.字符緩衝流的介紹和使用
a.字符緩衝流的構造
public BufferedReader(Reader r); 創建緩衝字符流需要普通字符流
public BufferedWriter(Writer w);創建緩衝字符流需要普通字符流
b.字符緩衝流的2個特有方法
BufferedReader緩衝字符輸入流
public String readLine(); 一次讀取一行
public class BufferedReaderDemo {
public static void main(String[] args) throws Exception {
//1.創建BufferedReader對象
BufferedReader br = new BufferedReader(new FileReader("1.txt"));
//2.讀取數據
// String line = br.readLine();
// System.out.println(line);
//一次讀取一行的標準循環代碼
String line = "";
/**
* (line = br.readLine()) != null
* a.先讀一行
* b.賦值 line = 一行的內容
* c.判斷 line != null
*/
while ((line = br.readLine()) != null) {
System.out.println(line);
}
//3.釋放資源
br.close();
}
}
BufferedWriter緩衝字符輸出流
public void newLine(); 寫一個跨平臺的換行符
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//1.創建一個BufferedWriter對象
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
//2.寫數據
for (int i = 0; i < 10; i++) {
bw.write("java");
//bw.write("\r\n"); //Java是跨平臺
bw.newLine();//寫一個跨平臺換行符
}
//3.釋放資源
bw.close();
}
}
5.綜合練習:文本排序
將一個文件中的內容讀取,根據每一行的編號,從小到大寫到另一個文本文件中
public class BufferedTestDemo {
public static void main(String[] args) throws Exception {
// 綜合練習:文本排序
// 將一個文件中的內容讀取,根據每一行的編號,從小到大寫到另外一個文本文件中
//1.將原文本一行一行讀取出來,保存到集合中
ArrayList<String> lines = new ArrayList<String>();
//讀取文本
BufferedReader br = new BufferedReader(new FileReader("csb.txt"));
//循環
String line = "";
while ((line = br.readLine()) != null) {
//保存到集合
lines.add(line);
}
//釋放資源
br.close();
//3.對集合中文本進行排序
Collections.sort(lines, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//口訣:升序 前 - 後
return o1.charAt(0) - o2.charAt(0);
}
});
//4.寫到另外一個文本中
BufferedWriter bw = new BufferedWriter(new FileWriter("csb02.txt"));
for (String str : lines) {
bw.write(str);
//換行
bw.newLine();
}
bw.close();
}
}
二.轉換流*******************
1.字符集
是一個平臺所能支持的所有字符的集合(文字、符號、圖形、數字)(編碼表等於字符集加碼值)
2.字符編碼(編碼和解碼)
就是指每一個字符和對應碼值的轉換規則
編碼:把字符轉成對應的碼值 比如:a --> 97
解碼:把碼值轉成對應的字符 比如:97 --> a
擴展:
常見的字符集和字符編碼
a.ascii字符集(美國標準信息交換代碼) 包含英文字母,英文標點,阿拉伯數字(128個)
其對應的字符編碼ascii編碼,在ascii編碼中所有的字符只佔一個字節
b.GBXXXX字符集
GB2312字符集 含有大概7000多個漢字(簡體常用漢字)
GBK字符集 含有大概兩萬多個漢字(簡體和繁體漢字以及日韓漢字)
GB18030字符集 含有大概70000多個漢字(目前還沒有啓用)
GBXXXX字符集對應的字符編碼稱爲GBK編碼,在GBK編碼中一箇中文佔2個字節
c.Unicode字符集
萬國字符集(全球幾乎所有國家的字符都在此字符集中)
Unicode字符集對應的字符編碼稱爲UTF-8編碼,UTF-16編碼,UTF-32編碼
在UTF-8編碼中一箇中文佔3個字節
d.ISO-8859-1字符集
拉丁字符集(西歐國家)
ISO-8859-1字符集採用ISO-8859-1字符編碼,每一個字符佔一個字節(二進制都是1開頭,表示負數,ascii碼值中二進制都是0開頭的,故不衝突)
以後我們的服務器(Tomcat7.0)默認採用就是ISO-8859-1,我們需要手動改爲GBK或者UTF-8
3.編碼引出的問題
總結:只要是亂碼,99%的情況下都是由編碼不一致引起的
比如文本是GBK,讀取時,IDEA默認使用的是UTF-8,所以出現亂碼
public class LuanMaDemo {
public static void main(String[] args) throws Exception {
//1.讀取文件 2.txt(記事本默認是GBK編碼)
FileReader fr = new FileReader("2.txt"); //IDEA中讀取中時,默認UTF-8
//2.讀取一個字符
int read = fr.read();
System.out.println((char) read);
//3.釋放資源
fr.close();
}
}
4.使用轉換流InputStreamReader解決中文問題
InputStreamReader extends Reader
1.構造方法
public InputStreamReader(InputStream in, String charsetName); 指定編碼
public InputStreamReader(InputStream in); 默認和IDEA一樣(UTF-8)
2.使用InputStreamReader讀取不同編碼的文件(代碼演示)
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception {
//1.創建一個InputStreamReader對象
// InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"), "gbk");
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"), "gbk");
//2.讀
int read = isr.read();
System.out.println((char) read);
read = isr.read();
System.out.println((char) read);
read = isr.read();
System.out.println((char) read);
//2.釋放資源
isr.close();
}
}
5.使用轉換流OutputStreamWriter寫中文
OutputStreamWriter extends Writer
1.構造方法
public OutputStreamWriter(InputStream in, String charsetName); 指定編碼
public OutputStreamWriter(InputStream in); 默認和IDEA一樣UTF-8編碼
public static void main(String[] args) throws Exception {
//1.寫文件
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf8.txt"),"UTF-8");
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
//2.寫數據
osw.write('你');
osw.write('好');
//3.釋放資源
osw.close();
}
}
6.練習:轉換文件編碼****************
練習:將GBK編碼的文件,轉換爲UTF-8編碼的文本文件
public class TestDemo {
public static void main(String[] args) throws Exception {
// 6.練習:轉換文件編碼**********************
// 需求:將GBK編碼的文本文件,轉換爲UTF-8編碼的文本文件。
//1.創建一個轉換輸入流
InputStreamReader isr = new InputStreamReader(new FileInputStream("test_gbk.txt"),"gbk");
//2.創建一個轉換輸出流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test_utf.txt"), "utf-8");
//3.一邊讀 一邊寫
int ch = 0;
while ((ch = isr.read()) != -1) {
osw.write(ch);
}
//4.釋放資源
osw.close();
isr.close();
}
}
三.序列化流
1.什麼是序列化流
字符流:以字符爲單位操作數據
字節流:以字節爲單位操作數據
序列化流:也叫對象流,以對象爲單位操作數據 序列化流:對象的輸出流,寫對象
ObjectOutputStream
反序列化流:對象的輸入流,讀對象
ObjectInputStream
2.ObjectOutputStream的介紹和使用
a.構造方法
public ObjectOutputStream(OutputStream out);
創建序列化流需要普通的字節輸出流
b.序列化操作的前提
被序列化的對象必須使用java.io.Serializable接口
c.序列化操作(代碼演示)
public class Dog implements Serializable{
int age;
String name;
int legs;
public Dog() {
}
public Dog(int age, String name, int legs) {
this.age = age;
this.name = name;
this.legs = legs;
}
@Override
public String toString() {
return "Dog{" +
"age=" + age +
", name='" + name + '\'' +
", legs=" + legs +
'}';
}
}
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException {
//1.創建一個ObjectOutputStream對象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
//3.寫對象
//NotSerializableException
Dog d = new Dog(2, "旺財", 3);
oos.writeObject(d);
//3.釋放資源
oos.close();
}
}
3.ObjectInputStream的介紹和使用
ObjectinputStream對象的輸入流,也叫反序列化流
a.構造方法
public ObjectInputStream(InputStream in); 創建反序列化時需要普通的字節輸入流
b.反序列操作(正常演示)
public class ObjectStreamDemo01 {
public static void main(String[] args) throws Exception {
//1.創建ObjectInputStream對象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
//2.讀對象
Object obj = ois.readObject();
System.out.println(obj);
//3.釋放資源
ois.close();
}
}
c.反序列化操作的兩種錯誤演示
i.InvalidClassException 無效類異常
原因:序列化之後,反序列化之前,修改了類的源碼
ii.ClassNotFoundException 找不到類異常
原因:序列化之後,反序列化之前,直接刪除類
d.序列化流通過對比類的序列化版本號,判斷類是否有效的
每一個實現java.io.Serializable接口會自動生成一個版本號,當內容發生改變之後,版本號會重新計算,生成新的版本號,所以,反序列化時對比流中對象的版本號和本地類的對象的版本號,不一致就拋出異常 e.序列化版本號允許程序員自己管理,但是版本自己管理必須是以下格式:
public static final long seriralVersionUID = 值;
f.關鍵字: transient (''括起來表示默認值)
transient關鍵字修飾成員變量
作用:被transient修飾的成員和以前沒有任何區別!!!
當序列化流序列化該對象時,忽略有transient標記的成員變量
4.;練習:如果需要序列化多個對象怎麼操作?********************
解決方案:創建一個結合,把多個對象保存到這個集合對象中
public class ObjectStreamTestDemo {
public static void main(String[] args) throws Exception {
readArrayList();
}
public static void readArrayList() throws Exception {
//1.創建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt"));
//2.讀對象
ArrayList<Dog> dogs = (ArrayList<Dog>) ois.readObject();
for (Dog dog : dogs) {
System.out.println(dog);
}
//3.釋放資源
ois.close();
}
public static void writeArrayList() throws IOException {
//1.有多個對象
Dog d1 = new Dog(1, "旺1財", 2);
Dog d2 = new Dog(2, "旺2財", 3);
Dog d3 = new Dog(3, "旺3財", 4);
Dog d4 = new Dog(4, "旺4財", 5);
//2.要將這些對象保存到集合中
ArrayList<Dog> dogs = new ArrayList<Dog>();
Collections.addAll(dogs, d1, d2, d3, d4);
//3.只要序列化這個集合對象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt"));
//4.寫對象
oos.writeObject(dogs);
//5.釋放資源
oos.close();
}
}
四.打印流
1.打印流PrintStream的介紹
a.所見即所得
b.打印流不會拋出IOException
2.PrintStream的構造和常用方法
構造方法:
public printStream(String pathname);
public printStream(File file);
public publicStream(OutputStream out);
成員方法:
public void print(任意數據類型); 打印數據但是不換行
public void println(任意數據類型); 打印數據且換行
public class PrintStreamDemo {
public static void main(String[] args) throws Exception {
//1.創建一個打印流
PrintStream ps = new PrintStream("print.txt");
// PrintStream ps = new PrintStream(new File("print.txt"));
// PrintStream ps = new PrintStream(new FileOutputStream("print.txt"));
//2.打印 (特點:所見即所得)
// ps.print('a');
// ps.print(97);
// ps.print("java");
// ps.print(3.14);
// ps.print(true);
// ps.print(false);
ps.println('a');
ps.println(97);
ps.println("java");
ps.println(3.14);
ps.println(true);
ps.println(false);
//2.釋放資源
ps.close();
}
}
3.擴展_修改打印流的流向
打印流:System.out.println(); 之前一直在用
public class PrintStreamDemo02 {
public static void main(String[] args) throws Exception {
// PrintStream ps = System.out;
System.out.println("HelloWorld");
System.out.println("HelloWorld");
System.out.println("HelloWorld");
System.out.println("HelloWorld");
//修改System.out這個打印的方向
PrintStream ps = new PrintStream("111.txt");
// System.out = ps;
System.setOut(ps);
//測試
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
}
}
總結:
-[] 能夠使用字節緩衝流中流讀取數據到程序
BufferedInputStream
-[] 能夠使用字節緩衝流寫出數據到文件
BufferedOutputStream
-[] 能夠明確字符緩衝流的作用和基本用法
-[] 能夠使用緩衝流的特殊功能
BufferedReader
public String readLine();
BufferedWriter
public void newLine();
-[] 能夠闡述編碼表的意義
-[] 能夠使用轉換流讀取指定編碼的文本文件
InputStreamReader FileReader
-[] 能夠使用轉換流寫入指定編碼的文本文件
OutputStreamWriter FileWriter
-[] 能夠使用序列化流寫出對象到文件
ObjectOutputStream
-[] 能夠使用反序列化流讀取文件到程序中
ObjectInputStream