JavaSE:IO流

伸不直的十指發表於2020-10-05

File類

File類的一個物件,代表一個檔案或一個檔案目錄(俗稱:資料夾)

File類宣告在java.io包下


File類的例項化

File類的三個常用構造器,如下所示。
FIle類的例項化

注意

  • 相對路徑:相較於某個路徑下,指明的路徑。
    • 在main函式下,相對路徑是當前工程目錄
    • 在Test測試方法中,相對路徑是當前module
  • 絕對路徑:包含碟符在內的檔案或檔案目錄的路徑

File類的常用方法


//File類常用API測試
@Test
public void test2(){
    File file = new File("hello.txt");//相對路徑,建立在當前Module下
    String absolutePath = file.getAbsolutePath();//獲取絕對路徑
    //G:\java\work_space\day0930_reviewJavaSenior\genericity\hello.txt
    System.out.println(absolutePath);


    String path = file.getPath();//獲取路徑,在建立物件時傳入的路徑
    System.out.println(path);//hello.txt

    File file2 = new File("D:\\fileTest\\hello.txt");
    String name = file2.getName();//獲取名稱
    System.out.println(name);//hello.txt

    String parent = file2.getParent();//獲取上層檔案目錄
    System.out.println(parent);//D:\fileTest\java

    long length = file2.length();//獲取檔案長度(位元組數),不是獲取目錄長度。
    System.out.println(length);//0

    File file3 = new File("D:\\io");
    //獲取指定目錄下的所有檔案或者檔案目錄的名稱陣列
    String[] list = file3.list();
    for( String str:list){
        System.out.println(str);
    }

    //獲取指定目錄下的所有檔案或者檔案目錄的File陣列
    File[] files = file3.listFiles();
    for (File file1:files){
        System.out.println(file1.getName());
    }
    //把檔案重新命名為指定的檔案路徑
    //要想保證重新命名成功,呼叫此方法的File物件路徑下檔案或目錄在硬碟中必須存在,
    //而重新命名路徑下的檔案或資料夾在硬碟中不存在。
    
    boolean rename = file3.renameTo(new File("D:\\fileTest\\hello.txt"));
    System.out.println(rename);

}
@Test
public void test3(){
    File file = new File("D:\\fileTest\\hello");

    boolean directory = file.isDirectory();//判斷是否是檔案目錄
    System.out.println(directory);

    boolean file1 = file.isFile();//判斷是否是檔案
    System.out.println(file1);

    boolean exists = file.exists();//判斷在硬碟中是否存在
    System.out.println(exists);

    boolean b = file.canRead();//判斷是否可讀
    System.out.println(b);

    boolean b1 = file.canWrite();//判斷是否可寫
    System.out.println(b1);

    boolean hidden = file.isHidden();//判斷是否是隱藏檔案
    System.out.println(hidden);


}


File類的在磁碟中的建立與刪除


@Test
public void test4() throws IOException {
    //File類的建立功能
    File file = new File("D:\\io\\ioTest.txt");
    if (!file.exists()){
        //檔案建立
        file.createNewFile();
        System.out.println("建立成功!");
    }else{//檔案存在,刪除檔案
        file.delete();
        System.out.println("刪除成功!");
    }
}
@Test
public void test5(){
    //檔案目錄的建立
    //建立檔案目錄。如果此檔案目錄存在,就不建立了。如果此檔案目錄的上層目錄不存在,也不建立。
    File file1 = new File("D:\\io\\io1\\io2");
    boolean mkdir = file1.mkdir();
    if (mkdir){
        System.out.println("mkdir建立成功!");
    }

    File file2 = new File("D:\\io\\io2\\io3");
    //建立檔案目錄。如果上層檔案目錄不存在,一併建立
    boolean mkdirs = file2.mkdirs();
    if (mkdirs){
        System.out.println("mkdirs建立成功!");
    }


}



I/O流的使用


I/O 是Input/Output的縮寫,I/O技術是非常實用的技術,用於處理裝置之間的資料傳輸。如:讀寫檔案,網路通訊等。

