Java筆記-IO流

天會晴發表於2020-09-29

IO流:

檔案的輸入和輸出,通過IO完成檔案的讀寫。(以記憶體作為參照來看)
輸入流(InputStream)、讀(read):檔案輸入到記憶體當中。
輸出流(OutputStream)、寫(write):記憶體輸出的檔案中。

可按照多種方式分類:
1.按照流的方向進行分類,以記憶體作為參照物。輸入流、輸出流。

2.按照讀取的資料方式不同進行分類,一次讀取一個位元組byte(位元組流),等同於一次讀取8個二進位制位,這種流是萬能的,什麼都可以讀取。
一次讀取一個字元(字元流),這種流為了讀取普通文字檔案而存在,只能讀取純文字。

注意:所有的流都在java.io.*下。

java IO的四大家族:
java.io.InputStream 位元組輸入流
java.io.OutputStream 位元組輸出流
java.io.Reader 字元輸入流
java.io.Writer 字元輸出流

注意:在java中只要類名以”stream"結尾的都是位元組流,以“Reader/Writer“結尾的都是字元流。
所有的流都實現了Closeable介面,都是可關閉的,都有close()方法。流是記憶體和硬碟的介面,用完之後一定要關閉,不然會耗費很多資源。
所有的輸出流都實現了Flushable,都有flush()方法,都是可重新整理的。用完輸出流後,用flush()方法重新整理一下,這個重新整理表示將通道中剩餘未輸出的資料強行輸出完,重新整理的作用就是清空管道。
注意:如果在輸出之後沒有用flush,可能會導致丟失資料。
注意:IDEA的當前路徑:工程project的根。
節點流:當一個流的構造方法需要一個流的時候,這個被傳進來的流被稱為節點流。
包裝流、處理流:外部負責包裝的流。
對於包裝流來說,關閉流時只需要關閉最外層流就行,裡面的節點流會自動關閉。
例如:

 FileReader fis = new FileReader("hello");
 BufferedReader br = new BufferedReader(fis);

節點流:fis,包裝流:br,關閉流時:br.close();

需掌握的流:

檔案:

java.io.FileInputStream
1.檔案位元組輸入流,萬能的,任何型別的檔案都可以採用這個流來讀。
2.位元組的方式,完成讀的操作,完成輸入的操作(從硬碟到記憶體)
注意:需要try-catch或者throw異常,在finally中關閉資源,關閉流也需要try-catch
方法:
int read() //方法的返回值是讀到的位元組,讀取不到就返回-1.
例子:

public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("hello");
        int count = 0;
            while((count = fis.read())!=-1){
                System.out.println(count);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

int read(byte[] b) //一次最多讀取b.length()個位元組,讀取的到位元組存到b陣列中,返回讀到的位元組的數量。若b陣列已滿,則會覆蓋陣列前面的元素。當沒有讀到就返回-1.

public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("hello");
        int count = 0;
        byte[] b = new byte[5];
            while((count = fis.read(b))!=-1){
                System.out.print(new String(b,0,count));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

int available() //返回流當中剩餘的沒有被讀到的位元組數量
例如:

 byte[] b = new byte[fis.available()];
            int count = fis.read(b);
            System.out.println(new String(b));

注意:這種方式不適合大檔案,因為byte陣列不能太大。
long skip(long n) //跳過幾個位元組不讀

java.io.FileOutputStream
檔案位元組輸出流,從記憶體到硬碟。
原檔案是否會被清空,取決於在構造方法的第二個引數,若為true則檔案追加寫入,若為false則檔案清空再寫入。
方法:
void write(byte[] b) //把陣列b寫到對於的硬碟檔案中去。

 public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            byte[] b = {58,62,33,54,52};
            fos = new FileOutputStream("myhello");
            fos.write(b);
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos == null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

void write(byte[] b, int off, int len) //將byte陣列的一部分寫出

java.io.FileReader
檔案字元輸入流,只能讀取普通文字,讀取文字內容時,比較方便,快捷。
read(char[] c)//將檔案內容讀入字元陣列。
java.io.FileWriter
檔案字元輸出流,只能輸出普通文字。
在構造方法的第二個引數,傳入true會直接在檔案後面繼續寫入內容,傳入false會清空檔案再重寫。
void write(char[] cbuf) //將一個陣列寫入檔案中
abstract void write(char[] cbuf, int off, int len) //將陣列的一部分寫入檔案中。
void write(String str) //可以直接寫入一串字串。

轉換流(將位元組流轉換為字元流)
java.io.InputStreamReader
java.io.OutputStreamWriter

都是在構造方法中傳入一個位元組流,然後轉換為一個字元流。

緩衝流:
java.io.BufferedReader
String readLine() //讀入檔案的一行,並返回這個字串。

 public static void main(String[] args) throws IOException {
        FileReader fis = new FileReader("hello");
        BufferedReader br = new BufferedReader(fis);
        String s;
        while((s=br.readLine())!=null){
            System.out.println(s);
        }
    }

java.io.BufferedWriter
例子:

public static void main(String[] args) throws IOException {
        BufferedWriter bf = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("myfile")));
        bf.write("hello,i am coming");
        bf.write("\n can you hear me");
        bf.flush();
        bf.close();
    }

