java i o是什么流_【Java】I/O流的操作、认识使用
重要聲明:本文章僅僅代表了作者個人對此觀點的理解和表述。讀者請查閱時持自己的意見進行討論。
1、序
在 Java 編程中,I/O流的操作是必須學會的一項技能。無論是文件的復制粘貼,還是上傳下載,無論是文本的讀取寫入,還是音視頻的播放,都離不開I/O流的加持。I/O流如此重要,怎么能不了解它!本文將帶你了解在Java里,如何自如的操控各種流。
2、理解
網上教程千千萬,學校教材萬千千,無數遍的使用水流來比喻Java里的I/O流。這無疑是一個非常恰當合適的比喻,但依舊不能解開每個人對流的疑問,當然也包括本文,不一定能被每個人理解,但希望哪怕一個人能夠理解。
我也將使用水流來作比喻。現在,要將一個湖里的所有水全部轉移到另一個水庫里面,怎么辦?當然是用抽水機啊,要么就用桶不同的挑嘛。為了能夠更好地結合程序來理解,咱們假設選擇了使用桶挑水過去的方案。
隨即便產生了下面圖案:
有了這張圖,對Java里I/O的理解就會更加簡單一點。見名知意,為啥叫I/O流,是因為在java中,流的操作是通過 兩個類的協同操作進行完成的。
這兩個分別是:
I: InputStream 輸入流
O: OutputStream 輸出流
下面分別進行簡述:
(1)、InputStream 輸入流
輸入流和輸出流都是相對于程序來進行稱呼的。脫離了程序,不能確定某個流就是輸入或輸出流,下圖中“桶”就相當于是程序,那么輸入流是什么,一目了然:
可見,從湖泊A 到桶里的這部分水流,就可以說是輸入流,但你不能單純的認為就是這一通水就是輸入流,而應該理解為:整個湖里的水,在放入桶的這個行為過程中,這時這些水對于這個桶來說是輸入流。
所以同樣的,在程序里,數據流在往程序里跑時這個數據流叫做輸入流,承載這個數據跑到程序里面的類,是InputStream。
(2)、OutputStream 輸出流
與輸入流相似,想必你看了上面的輸入流,你對輸出流可能也有那個概念了,只不過是反其道而行之的,如圖所示:
從桶里,往湖泊B倒水,這個行為過程中,所有的湖泊里的水,這可理解為輸出流。在程序里,數據流在往程序外跑時,這個流叫做輸出流,承載這個數據跑到外面去的類,是OutputStream。
上訴的輸入流,輸出流都是對于程序來說的,把桶比作是這個運輸水的程序,所以在闡述是都是以“桶”為對象來闡述的。
3、代碼加入
(1)、InputStream 輸入流
首先講述InputStream輸入流的代碼應用。InputStream是一個abstract的抽象類,抽象類是不能直接實例化對象的,所以,Java為我們貼心的實現了許許多多的、用于處理各種場景的輸入流類,比較常用的FileInputStream可見名知意,它是專門為讀取文件而生的文件輸入流承載對象。下面是文件輸入流的使用案例:
// 為了保證程序的正常,請在D盤下建立文件:file.txt,文件內容:File Inputstream test.
// FileInputStream 在 java.io 包下,如果使用文本編輯器編寫代碼,記得導包:import java.io.FileInputStream;
public class Test {
public static void main(String[] args) throws Exception {
// 使用指定文件構建文件來構建文件輸入流。
FileInputStream fileInputStream = new FileInputStream("D:/file.txt");
// 就如同上圖要把一個湖泊里面的水全部傳到另一個湖泊,中間借助了一個“桶”來幫助。
// 并且,上面將“桶”比喻為整個程序。
// 現在要擯棄:將“桶”比喻為整個程序。這個概念了。
// 實際上“桶”只能充當程序里的一個變量。
// 這個變量每次能容納一定容量的數據。
// 這里定義 datas 數組。是一個每次只能容納4字節的“小桶”。
byte[] datas = new byte[4];
// 但是我們不能確定是不是每次重復用這只“桶”去舀水的時候都能把桶舀滿。
// 就比如上邊圖中,當桶兒把湖泊A里的水快舀完時,有一個人提著桶去舀最后一桶水,發小并不能舀滿
// 一整桶水,他索性舀了多少就帶走多少了。
// 而在程序里,程序是是的,它必須要你告訴他每次舀了多少水,
// 特別是在最后一次沒能舀滿一“桶”水時,這個標記了舀了多少水的字段就必不可少了。
// 定義一個字段表示每次舀了多少水。
int size = 0;
// 舀水一次可能完不成,畢竟我們桶只有這么大,所以要來來回回不同的舀,即循環進行。
// 有人可能說,你定義一個超大的桶,不就可以一次搞定了。
// 答:可以是可以,但是要明白,這個過程中是要把數據保存在你電腦的內存條上的,假如你的文件有100GB,你又定義了一個100GB的桶
// 而你的電腦內存一共才16GB,程序一運行就會內存溢出的,直接報錯了。
// 所以桶的大小,要根據電腦內存有多大,讀取行為發生的頻率大不大來自己權衡的一個數值。
// 下面開始循環讀取
while (size != -1) {
// 當文件讀取完成后, read 方法會返回 -1來表示已經讀取完成了,所以,只要不是 -1 就一定表示數據還能繼續讀取。
// 輸入流的讀取的方法會返回當前實際讀取了多少數據的大小,正合適告訴我們舀了多少水。
size = fileInputStream.read(datas);
// 此時 datas 里面的數據就已經是舀到的數據了。
// 拿到數據構建字符串:
String str = new String(datas);
// 輸出結果:
System.out.print(str);
}
// 當循環完成,也就表示讀取完成,水舀完了。
// 不要忘了最后調用輸入流的關閉方法,你要是不調用關閉方法,就如同占著茅坑不拉屎是一樣的道理。
fileInputStream.close();
}
}
運行這個程序,最后輸出:File Inputstream test.
加上代碼中的注釋,相信理解起來非常簡單。這是一個非常典型的代碼編寫方式,所有的輸入流幾乎都是這樣的代碼流程來進行數據的讀取。
(2)、OutputStream 輸出流
輸入流是講數據從程序的外部讀入到程序的內部,那么輸出流就是將數據從程序的內部輸出到程序的外部,上面使用了一個簡單的程序將外部文件“file.txt”的內容讀取到了程序內部并顯示,現在,我們要在程序內部設定好一個字符串,然后輸出到文件中,同輸入流一樣,這里也采用文件相關的“FileOutputStream”文件輸出流,來完成數據的輸出。示列代碼如下:
public class Test {
public static void main(String[] args) throws Exception {
// 準備好要輸出的數據內容。
String str = "File OutputStream test.";
// 構建文件輸出流:
FileOutputStream fileOutputStream = new FileOutputStream("D:/outFile.txt");
// 無論是流的輸出,還是流的讀取,它們操作的數據都是 byte 的二進制數據。
// 而定義的準備用于輸出數據是字符串,所以,需要先從字符串轉換成 byte 二進制數據。
byte[] datas = str.getBytes();
// 將數據寫到輸出流。
fileOutputStream.write(datas);
// 這一步很重要。
// 上面一行代碼是將數據寫入到了一個磁盤緩存區,內容其實(可能)還沒有真的被寫入到文件里。
// 這一行代碼的調用,可以強制的將數據從緩存區強制的寫入的文件中,所以為了保證效果,務必每次在 “關閉” 輸出流前
// 記住要調用一次該方法。
fileOutputStream.flush();
// 最后不要忘了關閉輸出流。
fileOutputStream.close();
}
}
運行程序,會在磁盤D盤下多出一個 outFile.txt 文件,打開這個文件,就可以看到文件內容:File OutputStream test.
你發現這個輸出流并沒有像輸入流那樣去循環的進行輸出。是的,因為這里是為了讓咱們快速理解輸出流的使用方式,只是單獨的進行單向輸出,而且輸出的只有幾個字,我們能確定它的大小不是很大。為什么上面輸入流讀取的文件也很小,而我們也是用循環讀取?因為我們只是在測試學習,知道這個文件不大,實際開發中,你永遠不知道你要讀取的文件有多大,對于我們不知道的事物,我們應該采取兼容性最大的程序代碼方式去編寫。所以輸入時往往使用循環來讀取。
現在了解了輸入流,輸出流,最有魅力的地方不是單獨使用它們,而是將它們結合起來使用,達到更加強悍的功能。耳熟能詳的的復制功能,就可以通過輸入流,輸出流的相互配合完成。
4、結合使用
將輸入流,輸出流結合起來,學會I/O流的一個關鍵環節,任何輸出流,輸入流都可以相互結合,而不一定只能是文件的輸入流對上文件的輸出流。假如現在我們有一個 1GB 大小的 視頻文件《video.mp4》在D盤根目錄,要把它復制到 E盤下。示列代碼如下:
public class Test {
public static void main(String[] args) throws Exception {
// 視頻文件路徑。
String videoFile = "D:/video.mp4";
// 建立輸入流
FileInputStream fileInputStream = new FileInputStream(videoFile);
// 準備一個小“桶”每次舀這么多數據。
byte[] datas = new byte[1024];
// 每次舀水的量
int size = 0;
// ---------------------------------------------------------------
// 準備輸出文件路徑
String targetFile = "E:/video.pm4";
// 建立輸出流
FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
// 循環的使用“小桶”舀。
while (size != -1) {
// 舀
size = fileInputStream.read(datas);
// 舀到數據,往目標倒。
// 因為我們使用 size 標記每次舀了多少水,所以這里寫的時候,也要講“桶里”有多少水這個信息
// 告訴寫出的位置,這樣就能拿在桶里拿到正確的數據量。
fileOutputStream.write(datas, 0, size);
}
// 完成操作,關閉輸入流,關閉輸出流
fileInputStream.close();
fileOutputStream.close();
// 提示完成
System.out.println("復制完成!");
}
}
執行程序,將會把D盤下的文件復制一份在E盤下,這樣就完成了文件的復制,同時對文件輸入流,輸出流有了更深刻的印象。在Java里,流的操作中心都是圍繞
read讀的方法,和write寫的方法,無論怎么樣,只要搞清楚各個類是用來干嘛的以及明白數據流向的方向,就能輕松的理解流的操作了。
總結
以上是生活随笔為你收集整理的java i o是什么流_【Java】I/O流的操作、认识使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一份工作,坚持多久跳槽最合适?
- 下一篇: Java开发的六大基本原则