Java語言的輸入與輸出與文件處理

一、流的概念

流是指計算機各部件之間的數據流動。按照數據的傳輸方法,流可以分爲輸入流與輸出流。從流的內容上劃分,流分爲字節流和字符流。

  1. 輸入輸出流
    在Java語言中,把不同類型的輸入輸出源(鍵盤,屏幕等)抽象爲流,其中輸入或輸出的數據被稱爲數據流。數據流分爲輸入流和輸出流,從外設或外存傳遞到應用程序的流稱爲輸入流,將數據從應用程序傳遞到外設或外存的流稱爲輸出流。輸入流只可以從其中讀取數據,輸出流只可以向其中寫入數據。
  2. 緩衝流
    對數據流的每次操作若都是以字節爲單位進行操作,那麼數據的傳輸效率顯然很低,所以爲了提高數據的傳輸效率,通常使用緩衝流(buffered stream),即爲一個流配有一個緩衝區(buffer),這個緩衝區就是專門用於傳送數據的一塊內存。
    當向一個緩衝流寫入數據時,系統將數據發送到緩衝區,而不是直接發送到外部設備。緩衝區自動記錄數據,當緩衝區滿時,系統會將數據全部發送到相應的外部設備。
    當從一個緩衝流讀取數據時,系統實際是從緩衝區中讀取數據,當緩衝區空時,系統就會從相關外部設備自動讀取數據,並讀取儘可能多的數據填滿緩衝區,由此可見,緩衝區提高了內存與外部設備之間的數據傳輸效率。

二、輸入輸出流類庫

爲了方便流的處理,Java語言的流類都封裝在java.io包之中,所以要是用流類,必須導入java.io包。
按照處理的數據單位分爲字節流和字符流。

  • 字節流:操作的數據單元是8位字節,InputStreamOutputStream作爲抽象基類。
  • 字符流:操作的數據單元是字符,WriterReader作爲抽象基類。
  • 字節流可以處理所有的數據文件,但是若處理純文本數據,建議使用字符流。

三、使用InputStreamOutputStream流類

InputStreamOutputStream流類是Java語言中用來處理以位(bit)爲單位的流,它除了可以用來處理二進制文件(binary file)的數據以外,也可以用來處理文本文件。
**注意:雖然說字節流可以操作文本文件,但是並不提倡這樣做,因爲字節流操作文本文件,若是文件中有漢字,可能會出現亂碼,這是因爲字節流不能夠直接操作Unicode字符所導致,因此Java語言不提倡使用字節流讀取文本文件,而是建議字符流操作文本文件。

  1. InputStream流類
    常用方法:

    方法 功能
    public int read() 從輸入流中的當前位置讀入一個字節的二進制數據,然後以此數據位地位字節,配上8個全0的高位字節合成一個16位的整型量(0-255)返回給調用此方法的語句,若輸入流中的當前位置沒有數據,則返回-1。
    public int read(byte[] b) 從輸入流中的當前位置連續讀入多個字節保存在數組b中,同時返回所讀到的字節數。
    public int read(byte[] b, int off, int len) 從輸入流中的當前位置連續讀入len個字節,從數組b的第off+1個元素位置處開始存放,同時返回所讀到的字節數。
    public int available() 返回輸入流中可以讀取的字節數
    public long skip(long n) 使位置指針從當前位置向後跳過n個字節
    public void mark(int readlimit) 在當前位置處做一個標記,並且在輸入流中讀取readlimit個字節數後該標記失效
    public void reset() 將位置指針返回到標記的位置
    public void close() 關閉輸入流與外設的鏈接並且釋放所佔用的系統資源

