JAVA IO流-小白版

椰椰210162701037發表於2024-08-22

I/O流原理

  1. I/O 是 Input / Output 的縮寫,I / O 流技術是非常實用的技術,用於處理資料傳輸。如讀/寫檔案,網路通訊等;
  2. Java中對於資料的輸入/輸出操作以"流(stream)"的方式進行;
  3. Java.io 包下提供了各種"流"類和介面,用以獲取不同種類的資料,並透過方法輸入或輸出資料;
  4. 輸入input:讀取外部資料(如磁碟資料)到程式(記憶體)中;
  5. 輸出output:將程式(記憶體)資料輸出到磁碟、光碟等儲存裝置中。

流的分類

  1. 按運算元據單位不同分為:位元組流(8 bit)二進位制檔案,字元流(按字元)文字檔案;
  2. 按資料流的流向不同分為:輸入流,輸出流;
  3. 按流的角色的不同分為:位元組流,處理流/包裝流。
    | 抽象基類 | 位元組流 | 字元流 |
    | :------: | :----------: | :----: |
    | 輸入流 | InputStream | Reader |
    | 輸出流 | OutputStream | Writer |
  • java的IO流共涉及40多個類,實際上非常規則,都是從上面四個抽象基類派生的;
  • 以這四個派生出來的子類都以父類名作為子類名的字尾。(如FileInputStream、ObjectOutputStream、BufferedReader、StringWriter等)

InputStream:位元組輸入流

InputSteam抽象類是所有位元組輸入流類的父類(超類、基類)。

InputStream類常用的子類

  1. FileInputStream:檔案輸入流
  2. BufferedInputSream:緩衝位元組輸入流
  3. ObjectInputStream:物件位元組輸入流
    FileInputStream例題1:
    使用FileInputStream讀取hello.test檔案,並將檔案內容顯示到控制檯
package IOStream.InputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author yeye
 * @desc FileInputStream的使用(位元組輸入流  檔案--->程式)
 * @date 2024/8/20 16:57
 */
public class FileInputStream_ {
    public static void main(String[] args) {
        FileInputStream_ fileInputStream = new FileInputStream_();
        fileInputStream.readFile01();
        fileInputStream.readFile02();
    }

