Java中的字節(jié),字符輸出流與字節(jié)和字符輸入流的簡單理解
我先解釋一下什么叫IO流:
- I:指的是InputStream,這是一個抽象類,最常用的子類是FileInputStream
- O:值得是OutputStream,這也是一個抽象類,最常用的子類是OutputStream
- 流:由于在進行文件操作的時候大多數(shù)是用的byte數(shù)據(jù),這些數(shù)據(jù)并不是一次性寫入(讀取),而是像水龍頭那樣慢慢的流(想象一下你接水的場景)
廢話還是不多bb,先來一份簡單的代碼:
File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if (!file.exists()){ file.createNewFile(); }
其中File.separator
指的是當(dāng)前系統(tǒng)的默認(rèn)分隔符,這樣寫的原因是可以保證Java文件在Windows系統(tǒng)運行時和Linux系統(tǒng)運行時都不會出錯
這段代碼也很簡單,主要就是創(chuàng)建一個文件。
當(dāng)然,這都不是重點,重點在下面
字節(jié)輸出流OutputStream
對于Output Stream類來說,它本身定義的是一個抽象類,按照抽象類的原則來講,需要定義抽象類的子類,而我們要執(zhí)行的是文件操作,則可以使用FileOutputStream子類來完成。而我們最關(guān)心的還是子類中的構(gòu)造方法
方法 | 描述 |
---|---|
public FileOutputStream(File file) throws FileNotFoundException | 實例化FileOutputStream,主要用于新建數(shù)據(jù) |
public FileOutputStream(File file,boolean append) throws FileNotFoundException | 實例化FileOutputStream,主要用于追加數(shù)據(jù) |
我們在實例化OutputStream對象之后肯定要進行輸出操作。在OutputStream類中定義了3個輸出方法。例如:
方法 | 描述 |
---|---|
public abstract void write(int b) throws IOException | 輸出單個字節(jié)數(shù)據(jù) |
public void write(byte[] b) throws IOException | 輸出一組字節(jié)數(shù)據(jù) |
public abstract void write(byte[] b,int off,int len) throws IOException | 輸出部分字節(jié)數(shù)據(jù) |
可能大家在看表的時候已經(jīng)發(fā)現(xiàn)了,都是byte類型的數(shù)據(jù)。
使用OutputStream向文件中輸出數(shù)據(jù)。
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if (!file.exists()){ file.createNewFile(); } OutputStream output=new FileOutputStream(file);// 實例化父類 String data="Hello World!"; output.write(data.getBytes()); output.close(); } }
可以發(fā)現(xiàn),在文件輸出的過程中,如果要輸出的文件和目錄不存在那么會覆蓋掉原有的內(nèi)容,咋辦呢?別忘了我們還有一個構(gòu)造方法專門是為了追加數(shù)據(jù)的:
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if (!file.exists()){ file.createNewFile(); } OutputStream output=new FileOutputStream(file,true);// 追加數(shù)據(jù) String data="Hello World!"; output.write(data.getBytes()); output.close(); } }
執(zhí)行一遍會發(fā)現(xiàn),會自動的把數(shù)據(jù)附加在已有的數(shù)據(jù)后面。
我們在來看看另一種類似的流
字符輸出流
看標(biāo)題,字節(jié)和字符就差一個字,但是,熟悉Java數(shù)據(jù)基本類型的都知道。這倆貨一個是byte,一個是String。那么我們在對文件進行輸出操作的時候,就可以把需要輸出的內(nèi)容定義成String類型而不是byte字節(jié)型;
同樣,Writer也是一個抽象類,當(dāng)我們用于文件操作的時候,常用的子類就是FileWriter。我們來看看Writer類的常用方法:
方法 | 描述 |
---|---|
public abstract void close() throws IOException | 關(guān)閉輸出流 |
public void write(String str) throws IOException | 將字符串輸出 |
public void write(char[] cbuf) throws IOException | 將字符數(shù)組輸出 |
public abstract void flush() throws IOException | 強制性清空內(nèi)存 |
還是不多bb,上代碼,就知道啥樣子了:
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if (!file.exists()){ file.createNewFile(); } Writer out=new FileWriter(file); String data="Hello World!"; out.write(data); out.close(); } }
了解了輸出流,我們再來看看輸入流;
Java中的輸入流有兩種,一種是InputStream,另一種就是Reader??催@名字就知道,md,可能又是一種簡單的一種難的。沒錯,你猜對了;
字節(jié)輸入流InputStream
同樣,這貨也是一個抽象類,用于文件操作的也是他的子類FileInputStream,當(dāng)然也有幾個方法用于操作文件:
方法 | 描述 |
---|---|
public abstract int read() throws IOException | 讀取單個字節(jié)數(shù)據(jù),每次執(zhí)行read()方法都會讀取一個數(shù)據(jù)源的指定數(shù)據(jù),如果已經(jīng)讀到了結(jié)尾,則會返回-1 |
public int read(byte[] b) throws IOException | 讀取多個字節(jié)數(shù)據(jù),如果要讀取的數(shù)據(jù)小于byte的數(shù)據(jù),這個時候read()方法的返回值int返回的是數(shù)據(jù)個數(shù),如果現(xiàn)在開辟的字節(jié)數(shù)組小于讀取的長度,且數(shù)據(jù)已經(jīng)讀取完了。則這個時候返回的是-1 |
public int read(byte[] int off,int len) throws IOException | 讀取指定多個字節(jié)數(shù)據(jù) |
我們還是看看讀取內(nèi)容,具體代碼怎么去實現(xiàn)它:
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if(file.exists()){ InputStream input=new FileInputStream(file); byte data[] = new byte[1024];// 開辟一個1024長度的byte數(shù)組 int len=input,read(data); input.close(); System.out.println("讀取的內(nèi)容:"+new String(data,0,lem)); } } }
上述代碼簡明的表達(dá)了讀取文件的全部內(nèi)容的邏輯,但是想象一下,單個單個的讀取怎么做呢?
這時候需要一點以前的知識了,看看代碼:
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if(file.exists()){ InputStream input=new FileInputStream(file); byte data[] = new data[1024]; int foot=0;// 數(shù)組的索引初始值 int temp=0;// 待會自己看是啥作用 while((temp=input.read())!=-1){ data[foot++]=(byte) temp; input.close(); System.out.println("讀取到的數(shù)據(jù)是:"+new String(data,0,foot)); } } } }
了解了字節(jié)輸入流,是不是還得了解一下字符輸入流。來吧,也別愣著了,碼代碼唄;
字符輸入流Reader
那些啥抽象啊,子類啊啥的我都不說了,反正類似,自己慢慢琢磨琢磨。
看看有哪些方法:
方法 | 描述 |
---|---|
public abstract void close() throws IOException | 關(guān)閉流 |
public int read() throws IOException | 讀取單個字符 |
public int read(char[] cbuf) throws IOException | 將內(nèi)容讀到字符數(shù)組中,返回讀入的長度 |
有一點和上面的不一樣:
雖然Writer類中提供了輸出字符串?dāng)?shù)據(jù)的操作方法,但是在Reader類中并沒有這樣的定義。之所以會這個樣子,完全是因為在使用OutputStream輸出數(shù)據(jù)時,其程序可以輸出的大小一定是程序可以承受的數(shù)據(jù)大小,如果在使用InputStream讀取時,可能被讀取的數(shù)據(jù)灰常大,一次性全部讀取的話可能會問題,于是就只有一個一個的讀取
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } Reader in=new FileReader(file); char data[] = new char[1024]; int len=in.read(data); in.close(); System.out.println("讀取的內(nèi)容:"+new String(data,0,len)); } }
代碼寫了這么一大堆,我們最后再看看一個問題;
字節(jié)流和字符流的區(qū)別
通過以上的代碼演示我們知道了,字節(jié)流和字符流都有類似的功能,那么在開發(fā)的過程中具體使用哪一種呢?
他們的區(qū)別在于:
字節(jié)流在進行IO操作時,直接針對的時操作的數(shù)據(jù)終端(如文件),而字符流操作時不是直接針對于終端,而是針對于緩存區(qū)(理解為內(nèi)存)的操作,而后由緩存區(qū)來操作終端(如文件),這屬于間接操作,按照這樣的方式,如果在使用字節(jié)流時不關(guān)閉最后的輸出操作,也可以將所有的內(nèi)容進行輸出,而使用字符流時如果不關(guān)閉,則意味著緩沖區(qū)的內(nèi)容不會被輸出,當(dāng)然,這個時候可以由用戶自己調(diào)用flush()方法去強制性的手動清空 例如:
import java.io.*; public class test { public static void main(String[] args) throws Exception{ File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); System.out.println("父級目錄創(chuàng)建成功"); } if (!file.exists()){ file.createNewFile(); } Writer out=new FileWriter(file); String data="Hello World!"; out.write(data); out.flush(); } }
總結(jié)一下,字節(jié)流和字符流的主要區(qū)別:
- 字節(jié)流沒有使用到緩沖區(qū),而字符流使用了;
- 處理各種數(shù)據(jù)都可以通過字節(jié)流完成,而在處理中午的時候使用字符流會更方便;
最后,留一個思考題給有興趣的小伙伴。
現(xiàn)有一個要求,按照DOS系統(tǒng)的文件拷貝命令,由初始化參數(shù)輸入源文件和拷貝文件的路徑,而后執(zhí)行操作。
提示:本程序直接在主方法中完成,不考慮多余的方法和類的設(shè)計??紤]大文件的情況(500MB以上)
我把思路也貼給大家:
方案一:將要復(fù)制的文件全部讀取到內(nèi)存中,而后將所有的內(nèi)容一次性輸出到目標(biāo)文件;
方案二:采用邊讀邊寫的方式一點一點的進行文件的復(fù)制。
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
靜態(tài)方法中調(diào)用Spring注入過程解析
這篇文章主要介紹了靜態(tài)方法中調(diào)用Spring注入過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11mybatis查詢到了數(shù)據(jù),但是實體類個別字段為null問題
這篇文章主要介紹了mybatis查詢到了數(shù)據(jù),但是實體類個別字段為null問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01java配置變量的解釋,搬運他人優(yōu)質(zhì)評論(推薦)
這篇文章主要介紹了java配置變量,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Java單線程程序?qū)崿F(xiàn)實現(xiàn)簡單聊天功能
這篇文章主要介紹了Java單線程程序?qū)崿F(xiàn)實現(xiàn)簡單聊天功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10