天天看點

Java學習記錄 Day17(IO流)

文章目錄

  • ​​Day 17​​
  • ​​IO流​​
  • ​​IO流的異常處理​​
  • ​​IO流的經典算法​​

Day 17

2019年5月18日。

這是我學習Java的第十七天。

這一天,我學到了以下的知識。

IO流

IO流,用來處理裝置之間的資料傳輸,Java對資料的操作是通過流的方式,而Java用于操作流的對象都在IO包中

IO流按照資料流向,可分為:輸入流(從硬碟讀取資料到記憶體),輸出流(從記憶體寫入資料到硬碟)

IO流按照資料類型,可分為:

  • 位元組流

    可以讀寫任何類型的檔案,比如音頻、視訊、文本檔案

    抽象基類如下:

  • InputStream

    常用具體子類:1.FileInputStream

    構造方法:​

    ​FileInputStream(File file)​

    ​:通過打開一個到實際檔案的連接配接來建立一個 FileInputStream,該檔案通過檔案系統中的 File 對象 file 指定

    ​FileInputStream(String name)​

    ​:通過打開一個到實際檔案的連接配接來建立一個 FileInputStream,該檔案通過檔案系統中的路徑名 name 指定

    常用的成員方法

  • 讀取功能
  • ​int read(byte[] b)​

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

    - 當該方法傳回 -1 時,表明已經讀完了資料。一般可用該值來判斷資料是否已經周遊完成

  • 關閉功能
  • ​public void close() throws IOException​

    ​:關閉檔案流,釋放資源

2.BufferedInputStream

為了對應BufferedOutputStream,Java提供了BufferedInputStream

構造方法:​

​BufferedInputStream(InputStream in)​

​:建立一個 BufferedInputStream 并儲存其參數,即輸入流 in,以便将來使用

  • OutputStream

    常用具體子類:1.FileOutputStream

    構造方法:​

    ​FileOutputStream(File file)​

    ​:建立一個向指定 File 對象表示的檔案中寫入資料的檔案輸出流

    ​FileOutputStream(String name)​

    ​:建立一個向具有指定名稱的檔案中寫入資料的輸出檔案流

    常用的成員方法

  • 寫入功能
  • ​public void write(int b)​

    ​:寫一個位元組 超過一個位元組 砍掉前面的位元組
  • ​public void write(byte[] b)​

    ​:寫一個位元組數組
  • ​public void write(byte[] b,int off,int len)​

    ​:寫一個位元組數組的一部分
  • 關閉功能
  • ​public void close() throws IOException​

    ​:關閉檔案流,釋放資源

    面試題:為什麼一定要close()?

    a: 通知系統釋放關于管理a.txt檔案的資源

    b: 讓Io流對象變成垃圾,等待垃圾回收器對其回收

2.BufferedOutputStream

位元組流一次讀寫一個數組的速度,明顯比一次讀寫一個位元組的速度快很多,這是加入了數組這樣的緩沖區效果,java本身在設計的時候,也考慮到了這樣的設計思想(裝飾設計模式後面講解),是以提供了位元組緩沖區流,即BufferedOutputStream

構造方法:​

​BufferedOutputStream(OutputStream out)​

​:建立一個新的緩沖輸出流,以将資料寫入指定的底層輸出流

  • 字元流

    隻能讀寫文本檔案

    由于位元組流操作中文不是特别友善,是以,java就提供了字元流

    介紹字元流之前,首先介紹編碼和解碼的概念:

  • 編碼

    - 把一個字元串轉換成一個位元組數組

    - ​

    ​public byte[] getBytes()​

    ​:使用平台的預設字元集将此 String編碼為 byte 序列,并将結果存儲到一個新的 byte 數組中

    - ​

    ​public byte[] getBytes(String charsetName)​

    ​:使用指定的字元集将此 String 編碼為 byte 序列,并将結果存儲到一個新的 byte 數組中
  • 解碼

    - 把位元組數組轉換成字元串

    - ​

    ​public String(byte[] bytes)​

    ​:通過使用平台的預設字元集解碼指定的 byte 數組,構造一個新的 String

    - ​

    ​public String(byte[] bytes, String charsetName)​

    ​:通過使用指定的 charset 解碼指定的 byte 數組,構造一個新的 String

抽象基類如下:

  • Writer

    常用具體子類:1.OutputStreamWriter——FileWriter(便攜類)

    構造方法:​

    ​OutputStreamWriter(OutputStream out)​

    ​:根據預設編碼(GBK)把位元組流的資料轉換為字元流

    ​OutputStreamWriter(OutputStream out,String charsetName)​

    ​:根據指定編碼把位元組流資料轉換為字元流

    常用的成員方法

  • 寫入功能
  • ​public void write(int c)​

    ​:寫一個字元
  • ​public void write(char[] cbuf)​

    ​:寫一個字元數組
  • ​public void write(char[] cbuf,int off,int len)​

    ​:寫一個字元數組的一部分
  • ​public void write(String str)​

    ​:寫一個字元串
  • ​public void write(String str,int off,int len)​

    ​:寫一個字元串的一部分

2.BufferedWriter

高效的字元輸出流

構造方法:​

​public BufferedWriter(Writer w)​

​:建立一個使用預設大小輸出緩沖區的緩沖字元輸出流

特殊方法:​

​public void newLine()​

​:根據系統來決定換行符,具有系統相容性的換行符l

  • Reader

    常用具體子類:1.InputStreamReader——FileReader(便攜類)

    構造方法:​

    ​InputStreamReader(InputStream is)​

    ​:用預設的編碼(GBK)讀取資料

    ​InputStreamReader(InputStream is,String charsetName)​

    ​:用指定的編碼讀取資料

    常用的成員方法

  • 讀取功能
  • ​public int read()​

    ​:一次讀取一個字元
  • ​public int read(char[] cbuf)​

    ​:一次讀取一個字元數組,如果沒有讀到,則傳回-1

