IO流

Input 輸入
Output 輸出

文件

java.io.File 它是對應者實際的文件或是文件夾(目錄)

new File(String 文件路徑)

new File("d:/1.txt");   // 可以使用 / 作爲分隔符
new File("D:\\MySQL");   // 可以使用 \ 作爲分隔符

或者可以使用 File.separator 獲取不同操作系統的分隔符

1. 文件對象的api

.isFile() ; 返回一個布爾值代表是否是文件
.isDirectory(); 返回一個布爾值代表是否是目錄

File 可以用來代表不存在的目錄或文件:
.mkdir() 來創建一個目錄
.mkdirs() 可以用來創建多級目錄

File file = new File("D:\\a\\b\\c");
file.mkdirs();

.exists() 用來判斷一個文件或目錄是否存在

.listFiles() 得到一個目錄下的所有子目錄和文件

File file = new File("D:\\6.23實訓班共享");
        File[] files = file.listFiles();
        for(File f: files) {
            System.out.println(f);
        }

可以使用FilenameFilter接口來過濾需要的文件或文件夾

File[] files2 = file.listFiles(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        if (name.startsWith("筆")) {
            return true;
        } else {
            return false;
        }
    }
});
for(File f :files2) {
    System.out.println(f);
}

刪除文件(立刻)

new File("D:\\6.23實訓班共享\\測試.txt").delete();

刪除文件(當程序運行結束)

new File("D:\\6.23實訓班共享\\測試.txt").deleteOnExit();

重命名和移動

new File("D:\\6.23實訓班共享\\測試.txt").renameTo(new File("c:\\測試2.txt"));

相對路徑

File file = new File("D:\\6.23實訓班共享\\代碼\\Day16-IO\\1.txt");// 絕對路徑
System.out.println(file.exists());

System.out.println(System.getProperty("user.dir")); // 當前目錄
File file2 = new File("1.txt"); // 相對路徑
System.out.println(file2.exists());
System.out.println(file2.getAbsoluteFile());

2.IO流

Input 輸入流: 從文件讀取內容,文件對我就是輸入流
Output 輸出流: 向文件寫入內容,文件對我就是輸出流

2.1 字節流(以字節爲單位操作數據)

InputStream 抽象類 -> FileInputStream 文件輸入流
OutputStream 抽象類 -> FileOutputStream 文件輸出流

讀取內容:

  1. 一次讀取一個字節

    // 1. 創建輸入流對象
        FileInputStream fis = new FileInputStream(new File("1.txt"));
    //        FileInputStream fis = new FileInputStream("1.txt")
    
        // 2. 讀取內容
        /*int read = fis.read();// 一次讀取一個字節, 返回int中只用了一個字節
        System.out.println((char)read);
        read = fis.read();
        System.out.println((char)read);
        read = fis.read();
        System.out.println((char)read);
        read = fis.read();
        System.out.println(read);*/
        while(true) {
            int read = fis.read();
            if(read == -1) {
                break;
            }
            System.out.println(read);
        }
  2. 一次讀取多個字節
    
    // 1. 創建輸入流對象
    FileInputStream fis = new FileInputStream(new File("1.txt"));

// 2. 一次讀取多個字節
byte[] buf = new byte[2];
/*int len = fis.read(buf);// 將讀到的內容填充到byte數組中,返回的是讀到的字節總數, 返回-1還是表示讀取完畢了
System.out.println(len);
System.out.println(Arrays.toString(buf));

len = fis.read(buf);
System.out.println(len);
System.out.println(Arrays.toString(buf));

len = fis.read(buf);
System.out.println(len);*/
while(true) {
int n = fis.read(buf);
if(n == -1) {
break;
}
System.out.println(Arrays.toString(buf));
}


> 特點: 流是單向的

