java之IO遍

File類

File類可以用來新建、刪除、重命名文件和目錄,但它不能訪問文件內容本身,訪問文件內容需要使用輸入輸出流

訪問文件名相關的方法

  • String getName():返回File對象所表示的文件名或路徑名
  • String getPath():返回File對象所對應的路徑名
  • String getAbsolutePath():返回次Fille對象所對應的絕對路徑
  • boolean renameTo(File newName):重命名此File對象所對應的文件或目錄,重命名成功返回true

文件檢測相關的方法

  • boolean exists():判斷File對象對應的文件或目錄是否存在
  • boolean canWrite(): 判斷File對象對應的文件或目錄是否可寫
  • boolean canRead():判斷File對象對應的文件或目錄是否可讀
  • boolean isFile():判斷File對象對應的是否爲文件
  • boolean isDirectory():判斷File對象對應的是否爲目錄

文件操作相關方法

  • long length():返回文件內容長度
  • boolean createNewFile():當此File對象所對應的文件不存在時,該方法將新建一個該File對象所指定的新文件,創建成功返回true
  • boolean delete():刪除File對應的文件

目錄操作相關的方法

  • boolean mkdir():創建一個File對象所對應的目錄
  • String[] list():列出File對象的所以子文件名和路徑名
  • File[] listFiles():列出File對象的所有子文件
  • getParentFile():得到文件的父級目錄

文件過濾器

File類的list方法了一返回File對象的所有子文件名,該方法中可以接收一個FilenameFilter參數,通過該參數可以只列出符合條件的文件

public static void main(String[] args) {
		--------以當前路徑來創建一個file對象
        File file = new File(".");
        --------如果文件名以.java結尾或文件對應一個路徑,則返回true
        file.list((dir,name)-> name.endsWith(".java") || new File(name).isDirectory());
        System.out.println(file);
   }

字節流和字符流

在這裏插入圖片描述

InputStream和Reader是所有輸入流的抽象基類,本身不能創建實例來執行輸入,但可以使用FileInputStream和FileReader來讀取文件

public static void main(String[] args) {
        try {
            //準備文件lol.txt其中的內容是AB,對應的ASCII分別是65 66
            File f =new File("d:/lol.txt");
            //創建基於文件的輸入流
            FileInputStream fis =new FileInputStream(f);
            //創建字節數組,其長度就是文件的長度
            byte[] all =new byte[(int) f.length()];
            //以字節流的形式讀取文件所有內容
            fis.read(all);
            for (byte b : all) {
                //打印出來是65 66
                System.out.println(b);
            }
             
            //每次使用完流,都應該進行關閉
            fis.close();
              
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          
    }

OutputStream和Writer是所有輸出流的抽象基類,本身不能創建實例來執行輸出,但可以使用FileOutputStream和FileWriter來讀取文件,如果用來輸出字符串內容使用FileWriter會更好些

處理流的用法

使用處理流的優勢:輸入輸出更簡單;執行效率更高

使用PrintStream來包裝OutputStream

FileOutputStream fileOutputStream = new FileOutputStream("F://tcp.txt");
 PrintStream printStream = new PrintStream(fileOutputStream);

字符流

FileReader:用來讀取訪問文件
FileWriter:用來寫入文件

StringReader:用字符流來讀取字符串,該對象傳入的是字符串節點
StringWriter:用字符流來寫入字符串,該對象實際上是以一個StringBuffer作爲輸出節點,字符串的長度是可變的

StringWriter stringWriter = new StringWriter();

stringWriter.write("你好");

轉換流

InputStreamReader:將字節輸入流轉換成字符輸入流

 InputStreamReader inputStreamReader = new InputStreamReader(System.in);

OutputStringWriter:將字節輸出流轉換成字符輸出流

BufferedReader: 用來將Reader再次包裝變成BufferedReader ,可以利用 bufferedReader.readLine()來讀取一行,BufferedReader 具有緩衝功能,它一次讀取一行文本,以換行符爲標誌,如果沒有讀取到換行符,則程序阻塞,等待讀取到換行符爲止,這也是在控制檯只有按下回車纔會打印出內容的原因

BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
 bufferedReader.readLine();

關閉流的方法

所有的流,無論是輸入流還是輸出流,使用完畢之後,都應該關閉。 如果不關閉,會產生對資源佔用的浪費。 當量比較大的時候,會影響到業務的正常開展。

在try的作用域裏關閉文件流

在try的作用域裏關閉文件輸入流,在前面的示例中都是使用這種方式,這樣做有一個弊端;
如果文件不存在,或者讀取的時候出現問題而拋出異常,那麼就不會執行這一行關閉流的代碼,存在巨大的資源佔用隱患。 不推薦使用

在finally中關閉

這是標準的關閉流的方式
1. 首先把流的引用聲明在try的外面,如果聲明在try裏面,其作用域無法抵達finally.
2. 在finally關閉之前,要先判斷該引用是否爲空
3. 關閉的時候,需要再一次進行try catch處理

這是標準的嚴謹的關閉流的方式,但是看上去很繁瑣,所以寫不重要的或者測試代碼的時候,都會採用上面的有隱患try的方式,因爲不麻煩~

public static void main(String[] args) {
        File f = new File("d:/lol.txt");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(f);
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
                System.out.println(b);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 在finally 裏關閉流
            if (null != fis)
                try {
 
                    fis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
 
    }

字符編碼問題

FileReader得到的是字符,所以一定是已經把字節根據某種編碼識別成了字符了
而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統,就是GBK
FileReader是不能手動設置編碼方式的,爲了使用其他的編碼方式,只能使用InputStreamReader來代替,像這樣:

new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));

