天天看點

java入門篇(24) IO流拓展一、資料輸入輸出流的概述和使二、記憶體操作流三、列印流的概述和特點

文章目錄

  • 一、資料輸入輸出流的概述和使
    • 1.1 資料輸入輸出流的概述
    • 1.2 構造方法
    • 1.3 輸入輸出流的特點
    • 1.4 案例
  • 二、記憶體操作流
    • 2.1操作位元組數組
    • 2.2 操作字元數組
    • 2.3 操作字元串
  • 三、列印流的概述和特點
    • 3.1 列印流的分類
    • 3.2 列印流的特點
    • 3.3自動重新整理的方法
    • 3.4列印流複制文本檔案
    • 3.5 标準輸入輸出流概述和輸出語句的本質
    • 3.6 二種方式實作鍵盤錄入
    • 3.7 輸出語句用字元緩沖流改進

一、資料輸入輸出流的概述和使

1.1 資料輸入輸出流的概述

  • 資料輸入流: DataInputStream
  • 資料輸出流: DataOutputStream

1.2 構造方法

  • DataInputStream(InputStream in)

使用指定的底層 InputStream (位元組輸入流的超類)建立一個 DataInputStream。

  • DataOutputStream(OutputStream out)

建立一個新的資料輸出流,将資料寫入指定基礎輸出流(位元組輸出流的超類)。

1.3 輸入輸出流的特點

  • 可以寫基本資料類型,可以讀取基本資料類型
  • 讀資料的順序必須和寫資料的順序一緻

1.4 案例

注意:如果寫入的是字元數組,則讀的時候将字元數組作為read()的參數。

public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
        DataOutputStream b = new DataOutputStream(new FileOutputStream("b.txt"));
        DataInputStream  a = new DataInputStream(new FileInputStream("b.txt"));
        b.write(12);
        b.write(new byte[]{'a','b','c'});
        b.writeUTF("張");
        System.out.println(a.read());
        System.out.println(a.read(new byte[]{'a','b','c'}));
        System.out.println(a.readUTF());
        a.close();
        b.close();
    }
}
           

二、記憶體操作流

特點:不關聯檔案,所有資料的操作都在記憶體中完成,記憶體操作流也無需關閉

2.1操作位元組數組

2.1.1

  • ByteArrayOutputStream
  • ByteArrayInputStream

2.1.2 特點:

  • 此流關閉無效,是以無需關閉
  • ByteArrayOutputStream實作了一個輸出流,其中的資料被寫入一個數組裡,随着資料的傳輸,數組的容量不斷的增加。
  • 通過toByteArray()和toString()方法将緩沖區的位元組轉換為字元串。

2.1.3

案例

一次讀取一個位元組數組:

public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
       ByteArrayOutputStream a = new ByteArrayOutputStream();
       a.write(88);
       a.write(new byte[]{'s','w','w'});
       a.write("棧".getBytes());
        byte[] array = a.toByteArray();
        System.out.println(new String(array));
        System.out.println(a.toString());

        ByteArrayInputStream b = new ByteArrayInputStream(array);
        byte[] arrays = new byte[1024];
        int len = b.read(arrays);
        System.out.println(new String(arrays, 0, len));
    }
}

           

一次讀取一個位元組

int by = 0 ;
	while((by = bais.read()) != -1){
		System.out.println((char)by);//注意這裡無法轉換成字元
}
           

2.2 操作字元數組

  • CharArrayWrite
  • CharArrayReader

特點:

  • 也是通過toCharArray()方法和toString()方法來擷取緩沖區中的内容。
  • 可以寫入字元串

2.3 操作字元串

  • StringWriter
  • StringReader

特點:

  • 通過toString()方法獲得緩沖區内容,但是都在一行

三、列印流的概述和特點

3.1 列印流的分類

  • 位元組流列印流
  • 字元列印流
  • PrintStream
//PrintStream(File file)
//建立具有指定檔案且不帶自動行重新整理的新列印流。
public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
       PrintStream out = new PrintStream(new File("b"));
        out.println('b');
        out.println('c');
        out.flush();
        out.close();  
        }
 }
           
  • PrintWriter
public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
      PrintWriter a = new PrintWriter(new File("d:\\a.txt"));
      a.println(23);
      a.print(false);
      a.flush();
      a.close();
    }
}

           

3.2 列印流的特點

  • 不關聯源檔案,隻能輸出資料,不能對讀取資料
  • 可以操作任意資料類型的資料 調用print() 方法可以寫任意資料類型
  • 如果我們啟用自動重新整理,那麼在調用println、printf 或 format 方法中的一個方法的時候,會完成自動重新整理
  • 這個流可以直接對檔案進行操作, 就是構造方法的參數可以傳遞檔案或者檔案路徑

3.3自動重新整理的方法