當Java程序需要從外設如鍵盤、磁盤文件等讀入數據時,應該創建一個適當類型的輸入流對象來完成與該設備的連接,由於InputStream是抽象類,所以程序中創建的輸入流對象一般是InputStream某個子類的對象,通過調用該對象繼承的read()方法就可以實現相應設備的輸入操作。
流中的方法都聲明拋出異常,所以程序中調用流方法時必須處理異常,否則編譯不能通過,由於所有的I/O流都實現了AutoCloseable接口,而只是實現該接口的資源纔可以使用try-with-resources語句自動關閉打開的資源。因此,在使用I/O流進行輸入輸出操作的時候,可以使用try-with-resources語句處理異常。

  1. OutputStream流類
    OutputStream流類中包含一套所有字節輸出都需要的方法,可以完成最基本的向輸出流寫入數據的功能。

    方法 功能
    public void write(int b) 將參數b的低位字節寫入到輸出流
    public void write(byte[] b) 將字節數組b的全部字節按順序寫入到輸出流
    public void write(byte[] b, int off, int len) 將字節數組b中的第off+1個元素開始的len個數據,順序地寫入到輸出流
    public void flush() 強制清空緩衝區並執行向外設寫操作
    public void close() 關閉輸出流與外設的連接並且釋放所佔用的系統資源

    例如:寫入到文件中

    import java.io.*;
    
    class demo {
        public static void main(String[] args) throws IOException {
            char ch;
            FileInputStream fin = new FileInputStream(FileDescriptor.in);
            FileOutputStream fout = new FileOutputStream("text.txt");
            System.out.println("請輸入一串字符!(以#號結束)");
            while ((ch = (char) fin.read()) != '#')
                fout.write(ch);
        }
    
    }
    

    讀取文件的內容

     import java.io.*;
     
     class demo {
         public static void main(String[] args) throws IOException {
             char ch;
             int data;
     //        FileInputStream fin = new FileInputStream(FileDescriptor.in);
     //        FileOutputStream fout = new FileOutputStream("text.txt");
     //        System.out.println("請輸入一串字符!(以#號結束)");
     //        while ((ch = (char) fin.read()) != '#')
     //            fout.write(ch);
             FileInputStream fin = new FileInputStream("text.txt");
             FileOutputStream fout = new FileOutputStream(FileDescriptor.out);
             while (fin.available() > 0) {
                 data = fin.read();
                 fout.write(data);
             }
         }
     }
    

    FileInputStreamFileOutputStream主要用來處理二進制圖像文件,例如:

    import java.io.*;
    
    class demo {
        public static void main(String[] args) throws IOException {
            FileInputStream fin = new FileInputStream("1.png");
            FileOutputStream fout = new FileOutputStream("2.png");
            System.out.println("文件大小"+fin.available());//利用available()方法獲取文件的大小,並輸出,以字節(B)爲單位。
            byte[] b = new byte[fin.available()];//新建一個byte類型的數組
            fin.read(b);//將文件讀入數組
            fout.write(b);//將數組中的數據寫入新文件"2.png"中。
            System.out.println("文件複製更名成功!");
        }
    }
    
  2. 順序輸入流
    順序輸入流類SequenceInputStreamInputStream的直接子類,其功能是將多個輸入流順序連接在一起,形成單一的輸入數據流,沒有對應的輸出數據流存在。再進行輸入時,順序輸入流依次打開每個輸入流並讀取數據,也在讀取完畢後將該流關閉,然後自動切換到下一個輸入流。也就是說,由多個輸入流構成的順序輸入流,當從一個流中中讀取數據遇到EOF時,SequenceInputStream將會自動轉向下一個輸入流,直到構成SequenceInputStream類的最後一個輸入流讀取到EOF時爲止。
    SequenceInputStream類的構造方法、

    構造方法 功能
    public SequenceInputStream(Enumeration e) 創建一個串行輸入流,連接枚舉對象e中的所有輸入流
    public SequenceInputStream(InputStream s1, InputStream s2) 創建一個串行輸入流,連接輸入流s1和s2

    SequenceInputStream類的常用方法

    常用方法 功能
    public int available() 返回流中可讀取的字節數
    public void close() 關閉輸入流
    public int read() 從輸入流中讀取字節,遇到EOF就轉向下一輸入流
    public int read(byte[] b, int off, int len) 將len個數據讀到一個字節數組從off開始的位置
  3. 管道輸入輸出流
    Java之中管道字節輸入流PipedInputSteam和管道字節輸出流PipedOutputStream類提供了利用管道方式進行數據輸入輸出管理的類。管道流用來將一個程序或縣城的輸出連接到另外一個程序或線程作爲輸入,是的相互連接的線程能夠通過PipedInputStreamPipedOutputStream流進行數據交換,從而可以實現程序內部線程間的通信或不同程序之間的通信。
    jdk1.8文檔中明確說明了,不建議從單個線程中使用這兩個對象,因爲它可能會使線程死鎖。
    具體方法參考jdk文檔

  4. 過濾輸入輸出流
    過濾字節輸入流類FilterInputStream和過濾字節輸出流類FilterOuputStream,分別實現了在數據的讀寫操作的同時進行數據處理,他們是InputStramOutputStream類的直接子類。過濾字節輸入輸出流類的主要特點是,顧慮字節輸入輸出流時間裏在基本輸入輸出流之上,並在輸入輸出數據的同時能對所傳輸的數據做指定類型或格式的轉換,即可實現對二進制字節數據的理解和編碼轉換。
    具體使用方法見jdk文檔。
    整理如下:

    DataInputStream類的常用方法

    常用方法 說明
    public boolean readBoolean() 從流中讀1字節,但是字節值非0返回true,否則返回false
    public byte readByte() 從流中讀1自字節,返回該字節值
    public char readChar() 從流中讀取a,b2字節,形成Unicode字符(char)((a<<8)|(b&0xff))
    public short readShort() 從六中讀入2字節的short值並返回
    public int readInt() 從流中讀入4字節的int值並返回
    public float readFloat() 從流中讀入4字節的float值並返回
    public long readLong() 從流中讀入8字節的long值並返回
    public double readDouble() 從流中讀入8字節的double值並返回

    DataOutputStream類的常用方法

    常用方法 說明
    public void writeBoolean(boolean v) 將boolean寫入底層輸出流作爲1字節值,值true被寫爲(byte)1,值false作爲值(byte)0
    public void writeByte(int v) 向流中寫入1字節,最低的1字節,其他的字節丟棄
    public writeChar(int v) 向流中寫入參數v的高2字節,其他的字節丟棄
    public writeShort(int v) 向流中寫入參數v的高2字節,其他的字節丟棄
    public writeInt(int v) 向流中寫入參數v的4字節
    public writeFloat(float v) 向流中寫入參數v的4字節
    public writeLong(long v) 向流中寫入參數v的8字節
    public writeDouble(double v) 向流中寫入參數v的8字節
    package sample;
    
    import java.io.*;
    
    class demo {
    
        public static void main(String[] args) throws IOException {
            FileOutputStream fout = new FileOutputStream("text");
            DataOutputStream dout = new DataOutputStream(fout);
    
            dout.writeInt(10);
            dout.writeLong(12345);
            dout.writeFloat(3.1415626f);
            dout.writeDouble(987654321.123);
            dout.writeBoolean(true);
            dout.writeChars("GoodBye!\0");//此處不加上\0後面會拋出IO異常EOFException;
            FileInputStream fin = new FileInputStream("text");
            DataInputStream din = new DataInputStream(fin);
    
            System.out.println(din.readInt());
            System.out.println(din.readLong());
            System.out.println(din.readFloat());
            System.out.println(din.readDouble());
            System.out.println(din.readBoolean());
    
            char ch;
            while ((ch = din.readChar()) != '\0')
                System.out.print(ch);
        }
    }
    

    writeChars()裏面需要加上一個\0,不然的話會拋出異常,親測,EOFException3表示輸入過程中意外地到達文件尾或流尾的信號,導致異常。

  5. 標準輸入輸出流
    當程序對標準輸入輸出設備進行操作的時候,則不需要創建輸入或輸出流類的對象。
    對於一般的系統來說,標準輸入設備通常指鍵盤,標準輸出設備通常指屏幕顯示器。爲了方便程序對鍵盤輸入和屏幕輸出進行操作。Java系統事先在System類中定義靜態流對象System.inSystem.outSystem.errSystem.in對應着輸入流,通常指鍵盤輸入設備。System.out對應着輸出流,指顯示器等信息輸出設備,System.err對應着標準錯誤輸出設備,使得程序的運行錯誤,可以由固定的輸出位置,通常來說該對象對應着顯示器。
    1.標準輸入
    Java語言的標準輸入是System.inBufferedInputStream類的對象,當程序需要從鍵盤上讀入數據時,只需要調用System.inread()方法即可,該方法從鍵盤緩衝區讀入一個字節的二進制數據,並將它們存儲到緩衝區b,實際讀取的字節數作爲整數返回。其方法:public int read (byte[] b) throws IOException。第一個字節存入b[0],以此類推。
    2.標準輸出
    Java語言的標準輸出,是打印輸出流PrintStream類的對象。詳見jdk手冊。

    import java.io.*;
    
    class demo {
    
        public static void main(String[] args) throws IOException {
            byte[] b = new byte[128];
            System.out.println("請輸入字符:");
            int count = System.in.read(b);
            System.out.println("輸入的是:");
            for(int i = 0; i < count; ++i){
                System.out.println(b[i] + " ");//輸出的是ASCII值
            }
            for(int i = 0; i < count; ++i)
                System.out.println((char)b[i] + " ");//以字符的方式輸出數組b元素
        }
    
    

四、使用ReaderWriter流類

ReaderWriter類則是用來處理“字符流”的,也就是文本文件,與字節輸入輸出流的功能一樣,字符輸入輸出流類知識建立了一條通往文本文件的通道。
Reader類的常用方法

常用方法 說明
public int read() 從輸入流中讀一個字符
publici int read(char[] cbuf) 從輸入流中讀最多cbuf.length個字符,存入字符數組cbuf
public int read(char[] cbuffer, int off, int len) 從輸入流中讀最多len個字符,存入字符數組cbuffer中從off開始的位置
public long skip(long n) 從輸入流中最多向後跳n個字符
public boolean ready() 判斷流是否最好讀的準備
public void mark(int readAheadLimit) 標記輸入流的當前位置
public boolean markSupported() 測試輸入流是否支持mark
public void reset() 重定位輸入流
public void close() 關閉輸入流

Writer類的常用方法

常用方法 說明
public void write(int c) 將單一字符c輸出到流中
public void write(String str) 將字符串輸出到流中
public void write(char[] cbuf) 將字符數組cbuf輸出到流
public void write(char[] cbuf, int off, int len) 將字符數組按指定格式輸出
public void flush() 將緩衝區的數組寫到文件
public void close() 關閉輸出流
  1. 使用FileReader類讀取文件
    文件字符輸入流類FileReader是繼承自InputStreamReader類,而InputStreamReader類又是繼承自Reader類,因此,Reader類與InputStreamReader類所提供的方法均可供FileReader類所創建對象使用。
    使用FileReader類讀取文件時,必須先調用FileReader()構造方法創建FileReader類的對象,再利用它來調用read()方法。
    其構造方法:public FileReader(String name),根據文件名稱創建一個可以讀取的輸入流對象。

    import java.io.*;
    
    class demo {
    
        public static void main(String[] args) throws IOException {
            char[] ch = new char[500];//創建可以容納500字符的數組
            FileReader file = new FileReader("text.txt");
            int num = file.read(ch);//將數據讀取到數組之中,並且返回讀取的字符數量
            String str = new String(ch, 0, num);//將字符數組轉換成爲字符串
            System.out.println("讀取的字符個數有:" + num + "個。內容如下:");
            System.out.println(str);
        }
    }
    

    這樣子會將文件中的內容讀出來,輸出。但是可能會有人遇到亂碼問題,記住,windows默認創建的txt文件時ANSI編碼格式,所以,你需要保存爲UTF-8格式。

  2. 使用FileWriter類寫入文件
    文件字符輸出流類FileWriter繼承自OutputStreamWriter類,但是OutputStreamWriter類又是從Writer類中繼承得到的,所以說,Writer類與OutputStreamWriter類suotigong7的方法均可提供給FileWriter類所創建的對象使用。
    FileWriter類的構造方法

    構造方法 功能說明
    public FileWriter(String filename) 根據所給的文件名創建一個可以供寫入字符數據的輸出流對象,原先的文件會被覆蓋
    public FileWriter(String filename, boolean a) 同上,如果說a設置爲true,則會被數據追加在原先文件之後
    import java.io.*;
    
     class demo {
         public static void main(String[] args) throws IOException {
             FileWriter file = new FileWriter("text.txt");
             String str = "Java牛皮!";
             file.write(str);
             file.close();
         }
     }
    
  3. 利用BufferedReader類讀取文件
    緩衝字符輸入流類BufferedReader繼承自Reader類,BufferedReader類是用來讀取緩衝區李的數據,使用該類讀取緩衝區中的數據之前,必須創建FileReader類對象,再將以該對象來創建BufferedReader類的對象,然後纔可以利用該對象來讀取緩衝區中的數據。
    構造方法

    構造方法 功能說明
    public BufferedReader(Reader in) 創建緩衝區字符輸入流
    public BufferedReader(Reader in, int size) 創建緩衝區字符輸入流,並設置緩衝區大小

    常用方法

    常用方法 功能說明
    public int read() 讀取單一字符
    public int read(char[] ch) 從流中讀取字符並且寫入到字符數組之中
    public int read(char[] ch, int off, int len) 從流中讀取字符存放到字符數組之中,off代表數組下標,len代表的是數組長度
    public long skip(long n) 跳過n個字符不讀取
    public String readLine() 讀取一行字符串
    public void close() 關閉流
    import java.io.*;
    
    class demo {
        public static void main(String[] args) throws IOException {
            FileReader file = new FileReader("text.txt");
            BufferedReader bfile = new BufferedReader(file);
    
            String tmpString;
            while((tmpString = bfile.readLine())!=null){
                System.out.println(tmpString);
            }
        }
    }
    
  4. 使用BufferedWriter類寫入文件
    BufferedReader類類似,BufferedWriter繼承自Writer類,BufferedWriter類,是用來將數據寫入緩衝區中,首先來說,我必須創建FileWriter類對象,再以該對象爲參數創建BufferedWriter類的對象,然後就可以利用此對象來講數據寫入緩衝區中,所以不同的是,緩衝區中的數據最後必須都要用flush()方法將緩衝區清空,也就是將緩衝區的數據全部寫到文件之內。
    緩衝字符輸出流類BuffereWriter的構造方法:

    構造方法 功能說明
    public BufferedWriter(Writer out) 創建緩衝區字符輸出流
    public BufferedWriter(Writer out, int size) 創建緩衝區字符輸出流

    BufferedWriter類的常用方法

    常用方法 功能說明
    public void writer(int c) 將單一字符寫入緩衝區
    public void write(char[] ch. int off, int len) 將字符數組ch按照指定格式寫入到輸出緩衝區中(off表示數組下標,len表示寫入的字符數)
    pulic void write(String str, int off, int len) 寫入字符串(off表示下標,len表示寫入的字符數)
    public void newLine() 寫入回車換行字符
    public void close() 關閉流
    import java.io.*;
    
    class demo {
        public static void main(String[] args) throws IOException {
            BufferedWriter out = new BufferedWriter(new FileWriter("text.txt"));
            String str = new String("Hello!Java!我是新一代程序員!");
            out.write(str);
            out.newLine();
            out.write("我必定會登頂巔峯!");
            out.close();
        }
    } 
    

五、文件的處理與隨機訪問

  1. 對於文件以及文件夾的管理

    • 創建一個File類的對象,每個File類的對象對應着系統的一個磁盤文件或者文件夾,所以說創建File類對象需要給出它所對應的文件名或者文件夾名。
      File類的構造方法

      構造方法 功能說明
      public File(String path) 利用path參數創建對象
      public File(String path, String name) 以path爲路徑,創建name的文件或文件夾
      public File(File dir. String name) 用一個已經存在代表某磁盤的文件夾的File對象dir作爲文件夾,以name作爲文件或文件夾名來創建File對象

      因爲在不同的操作系統中使用的文件夾的分隔符不一樣,如Windows操作系統使用的是反斜線,但是在UNIX操作系統上使用的是正斜線,但是爲了保證Java程序能夠在不同的平臺上運行,可以使用File類的一個靜態變量File.separator。該屬性中保存了當前系統規定的文件夾分隔符,使用它會組合成在不同操作系統上都能夠通用的路徑。

    • 文件或文件夾屬性
      常用方法

    用方法 功能說明
    public boolean exists() 判斷文件或文件夾是否存在
    public boolean isFile() 判斷對象是否代表有效文件
    public boolean isDirectory() 判斷對象是否代表有效文件夾
    public String getName() 返回文件名或文件夾名
    public String getPath() 返回文件或者文件夾的路徑
    public long length() 返回文件的字節數
    public boolean canRead() 判斷文件是否可讀
    public boolean canWriter() 判斷文件是否可寫
    public String[] list() 將文件夾中所有文件名保存在字符串數組中返回
    public boolean equals(File file) 比較兩個文件或文件夾是否相同
    1. 文件或文件夾操作
      管理操作方法
    常用方法 功能說明
    public boolean renameTo(File newFile) 將文件重命名成newFile對應的文件名
    public boolean delete() 將當前文件刪除,若刪除成功返回true,否則返回false
    public boolean mkdir() 創建當前文件夾的子文件夾,若成功返回true,否則返回false
  2. 對文件的隨機訪問
    RandomAccessFile類的構造方法

    構造方法 功能說明
    public RandomAccessFile(String name, String mode) 以name來指定隨機文件流對象所對應的文件名,以mode表示對文件的訪問模式
    public RandomAccessFile(File file, String mode) 以file來指定隨機文件流對象所對應的文件名,以mode表示對文件的訪問模式

    訪問模式:r:表示只讀方式打開文件,rw:表示以讀寫方式打開文件。

    RandomAccessFile類的常用方法

    常用方法 功能說明
    public void close() 關閉隨機訪問文件並釋放系統資源
    public final FIleDescriptorgetFD() 獲取文件描述符
    public long getFilePointer() 返回文件指針的當前位置
    public long length() 返回文件長度
    public int skipBytes(int n) 跳過輸入流中n個字符,並返回跳過實際的字節數
    public int read() 從文件輸入流中讀取一個字節的數據
    public int read(byte[] b, int off, int len) 從文件輸入流的當前指針位置開始讀取長度爲len字節的數據存放到字節數組b中,存放的便宜位置爲off,若遇到文件結束符,則返回值-1
    public final void readFully(byte[] b) 從文件輸入流的當前指針位置開始讀取b.length字節的數據存放到字節數組b中,若遇文件結束符,則拋出EOFException類異常
    public final void readFully(byte[] b, int off, int len) 從文件輸入流的當前指針位置開始讀取長度爲len字節的數據,放到b數組中,存放的位置開始爲off,遇到文件結束符,則拋出EOFException類異常
    public final boolean readBoolean() 讀取文件的邏輯值
    public final byte readByte() 從文件中讀取帶符號的字節值
    public final char readChar() 從文件中讀取一個Unicode字符
    public final String readLine() 從文本文件中讀取一行
    public void seek(long pos) 設置文件指針位置

    RandomAccessFile類用於寫入操作的常用方法

    用方法 功能說明
    public void write(int b) 在文件指針的當前位置寫入一個int型數據b
    public void writeBoolean(boolean v) 在文件指針的當前位置寫入一個boolean型數據v
    public void writeByte(int v) 在文件指針的當前位置寫入一個字節值
    public void writeBytes(String s) 以字節形式寫入一個字符串到文件
    public void writeChar(int v) 在文件指針的當前位置寫入v的兩字節,高字節優先
    public void writeChars(String s) 以字符形式寫一個字符串到文件
    public void writeDouble(double v) 在文件當前指針位置寫入8字節數據v
    public void writeFloat(float v) 在文件當前指針位置寫入4字節數據v
    public void writeInt(int v) 在整形數作爲4字節寫入文件
    public void writeLong(long v) 將長整型數作爲8字節寫入文件
    public void writeShort(int v) 在文件指針當前位置寫入2字節,高位字節
    public void writeUTF(String str) 作爲UTF格式向文件之中寫入一個字符串
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章