在介紹輸入輸出流之前,首先需要了解如何創建文件,創建文件夾以及遍歷文件夾等各種操作,這里面不在一一介紹,主要介紹的是文件的輸入輸出流操作。
在起初學習文件操作之前,總是喜歡將輸入輸出弄混淆,后來通過看一些書以及一些視頻,有了一些自己的心得體會,隨后介紹一下,以便在我以后忘記的時候可以溫習一下。
1.流的概念及分類
Java將所有傳統的流模型(類或抽象類),都放在了Java.io包中,用來實現輸入輸出的功能。
這里面我們將流分成兩種:輸入流和輸出流。
輸入流:只能從中讀取數據,而不能向其寫入數據。代表:InputStream(字節輸入流),Reader(字符輸入流)。
輸出流:只能向其寫入數據,而不能從中讀取數據。代表:OutputStream(字節輸出流),Writer(字符輸出流)。
流按照操作類型也可以分成兩種:
在這個地方,我們需要弄清楚的就是什么是輸入,什么是輸出。如下圖所示:
從Java程序指向文件,這個過程我們稱為輸出或者寫入文件,從文件指向Java程序,這個過程我們稱為輸入或者讀出文件。
在輸入流和輸出流中,我們主要掌握4個流文件的操作:InputStream,OutputStream,Reader,Writer。這四個類都是抽象類,前兩個代表了字節的輸入輸出流,后兩個代表字符的輸入輸出流,當我們調用的時候通常使用他們的子類來實現我們的類方法。
2.字節輸出流(OutputStream)
字節輸出流它有以下幾個方法可以提供給它的子類使用(在輸入輸出流中,子類幾乎沒什么方法,都是調用父類的方法)
-
-
void write(byte[] b): 將 b.length 個字節從指定的 byte 數組寫入此輸出流
-
void write(byte[] b, int off, int len) :將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
-
abstract void write(int b) : 將指定的字節寫入此輸出流。
由於OutputStream是抽象類,因此我們在向文件寫入(輸出)字節的時候,需要用到它的子類FileOutputStream,接下來通過使用上面的方法,來實現字節流的輸出操作。
關於FileOutputStream:
(1).寫入數據文件,通過使用父類的方法,調用子類的對象
(2).FileOutputStream構造方法:
-
-
FileOutputStream(File file)
-
創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流。
-
-
FileOutputStream(File file, boolean append)
-
創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流,以追加的方式寫入。
-
-
FileOutputStream(String name)
-
創建一個向具有指定名稱的文件中寫入數據的輸出文件流。
-
-
FileOutputStream(String name, boolean append)
-
創建一個向具有指定 name 的文件中寫入數據的輸出文件流,以追加的方式寫入。
-
(3).流對象的使用步驟:
1).創建流子類的對象,綁定數據目的。
2).調用流對象的方法write寫
3).close釋放資源
(4).注意事項:流對象的構造方法,可以用來創建文件,如果文件存在的情況下,直接覆蓋原文件。
接下來通過代碼來實現字節輸出流的方法:
(1).輸出單個字節
package IO_File; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamDemo { public static void main(String[] args) throws IOException{ // TODO Auto-generated method stub //創建字節輸出流的對象fos,並且指定了將直接寫到哪里 FileOutputStream fos = new FileOutputStream("d:\\output.txt"); //寫入一個字節,但是在文件中顯示的是ASCII表中對應的值。 fos.write(97); //關閉系統資源 fos.close(); } }
最終結果:
(2).輸出字節數組
package IO_File; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamDemo { public static void main(String[] args) throws IOException{ // TODO Auto-generated method stub //創建字節輸出流的對象fos,並且指定了將直接寫到哪里 FileOutputStream fos = new FileOutputStream("d:\\output.txt"); byte[] b = {97,98,99,100,101,102,103}; //流對象的方法write寫數據 //將整個數組都寫入到文件中 fos.write(b); //寫入了數組的一部分,從索引1的位置開始,寫入了兩個字節 fos.write(b, 1, 2); //關閉資源 fos.close(); } }
最終結果:
3.字節輸入流(InputStream)
字節輸入流它有以下幾個方法可以提供給它的子類使用(在輸入輸出流中,子類幾乎沒什么方法,都是調用父類的方法)
由於InputStream是抽象類,因此我們在從文件讀取(輸入)字節的時候,需要用到它的子類FileInputStream,接下來通過使用上面的方法,來實現字節流的輸入操作。
關於FileInputStream:
在使用FileInputStream創建對象的時候,我們也需要為這個類綁定數據源(我們要讀取的文件名)
FileInputStream的構造方法與上述的構造方法相似,里面的參數有兩種類型:File類型對象,String類型對象。
輸入流讀取文件的操作步驟:
(1).創建字節輸入流的子類對象
(2).調用讀取方法read讀取
(3).關閉資源
注意事項:read()方法每執行一次,就會自動的讀取下一個字節。它的返回值是讀取到的字節,如果沒有字節可以讀取了,那么返回-1。
下面用代碼來實現FileInputStream的操作
(1).按照每個字節進行讀取(效率相對低)
package IO_File; import java.io.FileInputStream; import java.io.IOException; //字節輸入流 public class FileInputStreamDemo { public static void main(String[] args) throws IOException{ FileInputStream fis = new FileInputStream("d:\\input.txt"); //必須添加這個變量,直接使用fis.read作為輸出,因為每次執行read()方法的時候,讀取文件字節的指針都會向后移動一位。 int hasRead = 0; //因為hasRead是每個字節的值,當為-1的時候,代表了整個文件都被讀取。 while((hasRead = fis.read())!=-1){ System.out.println(hasRead); } //關閉文件資源 fis.close(); } }
最終結果:
文件中的數據:
現在再Java程序中的數據:
(2).讀取字節數組
方法介紹:
1).int read(byte[] b):讀入緩沖區的字節總數,如果因為已經到達文件末尾而沒有更多的數據,則返回 -1。
2).int read(byte[] b,int off,int len):將輸入流中最多 len 個數據字節讀入 byte 數組。
代碼實現:
package IO_File; import java.io.FileInputStream; import java.io.IOException; //字節輸入流 public class FileInputStreamDemo { public static void main(String[] args) throws IOException{ FileInputStream fis = new FileInputStream("d:\\input.txt"); //創建字節數組,相當於每次從文件中讀取1024個字節保存到這個數據中。這里面一般都寫1024 byte[] b = new byte[1024]; //必須添加這個變量,直接使用fis.read作為輸出,因為每次執行read()方法的時候,讀取文件字節的指針都會向后移動一位。 int len = 0 ; //因為hasRead是每個字節的值,當為-1的時候,代表了整個文件都被讀取。 while( (len = fis.read(b)) !=-1){ System.out.print(len); } fis.close(); } }
最終的答案跟上述的結果相同,但是使用數組的執行效率比單個字節的效率高很多。
4.字符輸出流(Writer)
由於Writer也是一個抽象類,因此我們用它的子類FileWriter來實現字符流的輸出操作。
關於FileWriter:
(1).方法介紹:
void write(int c):
void write(String str):寫入字符串。
void write(String str, int off, int len):寫入字符串的某一部分。
void write(char[] cbuf):寫入字符數組。
abstract void write(char[] cbuf, int off, int len):寫入字符數組的某一部分。
代碼實現:
package IO_File; import java.io.FileWriter; import java.io.IOException; public class FileWriterDemo { public static void main(String[] args) throws IOException{ // TODO Auto-generated method stub FileWriter fw = new FileWriter("d://filewriter.txt"); fw.write("123"); //必須要加fw.flush(),代表刷新,不加這個語句不能寫入到文件中 fw.flush(); fw.close(); } }
最終結果:
5.字符輸入流(Reader)
由於Reader也是一個抽象類,因此我們用它的子類FileReader來實現字符流的輸出操作。
(1)方法介紹:
代碼實現:
package IO_File; import java.io.FileReader; import java.io.IOException; public class FileReaderDemo { public static void main(String[] args) throws IOException{ // TODO Auto-generated method stub FileReader fr = new FileReader("d://input.txt"); int hasRead = 0; while((hasRead = fr.read())!=-1){ System.out.print((char)hasRead); } fr.close(); } }
最終結果:
字符流的輸入輸出與字節流的差不多,但是字符流只能操作文本文件,不能操作除了文本文件以外的文件,而字節流可以操作文本文件以及音樂,視頻等文件,因此在平時的IO流中,我們使用字節流的操作更多一些。
6.文件的復制操作。(這里面我使用字節流的方式實現)
文件的復制操作簡單的說就是將一個文件上的內容讀取出來,並且將讀取到的內容寫入到另一個文件上,因此在文件的復制操作中,需要我們使用文件的輸入和輸出流操作。
注意事項:在復制文件的過程中,我們需要先讀后寫。
代碼的實現方式如下:
package IO_File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileCopy { public static void main(String[] args) throws IOException{ // TODO Auto-generated method stub //文件復制,先讀后寫 FileInputStream fis = new FileInputStream("d://input.txt"); FileOutputStream fos = new FileOutputStream("d://1.txt"); int hasRead = 0; while((hasRead = fis.read()) != -1){ fos.write(hasRead); } fos.close(); fis.close(); } }
最終結果,將input.txt文件中的數據復制到了1.txt文件中。
為了我們共同進步,我這里有計算機專業的各種視頻,
如果想要,關注我的公眾號:念流聲。私聊我,看到后給你連接(只放了一張圖片,視頻有很多,需要什么可以私聊問我,有的話就給你)。