通過以下構造建立對象 能夠啟動自動重新整理 然後調用println、printf 或 format 方法中的一個方法的時候,會完成自動重新整理

  • public PrintWriter(OutputStream out, boolean autoFlush)

    啟動自動重新整理,第二個參數傳入true

案例:

public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
      PrintWriter a = new PrintWriter(new FileOutputStream("d:\\a.txt"), true);
      a.println(23);
      a.print(false);
      a.print("sddfss");
      a.close();
    }
}
           
  • public PrintWriter(Writer out, boolean autoFlush)
public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
        PrintWriter a = new PrintWriter(new FileWriter("d:\\a.txt"), true);
        a.println(23);
        a.print(false);
        a.print("sddfss");
        a.close();
    }
}
           

3.4列印流複制文本檔案

public class DataInputstream_text1 {
    public static void main(String[] args) throws IOException {
        FileInputStream a = new FileInputStream("a.txt");
        PrintWriter a1 = new PrintWriter("d:\\a.txt");
        PrintStream a2 = new PrintStream(System.out);
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = a.read(bytes)) != -1) {
            a1.print(new String(bytes, 0, len));
        }
        a.close();
        a1.close();
    }
}

           

3.5 标準輸入輸出流概述和輸出語句的本質

在System這個類中存在兩個靜态的成員變量:

  • public static final InputStream in

    标準輸入流, 對應的裝置是鍵盤

  • public static final PrintStream out

    标準輸出流 , 對應的裝置就是顯示器

  • System.in的類型是InputStream.
  • System.out的類型是PrintStream是OutputStream的孫子類FilterOutputStream 的子類

3.5.1輸出語句的本質

// 擷取标準輸出流
		PrintStream ps = System.out ;
		// 寫資料
		ps.println(23) ;
		ps.println("你好呀") ;
		System.out.println("你好呀") ;
		System.out.println();

           

3.6 二種方式實作鍵盤錄入

  • Scanner
  • BufferedReader的readLine方法。

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

3.7 輸出語句用字元緩沖流改進

擷取System下的in成員變量

InputStream in = System.in ;

是一個位元組輸入流對象,那麼我們就可以通過這個位元組輸入流對象進行讀取鍵盤錄入的資料.

* 那麼我們在這個地方使用那種讀取方式. 經過分析,這兩種讀取方式都不太合适.因為資料是客戶通過鍵盤錄入
	 * 進來的,而我們希望直接讀取一行資料. 而既然要讀取一行資料,那麼我們就需要使用readLine方法,而這個方法
	 * 是屬于BufferedReader的方法,而我們就需要建立一個BufferedReader對象進行讀取資料.而我們這in有屬于
	 * 位元組流,而建立BufferedReader對象的時候需要一個字元流,而我們就需要将這個位元組流轉換成字元流,那麼既然
	 * 要對其進行轉換,那麼就需要使用轉換流. 需要使用InputStreamReader
	 */
           

// // 把in通過轉換流轉換成一個字元流

// InputStreamReader isr = new InputStreamReader(in) ;

//

// // 建立BufferedReader對象

// BufferedReader br = new BufferedReader(isr) ;

// 建立BufferedReader對象
	BufferedReader br = new BufferedReader(new InputStreamReader(in)) ;
	
	// 讀取資料
	/**
	 * 想結束就需要自定義結束标記. 886
	 */
	String result = null ;
	while((result = br.readLine()) != null){
		if("886".equals(result)){
			break ;
		}
		System.out.println(result);
	}
	
	// 釋放資源
	br.close() ;
           

###22.11_IO流(随機通路流概述和寫出資料)(了解)

A:随機通路流概述
	RandomAccessFile概述 最大特點 能讀能寫
	RandomAccessFile類不屬于流,是Object類的子類。但它融合了InputStream和OutputStream的功能。
	支援對随機通路檔案的讀取和寫入。

	 RandomAccessFile的父類是Object , 這個流對象可以用來讀取資料也可以用來寫資料.可以操作任意資料類型的資料.
           
  • 我們可以通過getFilePointer方法擷取檔案指針,并且可以通過seek方法設定檔案指針
               
    B:案例示範: 随機通路流寫出資料
    // 建立對象
     RandomAccessFile raf = new RandomAccessFile("raf.txt" , "rw");
     
     // 寫資料
     raf.writeInt(100) ;
     raf.writeChar('中') ;
     raf.writeUTF("你好") ;
     
     // 釋放資源
     raf.close() ;
               

###22.12_IO流(随機通路流讀取資料和操作檔案指針)(了解)