java.io.BufferedInputStream
java.io.BufferedOutputStream

資料流:
java.io.DataInputStream
java.io.DataOutputStream

這個流可以將資料連同資料型別一併寫入檔案中,不是普通文字文件,用記事本打不開。
方法:
有writeBoolean(boolean v) 、writeByte(int v) 、writeBytes(String s) 、writeChar(int v)、writeChars(String s) 、writeDouble(double v)、
writeFloat(float v) 、writeInt(int v) 、writeLong(long v) 、writeShort(int v) 等,可以將資料及其型別一併寫入檔案中。
如果要用DataInputStream去讀DataOutputStream的東西,必須要提前知道儲存的規則,否則會亂碼。

物件流:
transient:遊離的,被transient修飾的屬性不參與序列化
java.io.ObjectInputStream
常用方法:
Object readObject() //將檔案內容反序列化,返回object。

java.io.ObjectOutputStream
常用方法:
void writeObject(Object obj) //將obj物件序列化寫入檔案中。
注意:傳入的obj物件需要實現Serializable介面。

標準輸出流:
java.io.PrintWriter
java.io.PrintStream

標準的位元組輸出流,預設輸出到控制檯。
不需要手動關閉。
注意:System.setOut(PrintStream ps);給該方法傳入一個標準輸出流ps,可以將原本print、println列印在控制檯中的資訊轉成寫入ps檔案中。
例如編寫日誌檔案:

public  static  void login(String msg){
        PrintStream ps = null;
        try {
            //指向一個日誌檔案
            ps = new PrintStream(new FileOutputStream("log.txt",true));
            //改變輸出方向
            System.setOut(ps);
			//日期
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String time = sdf.format(date);
            System.out.println(time+":"+msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

呼叫System.out.println時,由於之前System.setOut(ps)修改了內容輸出的方向,內容不再輸出到控制檯了,而是輸出到ps指定的檔案中。

序列化(Serialize):

Java序列化就是指把Java物件轉換為位元組序列的過程

反序列化(DeSerialize):

Java反序列化就是指把位元組序列恢復為Java物件的過程。
注意:參與序列化和反序列化的物件需要實現Serialize介面
序列化版本號:每個實現了Serialize介面的類都自動生成了一個序列化版本號,用來區別不同的類。
缺陷:修改類中的程式碼之後,序列化版本號會發生變化。一旦程式碼確定後,不能再進行修改。
建議給實現Serializable介面的類提供一個固定不變的序列化版本號。
idea工具也可以幫助生成序列化版本號

屬性配置檔案:當配置檔案中的內容類似於 key1=value1,key2=value2的時候,我們把這種檔案稱為屬性配置檔案。建議以properties結尾。

java.io.File類

檔案或目錄的路徑名的抽象表示。
File類不能完成檔案的讀和寫
常用方法:

boolean exists()//判斷當前檔案是否存在。
boolean createNewFile()//當該檔案不存在時,以檔案形式建立。
boolean mkdir()//當該檔案不存在時,以目錄形式建立。
File getParentFile()//獲取父目錄
String getParent()//獲取父目錄的路徑
String getAbsolutePath()//獲取當前檔案的絕對路徑
String getName()//獲取檔名
boolean isDirectory()//判斷是否是目錄
boolean isFile()//判斷是否是檔案
long lastModified()//獲取檔案上一次修改的時間

例如:

public static void main(String[] args) {
        File f = new File("hello");
        long haomiao = f.lastModified();
        Date date = new Date(haomiao);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm-ss SSS");
        String s=sdf.format(date);
        System.out.println(s);
    }

long length() //獲得檔案大小
File[] listFiles() //返回一個檔案陣列,裡面是當前目錄下的所有檔案。

相關文章