public class TestStream {
 -----爲什麼中字前面有一個?
 	 如果是使用記事本另存爲UTF-8的格式,那麼在第一個字節有一個標示符,
 	 叫做BOM用來標誌這個文件是用UTF-8來編碼的
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
        File f = new File("E:\\project\\j2se\\src\\test.txt");
        System.out.println("默認編碼方式:"+Charset.defaultCharset());
        //FileReader得到的是字符,所以一定是已經把字節根據某種編碼識別成了字符了
        //而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統,就是GBK
        try (FileReader fr = new FileReader(f)) {
            char[] cs = new char[(int) f.length()];
            fr.read(cs);
            System.out.printf("FileReader會使用默認的編碼方式%s,識別出來的字符是:%n",Charset.defaultCharset());
            System.out.println(new String(cs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //FileReader是不能手動設置編碼方式的,爲了使用其他的編碼方式,只能使用InputStreamReader來代替
        //並且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 這樣的形式
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
            char[] cs = new char[(int) f.length()];
            isr.read(cs);
            System.out.printf("InputStreamReader 指定編碼方式UTF-8,識別出來的字符是:%n");
            System.out.println(new String(cs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }
}

在這裏插入圖片描述

序列化

序列化機制允許將實現序列化的java對象轉換成字節序列,也可使用反序列化將從二進制流中恢復Java對象;一個對象以流的形式進行傳輸,叫做序列化。 該對象所對應的類,必須是實現Serializable接口;web應用中需要保存到HttpSession或ServletContext屬性的java對象都應該實現序列化

使用對象流實現序列化

ObjectOutputStream,是一個處理流,必須建立在其它節點流之上,使用ObjectOutputStream對象的writeObject可以將一個對象寫入輸出流```

public class ScannerSerizable implements Serializable {
    String name;
    int age;
    public ScannerSerizable(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
}
  public static void main(String[] args) throws IOException {
        
        FileOutputStream fileOutputStream = new FileOutputStream(new File("F://java.txt"));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        ScannerSerizable person = new ScannerSerizable("張三",20);
        objectOutputStream.writeObject(person);

    }

使用 ObjectInputStream進行反序列化

FileInputStream fileInputStream = new FileInputStream("F://java.txt");
 ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream );
 ScannerSerizable person2 =(ScannerSerizable) objectInputStream.readObject();

使用引用的序列化

如果某個類的成員變量的類型不是基本類型而是引用類型,那麼這個引用類型必須也是可序列化的,否則擁有該引用類型的類也不可序列化,如下面代碼,如果student對象的類沒有可序列化,不管ScannerSerizable 有沒有實現Serializable接口,ScannerSerizable 都是不可序列化的

public class ScannerSerizable implements Serializable
 {
    String name;
    int age;
    private ScannerSerizable student;
    }

練習:準備一個長度是10,類型是Hero的數組,使用10個Hero對象初始化該數組
然後把該數組序列化到一個文件heros.lol
接着使用ObjectInputStream 讀取該文件,並轉換爲Hero數組,驗證該數組中的內容,是否和序列化之前一樣

 public static void main(String[] args) throws IOException, ClassNotFoundException
    {

        ScannerSerizable scannerSerizable1 = new ScannerSerizable("張1",20);
        ScannerSerizable scannerSerizable2 = new ScannerSerizable("張2",20);
        ScannerSerizable scannerSerizable3 = new ScannerSerizable("張3",20);
        ScannerSerizable scannerSerizable4 = new ScannerSerizable("張4",20);
        ScannerSerizable scannerSerizable5 = new ScannerSerizable("張5",20);
        ScannerSerizable scannerSerizable6 = new ScannerSerizable("張6",20);
        ScannerSerizable scannerSerizable7 = new ScannerSerizable("張7",20);
        ScannerSerizable scannerSerizable8 = new ScannerSerizable("張8",20);
        ScannerSerizable scannerSerizable9 = new ScannerSerizable("張9",20);
        ScannerSerizable scannerSerizable10 = new ScannerSerizable("張10",20);

        ScannerSerizable[] scannerSerizables = new ScannerSerizable[10];

        scannerSerizables[0] = scannerSerizable1;
        scannerSerizables[1] = scannerSerizable2;
        scannerSerizables[2] = scannerSerizable3;
        scannerSerizables[3] = scannerSerizable4;
        scannerSerizables[4] = scannerSerizable5;
        scannerSerizables[5] = scannerSerizable6;
        scannerSerizables[6] = scannerSerizable7;
        scannerSerizables[7] = scannerSerizable8;
        scannerSerizables[8] = scannerSerizable9;
        scannerSerizables[9] = scannerSerizable10;

        FileOutputStream fileOutputStream = new FileOutputStream("F://heros.lol");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        for(int i =0;i<10;i++)
        {
            objectOutputStream.writeObject(scannerSerizables[i]);
        }

        FileInputStream fileInputStream = new FileInputStream("F://heros.lol");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        for(int i =0;i<10;i++)
        {
            ScannerSerizable scannerSerizable = (ScannerSerizable) objectInputStream.readObject();
            System.out.println("姓名:"+scannerSerizable.getName()+";age:"+scannerSerizable.getAge());
        }

    }

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章