2.BufferedReader

高效的字元輸入流

構造方法:​

​public BufferedReader(Reader e)​

​:建立一個使用預設大小輸入緩沖區的緩沖字元輸入流

特殊方法:​

​public String readLine()​

​:一次讀取一行資料 ,是以換行符為标記的,讀到換行符就換行,沒讀到資料傳回null

IO流的異常處理

  • 位元組流

    以FileOutputStream為例,代碼如下

public class MyTest {
    public static void main(String[] args) {
        //流的異常處理
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("d.txt");
            out.write(100);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}      
  • 字元流
public class MyTest {
    public static void main(String[] args) {
        //處理流的異常
        //一次多寫一些
        InputStreamReader in = null;
        OutputStreamWriter out = null;
        try {
            in = new InputStreamReader(new FileInputStream("MyTest.java"));
            out = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\MyTest.java"));
            //定義一個字元緩沖區
            char[] chars = new char[2000];
            int len = 0;//記錄每次讀取到的有效字元個數
            while ((len = in.read(chars)) != -1) {
                out.write(chars, 0, len);
                out.flush();
            }
        } catch (IOException e) {
            //處理邏輯,預設列印異常的詳細堆棧資訊
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
      

IO流的經典算法

  • ArrayList集合中的字元串資料存儲到文本檔案中,以及将文本檔案中的資料反向讀入到ArrayList集合中

    代碼如下

//1.ArrayList集合中的字元串數組存儲到文本檔案
public class MyTest {
    public static void main(String[] args) throws IOException {
        //需求:把ArrayList集合中的字元串資料存儲到文本檔案
        ArrayList<String> list = new ArrayList<>();
        list.add("馮小剛");
        list.add("張藝謀");
        list.add("甯浩");
        list.add("徐峥");
        list.add("小四");
        //把集合中的資料儲存到檔案檔案中
        //思路,周遊集合,取出資料寫入文本檔案
        BufferedWriter writer = new BufferedWriter(new FileWriter("username.txt"));
        for (String s : list) {
            writer.write(s);
            writer.newLine();
            writer.flush();
        }
        writer.close();
    }
}      
//2.文本檔案中的資料反向讀入到ArrayList集合
public class MyTest2 {
    public static void main(String[] args) throws IOException {
        //需求是,把文本檔案中的資料讀取到集合中
        ArrayList<String> list = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new FileReader("username.txt"));
        while (true){
            String s = reader.readLine();
            if(s!=null){
                list.add(s);
            }else{
                break;
            }

        }

        System.out.println(list);
    }
}      
  • 多級檔案夾複制

    代碼如下

public class HomeTest {
    public static void main(String[] args) throws IOException {
        //需求:複制多級檔案夾
        //1.封裝源檔案夾
        File srcFolder = new File("C:\\test2");
        //2.封裝目标檔案夾
        File targetFolder = new File("D:\\test2");
        if (!targetFolder.exists()) {
            targetFolder.mkdirs();
        }
        //進行複制
        copyFolder(srcFolder, targetFolder);
        System.out.println("複制完成");

    }

    private static void copyFolder(File srcFolder, File targetFolder) throws IOException {
        //周遊源檔案夾下,所有的檔案,複制到目标檔案夾下去
        File[] files = srcFolder.listFiles();
        for (File f : files) {
            if(f.isFile()){
                copyFiles(f, targetFolder);
            }else{
                //targetFolder = new File(targetFolder.getPath() + "\\" + f.getName());
                //遞歸
                File file = new File(targetFolder,f.getName());
                if (!file.exists()) {
                    file.mkdirs();
                }
                copyFolder(f, file);
            }
        }
    }


    //複制檔案
    private static void copyFiles(File f, File targetFolder) throws IOException {
        //使用位元組流來複制
        FileInputStream in = new FileInputStream(f);//封裝源檔案
        //封裝目标檔案
        //File file = new File(targetFolder, f.getName());
        //System.out.println(file);
        FileOutputStream out = new FileOutputStream(new File(targetFolder, f.getName()));
        int len = 0;
        byte[] bytes = new byte[1024 * 8];
        while ((len = in.read(bytes)) != -1) {
            out.write(bytes, 0, len);
            out.flush();
        }
        //是否資源
        in.close();
        out.close();
    }
}      
  • 錄入學生資訊到檔案中

    代碼如下

//學生類
public class Student implements Comparable<Student>{
    private String name;
    private int score;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.score = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return score;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", grade=" + score +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return score == student.score &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, score);
    }

    @Override
    public int compareTo(Student o) {
        int num=this.score-o.score;
        int num2=num==0?this.name.compareTo(o.name):num;
        return num2;
    }
}      
//測試類
public class HomeTest {
    public static void main(String[] args) throws IOException {
        //需求: 鍵盤錄入學生資訊按照總分排序并寫入文本檔案
        Scanner scanner = new Scanner(System.in);
        Student student;
        TreeSet<Student> treeSet = new TreeSet<>();
        BufferedWriter buf = new BufferedWriter(new FileWriter("Student.txt"));
        for (int i = 1; i < 4; i++) {
            scanner = new Scanner(System.in);
            student = new Student();
            System.out.println("請輸入第" + i + "位學生的姓名");
            String name = scanner.nextLine();
            student.setName(name);
            System.out.println("請輸入第" + i + "位學生的成績");
            int score = scanner.nextInt();
            student.setAge(score);
            treeSet.add(student);
        }
        buf.write(treeSet.toString());
        buf.close();
    }
}