    /**
     * 單個位元組的讀取,機率比較低
     * */
    public void readFile01() {
        String filePath = "C:\\app\\hello.txt";
        int readDate = 0;
        FileInputStream fileInputStream = null;
        try {
            // 建立FileInputStream物件,用於讀取檔案
            fileInputStream = new FileInputStream(filePath);
            //從該輸入流讀取一個位元組的資料,如果沒有輸入可以,此方法將阻止。

            //返回讀取的位元組數,如果到達檔案末尾,則返回-1
            while ((readDate = fileInputStream.read())!= -1) { // 讀取檔案內容
                System.out.print((char) readDate);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //關閉檔案流,釋放資源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用read(byte[] b)方法,一次性讀取多個位元組,提高效率
     */
    public void readFile02() {
        String filePath = "C:\\app\\hello.txt";
        int readLen = 0;
        //位元組陣列,用於儲存讀取的檔案內容
        byte[] buffer = new byte[4]; //一次性讀取4個位元組
        FileInputStream fileInputStream = null;
        try {
            // 建立FileInputStream物件,用於讀取檔案
            fileInputStream = new FileInputStream(filePath);
            //從該輸入流最多讀b.length個位元組,將讀取的內容儲存在b陣列中,返回實際讀取的位元組數。

            //如果讀取的位元組數小於b.length,說明到達了檔案末尾
            //如果返回值為-1,則說明讀取完畢
            //如果讀取正常,返回實際讀取的位元組數
            while ((readLen = fileInputStream.read(buffer))!= -1) { // 讀取檔案內容
                System.out.print(new String(buffer, 0, readLen));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //關閉檔案流,釋放資源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

OutputStream類

FileOutputStream例題1:
使用FileOutputStream在test.txt檔案中寫入"hello,world",如果檔案不存在,則會建立檔案

package IOStream.OutputStream;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutPutStream01 {
    public static void main(String[] args) {
        FileOutPutStream01 fil = new FileOutPutStream01();
        fil.writeFile();
    }
    /**
     * 使用FileOutputStream將資料寫入檔案
     * 如果檔案不存在,則建立該檔案
     */
    public void writeFile(){
        // 建立FileOutputStream物件
        String filePath = "E:/test.txt";
        FileOutputStream fileOutPutStream = null;

        try {
            //得到FileOutputStream物件
            //1.new FileOutputStream(filePath)建立方式,會覆蓋原檔案
            //2.new FileOutputStream(filePath,true)建立方式,不會覆蓋原檔案,在檔案末尾追加內容
            fileOutPutStream = new FileOutputStream(filePath);
            //寫入一個位元組
            fileOutPutStream.write('a');
            //寫入一個字串
            String str = "hello world";
            //str.getBytes();可以把字串轉換為位元組陣列
            //fileOutPutStream.write(str.getBytes());
            //write(byte[] b, int off, int len)方法,可以指定寫入的起始位置和長度
            fileOutPutStream.write(str.getBytes(), 0, 5);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileOutPutStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

FileOutputStream例題2
程式設計完成圖片/音樂的複製

package IOStream.OutputStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author yeye
 * @desc
 * @date 2024/8/20 19:10
 */
public class FileCopy {
    public static void main(String[] args) {
        //完成檔案複製,將e:\dog1.jpg檔案複製到c:\dog.jpg
        /**
         * 1.建立檔案的輸入流,將檔案讀取的程式
         * 2.建立檔案的輸出流,將讀取到的檔案資料寫入到指定的檔案
         * 在完成程式時,應該是讀取部分資料,就寫入到值得檔案,這裡使用迴圈
         */
        //讀取檔案的路徑
        String srcfilePath = "e:\\dog1.jpg";
        String destfilePath = "e:\\dog01.jpg";
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        try {
            fileInputStream = new FileInputStream(srcfilePath);
            fileOutputStream = new FileOutputStream(destfilePath);
            //定義一個位元組陣列,提高讀取效率
            byte[] buffer = new byte[1024];
            int ReadLen = 0;
            while ((ReadLen = fileInputStream.read(buffer))!= -1){
                //讀取到資料後,就透過fileOutputStream寫入到指定的檔案
                fileOutputStream.write(buffer,0,ReadLen);
            }
            System.out.println("檔案複製成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                //關閉輸入流和輸出流,釋放資源
                if(fileInputStream!= null){
                    fileInputStream.close();
                }
                if (fileOutputStream!= null){
                    fileOutputStream.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

Reader常用的類、Writer常用的類

FileReader和FileWriter

1.FileReader常用方法

  1. new FileReader(File/String)
  2. read():每次讀取單個字元,返回該字元,如果檔案末尾,返回-1
  3. read(char []):批次讀取多個字元到陣列,返回讀取到的字元數,如果到檔案末尾返回-1
    相關API:
  • new String ( char [] ) : 將char轉換成String
  • new String ( char [] ,off,len) : 將char [ ] 值得的部分轉換成String

3.FileReader應用案例

要求:1.使用FileReader從story.txt讀取內容並顯示

package IOStream.Reader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * @author yeye
 * @desc
 * @date 2024/8/20 22:30
 */
public class FileReader01 {
    public static void main(String[] args) {
        //方法1 --read()方法
        String filePath = "e:\\story.txt";
        FileReader fileReader = null;
        int date =' ';
        //建立FileReader物件
        try {
            fileReader = new FileReader(filePath);
            //讀取檔案內容--迴圈讀取--使用read()方法,單個讀取
            while((date = fileReader.read()) !=-1){
                System.out.print((char)date);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fileReader!= null){
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

//        //方法2 --read(buffer)方法
//        String filePath = "e:\\story.txt";
//        FileReader fileReader = null;
//        int ReadLen = 0;
//        char[]buffer = new char[8];
//        //建立FileReader物件
//        try {
//            fileReader = new FileReader(filePath);
//            //讀取檔案內容--迴圈讀取--使用read(buffer)方法,批次讀取
//            //返回的是實際讀取到的字元數
//            //如果返回-1,表示已經讀取到檔案末尾
//            while((ReadLen = fileReader.read(buffer)) !=-1){
//                System.out.print(new String(buffer,0,ReadLen));
//            }
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }finally {
//            if(fileReader!= null){
//                try {
//                    fileReader.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }

    }
}

2.FileWriter常用方法:

  1. new FileWriter(File/String) : (物件/地址) 覆蓋模式,每寫一次都會覆蓋之前的內容,相當流的指標在首端
  2. new FileWriter(File/String,true) : 追加模式,在原內容尾端輸入內容,相當於指標在尾端
  3. writer(int) : 寫入單個字元
  4. write(char [] ) : 寫入指定陣列
  5. write(char [],off,len) :寫入指定陣列的指定部分
  6. writer(String) : 寫入整個字串
  7. writer(String,off,len) : 寫入字串的指定部分
    相關API:String類 : toCharArray:將String類轉換成char[]
    注:FileWriter在使用後,必須關閉(close)或者重新整理(flush),否則寫入不到指定檔案。

3.FileWriter應用案例

要求:使用FileWriter將"你好,Java!"寫入到note.txt檔案中,

package IOStream.Writer;

import java.io.FileWriter;
import java.io.IOException;

/**
 * @author yeye
 * @desc
 * @date 2024/8/20 23:03
 */
public class FileWriter01 {
    public static void main(String[] args) {
    String filePath = "E:/test.txt";
    //建立一個FileWriter物件,用於寫入檔案
    FileWriter fileWriter = null;
    char [] buffer = {'h', 'e', 'l', 'l', 'o'};
        try {
            fileWriter = new FileWriter(filePath); //預設是覆蓋寫入
            //1. writer(int) : 寫入單個字元
            fileWriter.write('a');
            //2. write(char [] ) : 寫入指定陣列
            fileWriter.write(buffer);
            //3. write(char [],off,len) :寫入指定陣列的指定部分
            fileWriter.write("椰椰在努力學Java".toCharArray(), 1, 9);
            //4. writer(String) : 寫入整個字串
            fileWriter.write("你好,Java!");
            //5. writer(String,off,len) : 寫入字串的指定部分
            fileWriter.write("你好,成都!", 0, 3);
            //在資料量大的情況下,可以使用迴圈操作


        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //對應FileWriter,一定要關閉(close),或者重新整理(flush)才能正真把資料寫入檔案

            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

節點流和處理流

節點流

節點流可以從一個特定的資料來源(如文字、陣列、字串、管道等)讀寫資料,如FileReader、FileWriter、FileInputStream、FileOutputStream等
靈活性低

處理流

處理流也叫包裝流,是"連線"在已存在的流(節點流或處理流)之上,為程式提供更為強大的功能,也更加靈活如BufferedReader、BufferedWriter.

public class BufferedReader extends Rander{
    private Reader in;
    private char cb[];
}
//BufferedReader類中,有屬性Reader,即可以封裝任何一個節點流,只要該節點流是Reader類的子類
public class BufferedWriter extends Writer{
    private Writer out;
    private char cb[];
}
//BufferedWriter類中,有屬性Writer,即可以封裝任何一個節點流,只要該節點流是Reader類的子類

節點流和處理流的區別和聯絡

  1. 節點流是底層流/低階流,直接跟資料來源相連;
  2. 處理流(包裝流)包裝節點流,既可以消除不同節點流的實現差異,也可以提供更為方便的方法來完成輸入輸出。
  3. 處理流(包裝流)對節點流進行包裝,使用了修飾器設計模式,不會直接跟資料來源相連
    處理流的功能主要體現在以下兩個方面:
  4. 效能的提高:主要以增加快取的方式來提高輸入輸出的效率;
  5. 操作的便捷:處理流可提供一系列便捷的方法來輸入輸出大批次的資料,使用起來更加的靈活。
    處理流大概實現如下:
//抽象父類
public abstract class Reader_ {
    public void readFile(){}
    public void readString(){}
}
//節點流————直接讀取原始檔
public class FileReader_  extends Reader_{
    public void readFile(){
        System.out.println("正在讀取檔案...");
    }
}
//節點流————直接讀取字串
public class StringReader_ extends Reader_ {
    public void readString(){
        System.out.println("正在讀取字串");
    }
}
//處理流(包裝流)
public class BufferedReader_ extends Reader_ {
    private Reader_ reader_; //Reader_型別的reader_屬性
    //接受Reader_子類物件
    public BufferedReader_(Reader_ reader_){
        this.reader_ = reader_;
    }
    //讓方法更加靈活,多次讀取檔案,或者加緩衝char[]...
    public void readLines(int num){
        for(int i = 0;i<num;i++){
            reader_.readFile();
        }
    }
    //擴充套件readString,批次讀取字串
    public void readStrings(int num){
        for(int i = 0;i<num;i++){
            reader_.readString();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BufferedReader_ bufferedReader = new BufferedReader_(new FileReader_());
        bufferedReader.readLines(10);
        
        BufferedReader_ bufferedReader1 = new BufferedReader_(new StringReader_());
        bufferedReader1.readStrings(10);
    }
}

處理流—— BufferedReader和BufferedWriter

  1. BufferedReader和BufferedWriter屬於字元流,是按照字元來讀取資料的;
  2. 關閉處理流時,只需關閉外層流即可。
    例1:使用BufferedReader讀取文字檔案,並顯示在控制檯
package IOStream.Reader;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReader02 {
    public static void main(String[] args) throws IOException {

        String filePath ="E:/BufferedReader_.txt";
        // 建立BufferedReader物件
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        // 讀取檔案內容
        String line ;//按行讀取,效率高
        //bufferedReader.readLine()是按行讀取
        //當返回null時,表示已經讀取到檔案末尾
        while((line = bufferedReader.readLine()) !=null){
            System.out.println(line);
        }
        // 關閉流,只需關閉外層流(BufferedReader)即可,因為底層會自動關閉節點流(FileReader)
        bufferedReader.close();
    }
}

例2:使用BufferedWriter 將"hello,JAVA"寫入到檔案中

package IOStream.Writer;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriter02 {
    public static void main(String[] args) throws IOException {

        String filePath = "E:\\test.txt";
        //建立BufferedWriter物件
        /**
         * new FileWriter(filePath)表示以覆蓋的方式寫入
         * new FileWriter(filePath,true)表示以追加的方式寫入
         */
        BufferedWriter bufferedWriter02 = new BufferedWriter(new FileWriter(filePath,true));
        //寫入資料
        bufferedWriter02.write("Hello JAVA!");
        //插入一個和系統相關的換行
        bufferedWriter02.newLine();
        bufferedWriter02.write("Hello 椰椰!");

        //關閉外層流(BufferedWriter)即可,傳入的new FileWriter(filePath)會在底層關閉
        bufferedWriter02.close();
    }
}

例3:綜合使用BufferedReader和BufferedWriter完成文字檔案複製

package IOStream.Writer;

import java.io.*;

public class BufferedReader_BufferedWriter_01 {
    public static void main(String[] args) throws IOException {
        /**
         * BufferedReader和BufferedWriter是按照字元操作
         * 不要操作二進位制檔案,可能會造成檔案損壞
         */
        String srcFilePath = "E:\\test.txt";
        String destFilePath = "E:\\test_copy.txt";
        //建立BufferedReader物件
        BufferedReader bufferedReader = new BufferedReader(new FileReader(srcFilePath));
        //建立BufferedWriter物件
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
        //讀取檔案內容並寫入到目標檔案中
        String line;
        //readLine()方法讀取一行內容,沒有換行
        while ((line = bufferedReader.readLine())!= null){
            bufferedWriter.write(line);
            //插入一個換行
            bufferedWriter.newLine();
        }
       if(bufferedReader!=null){
           bufferedWriter.close();
       }
       if(bufferedWriter!=null){
           bufferedWriter.close();
       }
        System.out.println("檔案複製成功!");
    }
}

處理流——BufferedInputStream和BufferedOutputStream

BufferedInputStream是位元組流,在建立BufferedInputStream時,會建立一個內部緩衝陣列
BufferedOutputStream是位元組流,實現緩衝的輸出流,可以將多個位元組寫入底層的輸出流中,而不必對每次位元組寫入呼叫底層系統
例1:程式設計完成圖片/音樂/文字檔案的複製,(此處以圖片為例,音樂/文字檔案只需改變相應地址即可)

package IOStream.OutputStream;

import java.io.*;

public class BufferedInputStream_BufferedOutputStream_001 {
    public static void main(String[] args) throws IOException {

        String scrFilePath = "E:/dog01.jpg";
        String destFilePath = "E:/dog01_copy.jpg";
        //建立BufferedInputStream物件和BufferedOutputStream物件
        //FileInputStream是InputStream的子類,BufferedInputStream是FilterInputStream的子類
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(scrFilePath));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));
        //迴圈讀取檔案,並寫入到destFilePath中
        byte [] buffer = new byte[1024];
        int len = 0;
        //當返回值是-1時,表示檔案已經讀取完畢
        while((len = bufferedInputStream.read(buffer)) != -1){
            bufferedOutputStream.write(buffer,0,len);
        }

        System.out.println("檔案複製成功!");
        //關閉流外層處理流,底層會關閉節點流
        if(bufferedInputStream !=null){
            bufferedInputStream.close();
        }
        if(bufferedOutputStream != null){
            bufferedOutputStream.close();
        }
    }
}

處理流——(物件流)———ObjectInputStream和ObjectOutputStream

看一個需求:

  1. 將int num = 100 這個 int 資料儲存到檔案中,注意不是 100 數字,而是 int 100,並且,能夠從檔案中直接恢復 int 100
  2. 將 Dog dog = new Dog(“小黃”, 3) 這個 dog物件 儲存到 檔案中,並且能夠從檔案恢復.上面的要求,就是 能夠將 基本資料型別 或者 物件 進行 序列化 和 反序列化操作
功能:提供了對基本型別或物件型別的序列化和反序列化
  • ObjectOutputStream提供了 序列化功能
  • ObjectInputStream 提供了反序列化功能
注意事項:
  • 讀寫順序要一致;
  • 實現序列化或反序列化,要實現Serializable;
  • 序列化的類建議新增SerialVersionUID,為了提高版本的相容性;
  • 序列化物件時,預設將裡面所有的屬性都進行序列化,除了static、transient修飾的成員;
  • 序列化物件時,要求裡面屬性的型別也需要實現序列化介面;
  • 序列化具備可繼承性,也就是某類已經實現了序列化,則它所有的子類也以及預設實現了序列化。

序列化和反序列化

  1. 序列化就是在儲存資料時,儲存資料的值和資料型別
  2. 反序列化就是在恢復資料時,恢復資料的值和資料型別
  3. 需要讓某個物件支援序列化機制,就必須讓其類是可序列化的,為了讓某個類是可序列化的,該類必須實現以下兩個介面之一:
    • Serializable //一個標記介面,沒有方法,一般實現這個介面
    • Externalizable //該方法有方法需要實現
      例1:使用ObjectOutputStream 序列化基本資料型別和一個Dog物件(name,age),並儲存到一個檔案中。
package IOStream.OutputStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author yeye
 * @desc 使用ObjectOutputStream 完成資料的序列化
 * @date 2024/8/22 13:59
 */
public class ObjectOutputStream01 {
    public static void main(String[] args) throws IOException {
        //序列化後儲存到檔案格式,不是文字格式,而是按照它的格式儲存
        String filePath = "E:/data.dat";
        //建立ObjectOutputStream物件
        ObjectOutputStream obj= new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化資料到E/data.dat
        obj.writeInt(10); //int - >Integer (實現了Serializable介面)
        obj.writeBoolean(true); //boolean -> Boolean(實現了Serializable介面)
        obj.writeChar('a'); //char -> Character(實現了Serializable介面)
        obj.writeDouble(3.1415926); //double -> Double(實現了Serializable介面)
        obj.writeUTF("Hello 椰椰"); //String(實現了Serializable介面)
        //儲存一個dog物件
        obj.writeObject(new Dog("小寶",3));
        //關閉流
        obj.close();
        System.out.println("序列化完成");
    }
}
//如果要序列化某個類的物件,該類必須實現Serializable介面
class Dog implements Serializable {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

例2:使用ObjectInputStream讀取data.dat並反序列化恢復資料。

package IOStream.InputStream;

import polymorphism.Dog;

import java.io.*;

/**
 * @author yeye
 * @desc 使用ObjectInputStream讀取data.dat並反序列化恢復資料。
 * @date 2024/8/22 14:39
 */
public class ObjectInputStream01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //指定反序列化檔案
        String filePath = "E:/data.dat";
        //建立ObjectInputStream物件
        ObjectInputStream obj = new ObjectInputStream(new FileInputStream(filePath));

        //讀取(反序列化)的順序需要和寫入(序列化)順序保持一致,否則會出現異常
        System.out.println(obj.readInt());
        System.out.println(obj.readBoolean());
        System.out.println(obj.readChar());
        System.out.println(obj.readDouble());
        System.out.println(obj.readUTF());
        //dog編譯型別是Dog,dog執行型別是Dog
        Object dog = obj.readObject();
        System.out.println("執行型別:" + dog.getClass());
        System.out.println("dog資訊:" + dog); //底層Object - >Dog

        //如果我們希望呼叫dog的方法,就需要向下轉型
        //需要我們將Dog類的定義,複製到可以引用的位置
    }
}

標準輸入輸出流

編譯型別 執行型別 預設裝置
System.in InputStream BufferedInputStream 鍵盤
System.out PrintStream PrintStream 顯示器
程式碼展示:
package IOStream.Standard;
import java.util.Scanner;

/**
 * @author yeye
 * @desc
 * @date 2024/8/22 15:49
 */
public class InputAndOutput {
    public static void main(String[] args) {
        //System 類的public final static InputStream in = null;
        //編譯型別:InputStream
        //執行型別:BufferedInputStream
        //表示標準輸入,鍵盤
        System.out.println(System.in.getClass());

        //System 類的public final static PrintStream out屬性;
        //編譯型別:PrintStream
        //執行型別:PrintStream
        //表示標準輸出,顯示器
        System.out.println(System.out.getClass());

        Scanner scanner = new Scanner(System.in);
        System.out.println("請輸入內容:");
        String next = scanner.next();
        System.out.println("你輸入的內容是:" + next);

    }
}
//執行結果:
class java.io.BufferedInputStream
class java.io.PrintStream
請輸入內容:
nihao
你輸入的內容是:nihao

轉換流——InputStreamReader和OutputStreamWrider

transformation - 轉型

  1. InputStreamReader:是Reader類的子類,可以將InputStream(位元組流)包裝/轉換成Reader(包裝流);
  2. OutputStreamWriter:是Writer類的子類,實現將OutputStream(位元組流)包裝/轉換成Writer(包裝流);
  3. 當處理純文字資料時,如果使用字元流效率更高,並且可以有效解決中文問題,建議將位元組流轉換成字元流
  4. 可以在使用時指定編碼格式(比如 utf-8、gbk、gb2312等)
    例1:將位元組流 FileInputStream 包裝/轉換成 InputStreamReader,對檔案進行讀取(按照utf-8/gbk),進而再包裝成BufferedReader
package transformation;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author yeye
 * @desc 使用InputStreamReader 轉換流解決中文亂碼問題
 *  將位元組流FileInputStream轉換為字元流InputStreamReader,並指定編碼格式為UTF-8/GDK,即可解決中文亂碼問題。
 * @date 2024/8/22 16:43
 */
public class InputStreamReader01 {
    public static void main(String[] args) throws IOException {

        String filePath = "E:/aaa.txt";
        //第一步:把new InputStreamReader 轉成 InputStreamReader流,並指定編碼格式為GBK
        InputStreamReader in1 = new InputStreamReader(new FileInputStream(filePath), "gbk");
        //第二步:把InputStreamReader 轉成 BufferedReader流
        BufferedReader br = new BufferedReader(in1);

//        //將第一步和第二布流合併,一步到位
//        BufferedReader br = new BufferedReader(new InputStreamReader(
//                                                   new FileInputStream(filePath), "gbk"));

        //讀取
        System.out.println("讀取到的內容:"+br.readLine());
        //關閉流
        br.close();
    }
}

例2:程式設計將 位元組流 FileOutputstream 包裝成(轉換成)字元流OutputStreamWriter對檔案進行寫入(按照gbk格式,可以指定其他,比如utf-8)

package transformation;

import java.io.*;

/**
 * @author yeye
 * @desc 使用OutputStreamReader寫入檔案
 *  把位元組流 FileOutputStream 轉換成字元流 OutputStreamWriter
 *  指定處理的編碼格式,如UTF-8、GBK等
 * @date 2024/8/22 17:09
 */
public class OutputStreamWriter01 {
    public static void main(String[] args) throws IOException {

        String filePath = "E:/aaa.txt";
        String encoding = "UTF-8";

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), encoding);
        osw.write("你好,椰椰!");

        osw.close();
        System.out.println("寫入檔案成功!");
    }
}

列印流——PrintStream和PrintWriter

PrintStream位元組流,PrinteWriter字元流
列印流只有輸出流,沒有輸入流。
例1:printStream 位元組流列印

package printstream;

import java.io.IOException;
import java.io.PrintStream;

import static java.lang.System.out;

/**
 * @author yeye
 * @desc PrintStream (位元組列印/輸出流)
 * @date 2024/8/22 17:30
 */
public class PrintStream01 {
    public static void main(String[] args) throws IOException {

        PrintStream ps = System.out;
        //在預設的情況下,PrintStream 資料輸出的位置是 預設輸出,即顯示器
        ps.println("今天不想吃晚飯!");
        //因為print底層呼叫的是write方法,所以可以直接使用write方法列印/輸出
        ps.write("。。。,".getBytes());
        ps.close();

        //也可以透過System.setOut()方法修改預設的輸出位置
        System.setOut(new PrintStream("E://test.txt"));
        out.println("今天吃了晚飯!");

    }
}

例2:PrinteWriter 字元流列印

package IOStream.printstream_;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author yeye
 * @desc PrinterWriter 的使用
 * @date 2024/8/22 18:00
 */
public class PrintWriter01 {
    public static void main(String[] args) throws IOException {

        //標準輸出,顯示器
        PrintWriter pw1 = new PrintWriter(System.out);
        pw1.println("Hello World");
        pw1.close();
        //指定列印檔案
        PrintWriter pw2 = new PrintWriter(new FileWriter("E:/test.txt"));
        pw2.println("Hello 明天");
        pw2.close();
    }
}

Properties類

unicode碼查詢:http://tool.chinaz.com/tools/unicode.aspx

  1. 專門用於讀寫配置檔案的集合類
    配置檔案的格式:
    • 鍵=值
    • 鍵=值
  2. 鍵值對不需要有空格,值不需要用 " " ,預設型別是String
  3. Properties父類是HashTable,底層就是Hashtable核心方法
  4. Properties 類常見的方法
    • load:載入配置檔案的鍵值對到Properties物件;
    • list:將得到的鍵值對顯示到指定裝置/流物件;
    • getProperty(key):根據鍵獲取對應的值;
    • setProperty(key,value):修改鍵對應的值,沒有key,則新增;
    • store:將Properties中的鍵值對儲存到配置檔案中,在idea中,儲存資訊到配置檔案,如果含有中文,會儲存為unicode碼
如下一個配置檔案 mysql.properties
ip = 1234
user = root
password = root
請問程式設計讀取 ip 、user 和 pwd 的值是多少
例1:傳統的方法
例2:使用Properties類可以方便實現

例1:傳統方法:
配置檔案:src/IOStream/mysql.properties

package IOStream.properties;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * @author yeye
 * @desc
 * @date 2024/8/22 18:25
 */
public class Properties01 {
    public static void main(String[] args) throws IOException {
        //讀取mysql.properties檔案,並得到ip,username,password
        BufferedReader br = new BufferedReader(new FileReader("src/IOStream/mysql.properties"));
        String line = null;
        //迴圈讀取
        while((line = br.readLine()) != null){
            //使用line變數呼叫split方法,以等號(=)作為分隔符來分割字串。
            //split方法將字串分割成一個字串陣列split,其中包含兩個元素:等號前的文字和等號後的文字。
            String[] split = line.split("=");
            System.out.println(split[0] + " 的值是" + split[1]);
            //System.out.println(line);
        }
        br.close();

    }
}

例2:使用Properties類完成對mysql.properties的讀取

package IOStream.properties;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

/**
 * @author yeye
 * @desc
 * @date 2024/8/22 19:08
 */
public class Properties02 {
    public static void main(String[] args) throws IOException {
        //使用Properties類完成對mysql.properties的讀取

        //第一步,建立Properties物件
        Properties properties = new Properties();
        //第二步,讀取mysql.properties檔案
        properties.load(new FileReader("src/IOStream/mysql.properties"));
        //第三步,把鍵值對顯示到控制檯
        properties.list(System.out);
        //第四步,根據鍵獲取對應的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        System.out.println("使用者名稱:"+user);
        System.out.println("密碼:"+password);
  
    }
}
//執行結果
password=1234
encoding=UTF-8
user=root
使用者名稱:root
密碼:1234

例3:建立新的配置檔案,並儲存新的鍵值對

package IOStream.properties;

import java.io.*;
import java.util.Properties;

/**
 * @author yeye
 * @desc
 * @date 2024/8/22 19:48
 */
public class Properties03 {
    public static void main(String[] args) throws IOException {
        //使用Properties類建立配置檔案,並修改配置檔案內容
        Properties properties = new Properties();

        //建立鍵值對
        properties.setProperty("user","椰椰");//儲存時,是中文的unicode編碼
        properties.setProperty("password","1234");
        properties.setProperty("encoding","UTF-8");
        //將鍵值對儲存到配置檔案中
        properties.store(new FileOutputStream("src/IOStream/mysql02.properties"), "配置檔案");
        properties.list(System.out);
        System.out.println("儲存配置檔案成功");
    }
}
//執行結果
password=1234
encoding=UTF-8
user=椰椰
儲存配置檔案成功
//mysql02.properties檔案中儲存的內容
#\u914D\u7F6E\u6587\u4EF6
#Thu Aug 22 20:02:06 CST 2024
password=1234
encoding=UTF-8
user=\u6930\u6930

這是我在學習韓順平老師Java課程所寫,韓老師講的非常好,非常詳細,感興趣的同學可以去學習。