Java程式中,對於資料的輸入輸出操作以Stream)的方式進行。

java.io包下提供了各種流相關類和介面,用以獲取不同種類的資料,並通過標準的方法輸入或輸出資料。


輸入input:讀取外部資料(磁碟、光碟等儲存裝置的資料)到程式(記憶體)中

輸出output:將程式(記憶體)資料輸出到磁碟、光碟等儲存裝置中。


流的分類:

  1. 按照操作資料單位不同分為:位元組流(8 bit),字元流(16 bit)
  2. 按資料流的流向不同分為:輸入流、輸出流
  3. 按流的角色不同分為:節點流,處理流


常用流的體系結構:

抽象基類節點流(或檔案流)快取流(處理流的一種)
位元組流輸入InputStreamFileInputStreamBufferedInputStream
位元組流輸出OutputStreamFileOutputStreamBufferedOutputStream
字元流輸入readerFileReaderBufferedReader
字元流輸出WriterFileWriterBufferedWriter

節點流的使用


字元流的使用

FileReader輸入流示例:

@Test
    public void test1() {
        FileReader reader = null;
        try {
            //1.例項化File物件,指明要操作的檔案
            File file = new File("hello.txt");
            //2.提供具體的流
            reader = new FileReader(file);

            //3.資料的讀入過程
            char[] cbuf = new char[5];
            int len;
            //reader.read(cbuf)讀入操作,每次返回讀入cbuf陣列中的字元的個數
            //read返回一個字元。如果達到文字結尾,返回-1
            while ((len = reader.read(cbuf)) != -1){
                //常用讀取資料方法
                for (int i = 0; i < len; i++) {
                    System.out.print(cbuf[i]);
                }

//                //可行方式二
//                String str = new String(cbuf,0,len);
//                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.手動關閉資源
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

執行結果
在這裡插入圖片描述


說明點:

  1. read()的理解:返回讀入的一個字元。如果達到檔案末尾,返回-1
  2. 異常的處理:為了保證流資源一定可以執行關閉操作。需要使用try-catch-finally處理
  3. 讀入檔案一定要存在,否則就會報FileNotFoundException


FileWriter字元輸出流示例

@Test
public void test2() {
    FileWriter writer = null;
    try {
        //1,提供FIle類的物件,指明寫出到的檔案
        File file = new File("hello1.txt");


        //2.提供具體的流
        writer = new FileWriter(file);

        //3.寫入的操作
        writer.write("我試試中文寫不寫的進去。");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.資源的關閉
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

執行結果
在這裡插入圖片描述


從記憶體中寫出資料到硬碟中,說明:

  • 輸出操作:對應File可以可以不存在的
  • 如果不存在:在輸出的過程中,會自動建立此檔案
  • 如果存在:
    • 如果流適用的構造器是:FileWriter(file,false);/FileWriter(file);則會對原有資料進行覆蓋
    • 如果流使用的構造器是:FileWriter(file,true);則會在原有資料的基礎上新增資料,不會覆蓋


使用FileReader 和 FileWriter 實現文字複製操作

public void charCopy(String srcPath,String destPath){
    FileReader fr = null;
    FileWriter fw = null;
    try {
        //1,提供兩個File類的物件,指明寫出的檔案和目標檔案
        File file1 = new File(srcPath);
        File file2 = new File(destPath);

        //2.提供輸入輸出流
        fr = new FileReader(file1);
        fw = new FileWriter(file2);


        //3.複製操作
        char[] cbuf = new char[5];
        int len;
        while ((len  = fr.read(cbuf)) != -1){
            fw.write(cbuf,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.關閉資源
        if (fw != null){//避免空指標異常出現
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fr != null){
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


補充說明:
不能使用字元流來處理圖片等位元組資料

對於文字檔案(.txt、.java、.c、.cpp),使用字元流處理

對於非文字檔案(.jpg、.mp3、.mp4、.avi、.doc、.ppt,……),使用位元組流來處理




位元組流的使用

位元組流的複製操作

//位元組流的複製操作
public void byteCopy(String srcPath,String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        File file1 = new File(srcPath);
        File file2 = new File(destPath);

        fis = new FileInputStream(file1);
        fos = new FileOutputStream(file2);

        byte[] bucf = new byte[8];
        int len;
        while ((len = fis.read(bucf)) != -1){
            fos.write(bucf,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null){
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


緩衝流的使用

作用:

  1. 提高流的讀取、寫入的速度
  2. 提高讀寫速度的原因:內部提供了一個緩衝區


位元組緩衝流的複製操作

public void bufferedCopy(String srcPath,String DestPath){
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        //File類例項化
        File file1 = new File(srcPath);
        File file2 = new File(DestPath);
        //建立位元組流
        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);
        //建立位元組緩衝流
        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        //複製
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1){
            bos.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //流的關閉
        if (bos != null){
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bis != null){
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


字元緩衝流複製操作

public void bufferedCopy2(String srcPath,String DestPath){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //File類例項化
            File file1 = new File(srcPath);
            File file2 = new File(DestPath);
            //建立位元組流
            FileReader fr = new FileReader(file1);
            FileWriter fw = new FileWriter(file2);
            //建立位元組緩衝流
            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);

            //複製
            //方式一:
//            char[] buffer = new char[1024];
//            int len;
//            while ((len = br.read(buffer)) != -1){
//                bw.write(buffer,0,len);
//            }

            //方式二:
            //br.readLine(),直接讀取文字中的一行資料,但不包括換行符,因此,需要手動在寫入時加入"\n"換行符,或者呼叫newLine();換行
            String data;
            while ((data = br.readLine()) != null){
                bw.write(data);
                bw.newLine();
            }
        } catch (IOException 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();
                }
            }
        }
    }

轉換流的使用

public void copy(String srcPath,String destPath){
    InputStreamReader isr = null;
    OutputStreamWriter osw = null;
    try {
        FileInputStream fis = new FileInputStream(new File(srcPath));
        FileOutputStream fos = new FileOutputStream(destPath);//構造器二:直接闖入String型別的檔案路徑,內部自動建立一個File類

        isr = new InputStreamReader(fis,"UTF-8");//在轉換流中可以指定字符集,將文字轉換為其他字元其的文字
        osw = new OutputStreamWriter(fos,"GBK");

        char[] buffer = new char[10];
        int len;
        while ((len = isr.read(buffer)) != -1){
            osw.write(buffer,0,len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (isr != null){
            try {
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (osw != null){
            try {
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

物件流

序列化:用ObjectOutputStream類儲存基本型別資料或物件的機制

反序列化:用ObjectInputStream類讀取基本資料型別或物件的機制

物件序列化機制允許把記憶體中的Java物件轉換成平臺無關的二進位制流,從而允許把這種二級制流持久的儲存在磁碟上,或通過網路將這種二進位制流傳輸到另一個網路節點。//當其他程式獲取了這種二進位制流,就可以恢復成原來的Java物件

序列化過程:將記憶體中的Java物件儲存到磁碟中或通過網路傳輸出去

物件流的使用:

  1. ObjectInputStream 和 ObjectOutputStream
  2. 作用:用於儲存和讀取基本資料型別資料或物件的處理流。她的強大之處就是可以把Java中的物件持久化
  3. 要象一個Java物件是可序列化的,需要滿足相應的要求。
    1. 需要實現介面:Serializable
    2. 當前類提供一個全域性常量:SerialVersionUID
    3. 除了當前類需要實現Serializable介面之外,還必須保證其內部所有屬性也必須是可序列化的。(預設情況下,基本資料型別也是可序列化的。)

補充:ObjectInputStream 和 ObjectOutputStream不能序列化staitctransient修飾的成員變數

示例:

@Test
public void test(){

    ObjectOutputStream oos = null;
    FileInputStream fis = null;
    try {
        FileOutputStream fos = new FileOutputStream("hello.dat");
        fis = new FileInputStream("hello.txt");
        oos = new ObjectOutputStream(fos);

        byte[] buffer =new byte[10];
        int len;
        while ((len = fis.read(buffer)) != -1){
            oos.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (oos != null){
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}