A:案例示範:	随機通路流讀取資料和操作檔案指針

	// 建立對象
	RandomAccessFile raf = new RandomAccessFile("raf.txt" , "rw");
	
	// 讀取資料
	int a = raf.readInt() ;
	System.out.println(a);	
	System.out.println(raf.getFilePointer());//4 擷取檔案指針 按位元組擷取的 寫了個int 是以是4
	
	char ch = raf.readChar() ;
	System.out.println(ch);
	System.out.println(raf.getFilePointer());// 擷取檔案指針
	
	String result = raf.readUTF() ;//這裡會多讀兩個位元組 是因為writeUTF("你好") 會多寫兩個位元組
	System.out.println(result);
	System.out.println(raf.getFilePointer());
	
	// 設定檔案指針的位置 可以往回讀
	raf.seek(4) ;
	ch = raf.readChar() ;
	System.out.println(ch);
	
	// 釋放資源
	raf.close() ;
           

###22.13_IO流(序列化流和反序列化流的概述和使用)(了解)

A:序列化流的概述
	所謂的序列化:就是把對象通過流的方式存儲到檔案中.注意:此對象 要重寫Serializable 接口才能被序列化
	反序列化:就是把檔案中存儲的對象以流的方式還原成對象
	序列化流:	ObjectOutputStream
	反序列化流:	ObjectInputStream
           

像這樣一個接口中如果沒有方法,那麼這樣的接口我們将其稱之為标記接口(用來給類打标記的,相當于豬肉身上蓋個章)

一個對象可以被序列化的前提是這個對象對應的類必須實作Serializable接口

B:案例示範:	對象序列化和反序列化的基本使用

序列化
// public ObjectOutputStream(OutputStream out)
	ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt")) ;
	
	// 建立對象
	Student s = new Student("劉亦菲" , 18) ;
	
	// public final void writeObject(Object obj)
	oos.writeObject(s) ;
	
	// 釋放資源
	oos.close() ;
           
反序列化
	// public ObjectInputStream(InputStream in)
	ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt")) ;
	
	// public final Object readObject()
	Object obj = ois.readObject() ;	
	
	// 向下轉換
	Student s = (Student)obj ;
	System.out.println(s.getName() + "----" + s.getAge());
			
	// 釋放資源
	ois.close() ;
           

###22.14_IO流(如何解決序列化時候的黃色警告線問題)(了解)

A:案例示範:	解決序列化時候的黃色警告線問題
           
  • 我們的一個類可以被序列化的前提是需要這個類實作Serializable接口,就需要給這個類添加一個标記.
  • 在完成序列化以後,序列化檔案中還存在一個标記,然後在進行反序列化的時候,

    會驗證這個标記和序列化前的标記是否一緻,如果一緻就正常進行反序列化,如果

  • 不一緻就報錯了. 而現在我們把這個類做了修改,将相當于更改了标記,而導緻這兩個标記不一緻,就報錯了.
  • 解決問題: 隻要讓這個兩個标記一緻,就不會報錯了吧
  • 怎麼讓這兩個标記一緻呢? 不用擔心,很簡單,難道你們沒有看見黃色警告線嗎? ctrl + 1 , 生成出來

###22.15_IO流(如何讓對象的成員變量不被序列化)(了解)

A:案例示範:	如何讓對象的成員變量不被序列化
	使用transient關鍵字聲明不需要序列化的成員變量

	private transient int age ;// 可以阻止成員變量的序列化使用transient
           

###22.16_IO流(Properties的概述和作為Map集合的使用)(掌握)

A:Properties的概述
	檢視API
	Properties 類表示了一個持久的屬性集。
	Properties 可儲存在流中或從流中加載。
	屬性清單中每個鍵及其對應值都是一個字元串。
	Properties父類是Hashtable
           
  • 屬于雙列集合,這個集合中的鍵和值都是字元串 Properties不能指定泛型
               

    B:案例示範: Properties作為Map集合的使用

    // 建立一個Properties對象

    Properties prop = new Properties() ;

    // 添加元素
     prop.put("張三", "23") ;
     prop.put("李四", "24") ;
     prop.put("王五", "25") ;
     
     // 周遊
     // 第一種方式: 通過鍵找值
               

// Set keySet = prop.keySet() ;

// for(Object obj : keySet){

//

// // 通過鍵找值

// Object object = prop.get(obj) ;

// System.out.println(obj + “----” + object);

// }

// 第二種方式: 通過鍵值對對象擷取鍵和值
	Set<Entry<Object,Object>> entrySet = prop.entrySet() ;
	
	for(Entry<Object,Object> en : entrySet){
		
		// 擷取鍵
		Object key = en.getKey() ;
		Object value = en.getValue() ;
		
		// 輸出
		System.out.println(key + "---" + value);
		
	}
           

###22.17_IO流(Properties的特殊功能使用)(掌握)

A:Properties的特殊功能
	public Object setProperty(String key,String value)
	public String getProperty(String key)
	public Set<String> stringPropertyNames()