3. 輸出流例子:
```java
// 1.創建了輸出流
FileOutputStream fos = new FileOutputStream("2.txt");

// 2. 向輸出流寫入內容
fos.write(97);
fos.write(98);
fos.write(99);

// 3. 關閉輸出流
fos.close();
  1. 文件的複製

    FileInputStream fis = new FileInputStream("1.txt");
        FileOutputStream fos = new FileOutputStream("3.txt");
    
        while(true) {
            byte[] buf = new byte[1024];
            int len = fis.read(buf);
            if(len == -1) {
                break;
            }
            fos.write(buf, 0, len); // 實際讀到len個字節,就寫入len個字節
        }
    
        fis.close();
        fos.close();

2.2 字符流

以字符爲單位處理流的內容

Reader 字符輸入流 InputStreamReader 將字節流轉爲字符流
Writer 字符輸出流 OutputStreamWriter 將字節流轉爲字符流

public static void main(String[] args) throws IOException {
    // 1. 將字節流轉換爲字符流
    FileInputStream fis = new FileInputStream("1.txt");
    // 注意:實際文件編碼要與讀取時的文件編碼一致
    InputStreamReader reader = new InputStreamReader(fis, "utf-8");

    // 2. 讀取
    /*while(true) {
        int c = reader.read();
        if(c == - 1) {
            break;
        }
        System.out.println((char)c);
    }*/
    while(true) {
        char[] buf = new char[1024];
        int len = reader.read(buf);
        if(len == -1) {
            break;
        }
        System.out.println(Arrays.toString(buf));
    }

    // 3. 關閉, 只需要關閉外層的流, 內部會幫我們關掉內層的流
    reader.close();
}

BufferedReader 在InputStreamReader的基礎上以行爲單位處理字符流
與 InputStreamReader是平級關係, 父類都是Reader

FileInputStream fis = new FileInputStream("1.txt");
InputStreamReader reader = new InputStreamReader(fis, "utf-8");
BufferedReader reader2 = new BufferedReader(reader);

/*System.out.println(reader2.readLine()); // 以行爲單位讀取數據
System.out.println(reader2.readLine()); // 以行爲單位讀取數據
System.out.println(reader2.readLine()); // 以行爲單位讀取數據*/

while(true) {
    String line = reader2.readLine();
    if(line == null) {
        break;
    }
    System.out.println(line);
}

reader2.close();

BufferedReader與InputStreamReader體現的是裝飾者模式

裝飾者模式
裝飾者與被裝飾者需要有一個共同的父類
裝飾者和被裝飾者之間體現的是組合的關係,而不是繼承的關係(目的是爲了更加靈活)
裝飾者會對被裝飾者做功能上的增強

Effective(高效的) JAVA 
    組合優於繼承
    字節流
InputStream
    (*) FileInputStream  從文件讀取字節
    (*) BufferedInputStream 加入緩衝功能,提高文件的讀取效率
    ByteArrayInputStream 從字節數組變成輸入流
OutputStream
    (*) FileOutputStream 向文件寫入字節
    (*) BufferedOutputStream 加入緩衝功能, 提高文件的寫入效率
    ByteArrayOutputStream 把流的內容寫入字節數組
    PrintStream 實際上就是 System.out

字符流
Reader
() InputStreamReader 轉換字節流爲字符流
(
) BufferedReader 功能增強,以行爲單位讀取數據 (裝飾器模式)
FileReader 是InputStreamReader子類,將字符編碼固定爲操作系統的默認編碼,不能手工改動
Writer
() OutputStreamWriter 轉換字節流爲字符流
(
) PrintWriter 以行爲單位寫入數據
write 當成字符寫入
print print就是將參數轉爲字符串後寫入
FileWriter 是OutputStreamWriter的子類,也是固定了字符編碼

java中的序列化

問題:如何將對象中的信息永久保存
1.將來將對象信息存入數據庫
2.java 中提供的序列化方式來永久保存數據

首先要讓類實現Serializable序列化接口
第二使用ObjectOutputStream 寫入要序列化的對象

public class Student implements Serializable{

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
```java
Student student = new Student();
student.setId(1);
student.setName("張三");

// 序列化就是將對象變爲輸出字節流
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:\\student.obj"));
os.writeObject(student);
os.close();

如果沒有實現Serializable接口,會出現NotSerializableException

注意:
1)要求對象中的所有屬性也都是可以序列化
2)如果某個屬性不想序列化,可以在屬性上加transient關鍵字

反序列化

把字節內容讀取進來,還原爲java對象
ObjectInputStream用來讀取字節內容,還原(反序列化)爲java對象

ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:\\student.obj"));
        Student s = (Student)is.readObject();
        System.out.println(s.getId());
        System.out.println(s.getName());
        System.out.println(s.getAddress());

除了可以寫入和讀取對象以外,還可以寫入和讀取基本類型(int,long,boolean...) ,讀取和寫入的順序要保持一致
如果不一致,出現EOFException
如果沒有更多內容,也會出現EOFException
建議在寫入時最後一個對象使用null,這樣讀取時就可以根據null來判斷是否讀取完畢

序列化和反序列化其實也是java中的一種數據傳輸的機制

創建對象的幾種方式:

  1. 反序列化
  2. clone 是一種
  3. new 是一種

克隆需要實現Cloneable接口,並覆蓋clone方法,克隆舉例:

public class Teacher implements Cloneable{ // 可克隆的

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 必須調用Object父類的克隆方法
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher t = new Teacher();
        t.setId(1);
        t.setName("滿老師");

        Teacher t2 = (Teacher)t.clone();
        System.out.println(t2.getId());
        System.out.println(t2.getName());

        System.out.println(t2 == t);
    }
}

克隆對應的設計模式:原型(prototype)模式 ,不走構造方法,根據一個已有對象創建新的對象。

使用Cloneable接口和clone克隆的對象,僅僅是淺拷貝,如果屬性爲引用類型,複製的僅是地址。沒有爲這個屬性創建新的對象

深拷貝 利用序列化和反序列化生成新的對象,也會爲屬性創建新的對象
例:

public class Teacher2 implements Serializable{

    private int id;
    private String name;
    private Date birthday;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Teacher2 clone() {
        try {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bos);
            os.writeObject(this); // 寫入當前對象
            byte[] bytes = bos.toByteArray(); // 字節結果

            // 反序列化
            ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytes));
            Teacher2 t = (Teacher2)is.readObject();
            return t;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        Teacher2 t = new Teacher2();
        t.setId(1);
        t.setName("李老師");
        t.setBirthday(new Date());

        Teacher2 t2 = t.clone();

        System.out.println(t == t2);
        System.out.println(t.getBirthday() == t2.getBirthday());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章