1. 程式人生 > >java核心技術-IO

java核心技術-IO

一 .IO

1.1 流的簡單介紹和分類

Java流操作的相關的類和介面:

Java流類圖結構:

四個抽象基類分別為:InputStream 、OutputStream 、Reader 、Writer;

流的概念:在Java中將輸入輸出抽象稱為為流,就好像水管,將兩個容器連線起來。流是一組有順序的,有起點和終點的位元組集合,是對資料傳輸的總稱和抽象,即資料在兩裝置間的傳輸稱為流

Java中IO所採用的設計模式:裝飾者模式

分類:

1.按流向不同:輸入流,輸出流(以程式為主體)

2.按型別不同:位元組流,字元流(字元流用於操作文字檔案 .txt .java 位元組流用於操作非文字檔案 .avi .rmvg .jpg .mp3)

3.按角色不同:節點流,處理流

注:若用位元組流操作文字檔案,會引起亂碼和效率低的問題。若用字元流去操作非文字檔案,不會報錯,但什麼也獲取不了。

1.2 常見節點流和處理流的使用方法

1.2.1 只使用節點流的複製貼上:

非文字檔案:

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //1.建立 FileInputStream 的例項,同時開啟指定檔案
            fis = new FileInputStream("1.jpg");
            fos = new FileOutputStream("2.jpg");
            
            byte[] b = new byte[1024];
            int len = 0;
            
            while((len = fis.read(b)) != -1){
                fos.write(b,0,len);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
        }

文字檔案:

        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader("1.txt");
            fw = new FileWriter("2.txt");
            
            char[] c = new char[100];
            int len = 0;
            
            while((len = fr.read(c)) != -1){
                fw.write(c, 0, len);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            if(fr != null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
1.2.2 帶上緩衝流的複製貼上

非文字檔案:

        BufferedOutputStream bos = null;
        BufferedInputStream  bis = null;
        try {
            FileInputStream fis  = new FileInputStream("1.jpg");
            FileOutputStream fos = new FileOutputStream("2.jpg");
            
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            
            byte[] b = new byte[1024];
            int len = 0;
            while((len = bis.read(b)) != -1){
                bos.write(b, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            if(bos != null){
                bos.close();
            }
            if(bis != null){
                bis.close();
            }
        }

文字檔案:

        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            FileReader fr = new FileReader("newFile.txt");
            FileWriter fw = new FileWriter("newFile2.txt");
            
            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);
            
            String str = null;
            
            while( (str = br.readLine()) != null){
                bw.write(str);
                bw.newLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(bw != null){
                bw.close();
            }
            if(br != null){
                br.close();
            }
        }

1.3 序列化與反序列化

主要使用物件流進行操作: ObjectInputStream 、ObjectOutputStream

序列化:將記憶體中的物件以二進位制的形式儲存在磁碟中

反序列化:將磁碟的物件讀取

準備工作: 需要提供一個序列化介面。序列號如果不顯示給出, 則會預設根據類資訊自動生成一個序列號,一旦類資訊傳送變動與序列化前不同,物件的反序列化將會丟擲異常,所以還是建議 顯示給出一個序列號。

關鍵字: transient 和 static修飾的屬性不會被序列化

1.3.1 序列化反序列化多個值

---序列化:

        //3. 建立物件流,包裝緩衝流,用於完成序列化
        ObjectOutputStream oos = null;
        try {
            int num = 10;
            boolean flag = false;
            String str = "abcde";
            
            //1.建立節點流,同時開啟指定檔案
            FileOutputStream fos = new FileOutputStream("./data.dat");
            
            //2.(可選)使用緩衝流包裝節點流,用於提高傳輸效率。
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            
            oos = new ObjectOutputStream(bos);
            
            oos.writeInt(num);
            oos.writeBoolean(flag);
            oos.writeUTF(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(oos != null){
                //5.關閉流
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

---反序列化:

        ObjectInputStream ois = null;
        try {
            FileInputStream fis = new FileInputStream("./data.dat");
            
            ois = new ObjectInputStream(fis);
            //反序列化的順序務 必和 序列化的順序保持一致
            int num = ois.readInt();
            boolean flag = ois.readBoolean();
            String str = ois.readUTF();
            
            System.out.println(num);
            System.out.println(flag);
            System.out.println(str);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
1.3.2 序列化和反序列化多個物件

---準備工作:

public class Person implements Serializable{

    private static final long serialVersionUID = 134628734823487283L;
    
    private String name;
    private int age;
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Person() {}
    
    public int getAge(){
        return age;
    }
    
    public String getName(){
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    
}

---序列化:

        //Person 務必要實現序列化介面
        Person p1 = new Person("張三",19);
        Person p2 = new Person("李四",20);
        Person p3 = new Person("王五",16);
        
        ObjectOutputStream oos = null;
        try {
            FileOutputStream fos = new FileOutputStream("person.dat");
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            
            oos = new ObjectOutputStream(bos);
            
            oos.writeObject(p1);
            oos.writeObject(p2);
            oos.writeObject(p3);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }   

---反序列化:

ObjectInputStream ois = null;
        try {
            FileInputStream fis = new FileInputStream("person.dat");
            BufferedInputStream bis = new BufferedInputStream(fis);
            ois = new ObjectInputStream(bis);
            
            Person p1 = (Person)ois.readObject();
            Person p2 = (Person)ois.readObject();
            Person p3 = (Person)ois.readObject();
            System.out.println(p1);
            System.out.println(p2);
            System.out.println(p3);
        }  catch (Exception e) {
            e.printStackTrace();
        }  finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

1.4 轉換流

轉換流:InputStreamReader & OutStreamWriter

編碼:字串 -> 位元組陣列

解碼:位元組陣列 -> 字串

        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            FileInputStream fis = new FileInputStream("hello.txt");
            InputStreamReader isr = new InputStreamReader(fis);
            br = new BufferedReader(isr);
            
            FileWriter fileWriter = new FileWriter("hello1.txt");
            bw = new BufferedWriter(fileWriter);
            String str = null;
            while((str = br.readLine()) != null){
                bw.write(str);
                bw.newLine();
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

1.5 隨機存取檔案類

RandomAccessFile 類支援"隨機訪問"的方式,程式可以跳到檔案的任意地方來讀寫檔案

支援只訪問檔案的部分內容

可以向已存在的檔案後追加內容

RandomAccessFile 物件包含一個記錄指標,用以標示當前讀寫處的位置。

RandomAccessFile 類物件可以自由移動記錄指標:

long getFilePointer():獲取檔案記錄指標的位置

void seek(long pos):將檔案記錄指標定位到pos位置

  • 構造器

public RandomAccessFile(File file,String mode)

public RandomAccessFile(String name,String mode)

  • 建立RandomAccessFile 類例項需要制定一個mode 引數, 該引數指定 RandomAccessFile的訪問模式:

r:以只讀方式開啟

rw:開啟以便讀取和寫入

rwd:開啟以便讀取和寫入;同步檔案內容的更新

rws:開啟以便讀取和寫入;同步檔案內容和元資料的更新

    /**
     * 在abcdef寫入檔案 再向abc中間 插入hello
     */
    @Test
    public void test4() throws IOException{
        RandomAccessFile randomAccessFile = new RandomAccessFile("hell.txt", "rw");
        String str = "abcdef";
        
        randomAccessFile.write(str.getBytes());
        
        randomAccessFile.seek(3);
        
        String line = randomAccessFile.readLine();
        
        randomAccessFile.seek(3);
        
        randomAccessFile.write("hello".getBytes());
        randomAccessFile.write(line.getBytes());
        
        randomAccessFile.close();
    }