B:案例示範:	Properties的特殊功能


// 建立對象
	Properties prop = new Properties() ;
	
	// public Object setProperty(String key,String value):	添加元素
	/**
	 * 第一次添加元素的時候傳回的是null
	 * 下一次添加元素的時候傳回的是上一次鍵對應的值
	 */
	System.out.println(prop.setProperty("文章", "馬伊琍")) ;
           

// System.out.println(prop.setProperty(“文章”, “姚笛”)) ;

prop.setProperty(“玉帝”, “王母”) ;

prop.setProperty(“賈寶玉”, “林黛玉”) ;

// public String getProperty(String key):根據鍵擷取值
           

// System.out.println(prop.getProperty(“文章”));

// System.out.println(prop.getProperty(“文章2”));

// public Set<String> stringPropertyNames():擷取所有的鍵對應的Set集合
           

// Set names = prop.stringPropertyNames() ;

// for(String name : names){

// System.out.println(name);

// }

/**
	 * Properties集合的特有的周遊方式:	根據鍵找值
	 */
	Set<String> names = prop.stringPropertyNames() ;
	for(String name : names){
		
		// 擷取值
		String value = prop.getProperty(name) ;
		
		// 輸出
		System.out.println(name + "----" + value);
		
	}
	
	// 輸出
	System.out.println("prop:" + prop);
           

###22.18_IO流(Properties的load()和store()功能)(掌握)

A:Properties的load()和store()功能
	 Properties和IO流進行配合使用:
           
  • public void load(Reader reader): 讀取鍵值對資料把資料存儲到Properties中
               
  • public void store(Writer writer, String comments)把Properties集合中的鍵值對資料寫入到檔案中, comments注釋
               

    B:案例示範

    Properties的load()和store()功能

    存資料到文本檔案中

    // 建立Properties集合對象

    Properties prop = new Properties() ;

    // 添加元素
     prop.setProperty("張三", "23") ;
     prop.setProperty("李四", "24") ;
     prop.setProperty("王五", "25") ;
     
     // public void store(Writer writer, String comments)	把Properties集合中的鍵值對資料寫入到檔案中, comments注釋
     // 建立輸出流對象
     FileWriter fw = new FileWriter("userInfo.txt") ;
     prop.store(fw, "姓名和年齡對應資訊") ;
     
     // 釋放資源
     fw.close() ;
               
    從文本檔案中讀取資料

###22.19_IO流(判斷檔案中是否有指定的鍵如果有就修改值的)(掌握)

A:案例示範
	需求:我有一個文本檔案,我知道資料是鍵值對形式的,但是不知道内容是什麼。
	      請寫一個程式判斷是否有“lisi”這樣的鍵存在,如果有就改變其值為”100”

	 分析:
           
  • a:  把文本檔案中的資料加載到Properties集合中
               
  • b:  判斷這個集合中是否有"lisi"這個鍵
               
  • 如果有直接修改其值為100
               
  • c:  把集合中的資料再次存儲到文本檔案中
               

// 建立Properties集合

Properties prop = new Properties() ;

// 把文本檔案中的資料加載到Properties集合中
	prop.load(new FileReader("names.txt")) ;
	
	// 擷取所有的鍵對應的set集合
	Set<String> names = prop.stringPropertyNames() ;
	
	// 判斷
	if(names.contains("lisi")){
		
		// 修改其值
		prop.setProperty("lisi", "100") ;//鍵相同,值覆寫
		
	}
	
	// 把集合中的資料存儲到文本檔案中
	prop.store(new FileWriter("names.txt"), null) ;
           

###22.19_IO流(SequenceInputStream)(掌握)

A:案例需求:将a.txt和b.txt兩個文本檔案的内容合并到c.txt

B:案例需求:采用SequenceInputStream來改進

C:作業:将一個music.mp3檔案,拆分成多個小檔案,再将多個小檔案,合并成一個mp3檔案

D:SequenceInputStream 
	表示其他輸入流的邏輯串聯。
	它從輸入流的有序集合開始,
	并從第一個輸入流開始讀取,直到到達檔案末尾,接着從第二個輸入流讀取,
	依次類推,直到到達包含的最後一個輸入流的檔案末尾為止
	a:構造方法
	SequenceInputStream(InputStream s1, InputStream s2) 
	通過記住這兩個參數來初始化新建立的 SequenceInputStream(将按順序讀取這兩個參數,先讀取 s1,然後讀取 s2),
	以提供從此 SequenceInputStream 讀取的位元組。
	b:構造方法
	SequenceInputStream(Enumeration<? extends InputStream> e) 
	 通過記住參數來初始化新建立的 SequenceInputStream,該參數必須是生成運作時類型為 InputStream 對象的 Enumeration 型參數。
           

###22.20_day22總結