Java二十篇: IO流

圣誕節(jié)快樂



圣誕節(jié)真的是一個溫柔又溫暖的節(jié)日了,可以在這飄雪的歲末里,富有儀式感又溫柔地對待生命里珍貴的人說上一句:“圣誕快樂 喜樂長安 ”
IO是指Input/Output,即輸入和輸出。以內(nèi)存為中心:
Input指從外部讀入數(shù)據(jù)到內(nèi)存,例如,把文件從磁盤讀取到內(nèi)存,從網(wǎng)絡(luò)讀取數(shù)據(jù)到內(nèi)存等等。
Output指把數(shù)據(jù)從內(nèi)存輸出到外部,例如,把數(shù)據(jù)從內(nèi)存寫入到文件,把數(shù)據(jù)從內(nèi)存輸出到網(wǎng)絡(luò)等等。
為什么要把數(shù)據(jù)讀到內(nèi)存才能處理這些數(shù)據(jù)?因為代碼是在內(nèi)存中運行的,數(shù)據(jù)也必須讀到內(nèi)存,最終的表示方式無非是byte數(shù)組,字符串等,都必須存放在內(nèi)存里。
從Java代碼來看,輸入實際上就是從外部,例如,硬盤上的某個文件,把內(nèi)容讀到內(nèi)存,并且以Java提供的某種數(shù)據(jù)類型表示,例如,byte[]
,String
,這樣,后續(xù)代碼才能處理這些數(shù)據(jù)。
因為內(nèi)存有“易失性”的特點,所以必須把處理后的數(shù)據(jù)以某種方式輸出,例如,寫入到文件。Output實際上就是把Java表示的數(shù)據(jù)格式,例如,byte[]
,String
等輸出到某個地方。
IO流是一種順序讀寫數(shù)據(jù)的模式,它的特點是單向流動。數(shù)據(jù)類似自來水一樣在水管中流動,所以我們把它稱為IO流。

IO流是一種流式的數(shù)據(jù)輸入/輸出模型:
二進制數(shù)據(jù)以
byte
為最小單位在InputStream
/OutputStream
中單向流動;字符數(shù)據(jù)以
char
為最小單位在Reader
/Writer
中單向流動。
Java標準庫的java.io
包提供了同步IO功能:
字節(jié)流接口:
InputStream
/OutputStream
;字符流接口:
Reader
/Writer
。


圣誕節(jié)快樂
io相關(guān)的操作
file對象
在計算機系統(tǒng)中,文件是非常重要的存儲方式。Java的標準庫java.io
提供了File
對象來操作文件和目錄。
要構(gòu)造一個File
對象,需要傳入文件路徑:
package com.zhsj.test;
import java.io.File;
/**
* @author 劉良琪
* @version V1.0
* <p> </p>
* @Package com.zhsj.test
* @date 2021/12/26 18:24
*/
publicclass Day3 {
? ?public static void main(String[] args) {
? ? ? ?File file = new File("D:\\元氣壁紙緩存\\img");
? ? ? ?System.out.println(file);
? ?}
}
注意Windows平臺使用
\
作為路徑分隔符,在Java字符串中需要用\\
表示一個\
。Linux平臺使用/
作為路徑分隔符:
File對象有3種形式表示的路徑,一種是getPath()
,返回構(gòu)造方法傳入的路徑,一種是getAbsolutePath()
,返回絕對路徑,一種是getCanonicalPath
,它和絕對路徑類似,但是返回的是規(guī)范路徑。
還可以獲取目錄的文件和子目錄:list()
/listFiles()
,還有一個文件的crud操作,不會的百度就行
案例:遍歷文件和目錄 (只包含.exe的文件)
package com.zhsj.test;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
/**
* @author 劉良琪
* @version V1.0
* <p> </p>
* @Package com.zhsj.test
* @date 2021/12/26 18:24
*/
publicclass Day3 {
? ?public static void main(String[] args) throws IOException {
? ? ? ?File file = new File("D:\\");
? ? ? ?File[] files = file.listFiles();
? ? ? ?printFiles(files);
? ? ? ?File[] files1 = file.listFiles(new FilenameFilter() {
? ? ? ? ? ?@Override
? ? ? ? ? ?public boolean accept(File dir, String name) {
? ? ? ? ? ? ? ?return name.endsWith(".exe");
? ? ? ? ? ?}
? ? ? ?});
? ? ? ?printFiles(files1);
? ?}
? ?static void printFiles(File[] files) {
? ? ? ?System.out.println("==========");
? ? ? ?if (files != null) {
? ? ? ? ? ?for (File f : files) {
? ? ? ? ? ? ? ?System.out.println(f);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?System.out.println("==========");
? ?}
}
俗話說:萬物皆字節(jié),我這里只說字節(jié)流,字符流大同小異。
InputStream
InputStream:字節(jié)輸入流基類,抽象類是表示字節(jié)輸入流的所有類的超類。
InputStream
就是Java標準庫提供的最基本的輸入流。它位于java.io
這個包里。java.io
包提供了所有同步IO的功能。
要特別注意的一點是,InputStream
并不是一個接口,而是一個抽象類,它是所有輸入流的超類。這個抽象類定義的一個最重要的方法就是int read()
,簽名如下:
public abstract int read() throws IOException;
這個方法會讀取輸入流的下一個字節(jié),并返回字節(jié)表示的int
值(0~255)。如果已讀到末尾,返回-1
表示不能繼續(xù)讀取了。
FileInputStream
是InputStream
的一個子類。顧名思義,FileInputStream
就是從文件流中讀取數(shù)據(jù)。
public void readFile() throws IOException {
? ?// 創(chuàng)建一個FileInputStream對象:
? ?InputStream input = new FileInputStream("src/readme.txt");
? ?for (;;) {
? ? ? ?int n = input.read(); // 反復(fù)調(diào)用read()方法,直到返回-1
? ? ? ?if (n == -1) {
? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?System.out.println(n); // 打印byte的值
? ?}
? ?input.close(); // 關(guān)閉流
}
在計算機中,類似文件、網(wǎng)絡(luò)端口這些資源,都是由操作系統(tǒng)統(tǒng)一管理的。應(yīng)用程序在運行的過程中,如果打開了一個文件進行讀寫,完成后要及時地關(guān)閉,以便讓操作系統(tǒng)把資源釋放掉,否則,應(yīng)用程序占用的資源會越來越多,不但白白占用內(nèi)存,還會影響其他應(yīng)用程序的運行。
InputStream
和OutputStream
都是通過close()
方法來關(guān)閉流。關(guān)閉流就會釋放對應(yīng)的底層資源。
我們還要注意到在讀取或?qū)懭隝O流的過程中,可能會發(fā)生錯誤,例如,文件不存在導(dǎo)致無法讀取,沒有寫權(quán)限導(dǎo)致寫入失敗,等等,這些底層錯誤由Java虛擬機自動封裝成IOException
異常并拋出。因此,所有與IO操作相關(guān)的代碼都必須正確處理IOException
。
緩沖
在讀取流的時候,一次讀取一個字節(jié)并不是最高效的方法。很多流支持一次性讀取多個字節(jié)到緩沖區(qū),對于文件和網(wǎng)絡(luò)流來說,利用緩沖區(qū)一次性讀取多個字節(jié)效率往往要高很多。InputStream
提供了兩個重載方法來支持讀取多個字節(jié):
int read(byte[] b)
:讀取若干字節(jié)并填充到byte[]
數(shù)組,返回讀取的字節(jié)數(shù)int read(byte[] b, int off, int len)
:指定byte[]
數(shù)組的偏移量和最大填充數(shù)
利用上述方法一次讀取多個字節(jié)時,需要先定義一個byte[]
數(shù)組作為緩沖區(qū),read()
方法會盡可能多地讀取字節(jié)到緩沖區(qū), 但不會超過緩沖區(qū)的大小。read()
方法的返回值不再是字節(jié)的int
值,而是返回實際讀取了多少個字節(jié)。如果返回-1
,表示沒有更多的數(shù)據(jù)了。
利用緩沖區(qū)一次讀取多個字節(jié)的代碼如下:
public void readFile() throws IOException {
? ?try (InputStream input = new FileInputStream("src/readme.txt")) {
? ? ? ?// 定義1000個字節(jié)大小的緩沖區(qū):
? ? ? ?byte[] buffer = newbyte[1000];
? ? ? ?int n;
? ? ? ?while ((n = input.read(buffer)) != -1) { // 讀取到緩沖區(qū)
? ? ? ? ? ?System.out.println("read " + n + " bytes.");
? ? ? ?}
? ?}
}
案例:
publicclass FileCount { ?
? /**
? ?* 我們寫一個檢測文件長度的小程序,別看這個程序挺長的,你忽略try catch塊后發(fā)現(xiàn)也就那么幾行而已。
? ?*/
? publicstatic void main(String[] args) { ?
? ? ?//TODO 自動生成的方法存根 ?
? ? ? ? ? ? int count=0; ?//統(tǒng)計文件字節(jié)長度 ?
? ? ?InputStreamstreamReader = null; ? //文件輸入流 ?
? ? ?try{ ?
? ? ? ? ?streamReader=newFileInputStream(new File("D:/David/Java/java 高級進階/files/tiger.jpg")); ?
? ? ? ? ?/*1.new File()里面的文件地址也可以寫成D:\\David\\Java\\java 高級進階\\files\\tiger.jpg,前一個\是用來對后一個
? ? ? ? ? * 進行轉(zhuǎn)換的,F(xiàn)ileInputStream是有緩沖區(qū)的,所以用完之后必須關(guān)閉,否則可能導(dǎo)致內(nèi)存占滿,數(shù)據(jù)丟失。
? ? ? ? ?*/
? ? ? ? ?while(streamReader.read()!=-1) { ?//讀取文件字節(jié),并遞增指針到下一個字節(jié) ?
? ? ? ? ? ? count++; ?
? ? ? ? ?} ?
? ? ? ? ?System.out.println("---長度是:"+count+" 字節(jié)"); ?
? ? ?}catch (final IOException e) { ?
? ? ? ? ?//TODO 自動生成的 catch 塊 ?
? ? ? ? ?e.printStackTrace(); ?
? ? ?}finally{ ?
? ? ? ? ?try{ ?
? ? ? ? ? ? streamReader.close(); ?
? ? ? ? ?}catch (IOException e) { ?
? ? ? ? ? ? //TODO 自動生成的 catch 塊 ?
? ? ? ? ? ? e.printStackTrace(); ?
? ? ? ? ?} ?
? ? ?} ?
? } ?
?
OutputStream
OutputStream:字節(jié)輸出流基類,抽象類是表示輸出字節(jié)流的所有類的超類。
和InputStream
相反,OutputStream
是Java標準庫提供的最基本的輸出流。
和InputStream
類似,OutputStream
也是抽象類,它是所有輸出流的超類。這個抽象類定義的一個最重要的方法就是void write(int b)
常用方法:
? ?// 將 b.length 個字節(jié)從指定的 byte 數(shù)組寫入此輸出流
? ?void write(byte[] b)
? ?// 將指定 byte 數(shù)組中從偏移量 off 開始的 len 個字節(jié)寫入此輸出流
? ?void write(byte[] b, int off, int len)
? ?// 將指定的字節(jié)寫入此輸出流
? ?abstract void write(int b)
? ?// 關(guān)閉此輸出流并釋放與此流有關(guān)的所有系統(tǒng)資源
? ?void close()
? ?// 刷新此輸出流并強制寫出所有緩沖的輸出字節(jié)
? ?void flush()
案例:
publicclass FileCopy { ?
?
?public static void main(String[] args) { ?
? ? // TODO自動生成的方法存根 ?
? ? byte[] buffer=newbyte[512]; ? //一次取出的字節(jié)數(shù)大小,緩沖區(qū)大小 ?
? ? int numberRead=0; ?
? ? FileInputStream input=null; ?
? ? FileOutputStream out =null; ?
? ? try { ?
? ? ? ?input=new FileInputStream("D:/David/Java/java 高級進階/files/tiger.jpg"); ?
? ? ? ?out=new FileOutputStream("D:/David/Java/java 高級進階/files/tiger2.jpg"); //如果文件不存在會自動創(chuàng)建 ?
? ? ? ?
? ? ? ?while ((numberRead=input.read(buffer))!=-1) { ?//numberRead的目的在于防止最后一次讀取的字節(jié)小于buffer長度, ?
? ? ? ? ? out.write(buffer, 0, numberRead); ? ? ? //否則會自動被填充0 ?
? ? ? ?} ?
? ? } catch (final IOException e) { ?
? ? ? ?// TODO自動生成的 catch 塊 ?
? ? ? ?e.printStackTrace(); ?
? ? }finally{ ?
? ? ? ?try { ?
? ? ? ? ? input.close(); ?
? ? ? ? ? out.close(); ?
? ? ? ?} catch (IOException e) { ?
? ? ? ? ? // TODO自動生成的 catch 塊 ?
? ? ? ? ? e.printStackTrace(); ?
? ? ? ?} ?
? ? ? ?
? ? } ?
?}
Filter模式
Java的IO標準庫使用Filter模式為InputStream
和OutputStream
增加功能:
可以把一個
InputStream
和任意個FilterInputStream
組合;可以把一個
OutputStream
和任意個FilterOutputStream
組合。
Filter模式可以在運行期動態(tài)增加功能(又稱Decorator模式)。
操作zip
ZipInputStream
是一種FilterInputStream
,它可以直接讀取zip包的內(nèi)容:
┌───────────────────┐
│ ? ?InputStream ? ?│
└───────────────────┘
? ? ? ? ?▲
? ? ? ? ?│
┌───────────────────┐
│ FilterInputStream │
└───────────────────┘
? ? ? ? ?▲
? ? ? ? ?│
┌───────────────────┐
│InflaterInputStream│
└───────────────────┘
? ? ? ? ?▲
? ? ? ? ?│
┌───────────────────┐
│ ?ZipInputStream ? │
└───────────────────┘
? ? ? ? ?▲
? ? ? ? ?│
┌───────────────────┐
│ ?JarInputStream ? │
└───────────────────┘
另一個JarInputStream
是從ZipInputStream
派生,它增加的主要功能是直接讀取jar文件里面的MANIFEST.MF
文件。因為本質(zhì)上jar包就是zip包,只是額外附加了一些固定的描述文件。
讀取Zip包
我們要創(chuàng)建一個ZipInputStream
,通常是傳入一個FileInputStream
作為數(shù)據(jù)源,然后,循環(huán)調(diào)用getNextEntry()
,直到返回null
,表示zip流結(jié)束。
一個ZipEntry
表示一個壓縮文件或目錄,如果是壓縮文件,我們就用read()
方法不斷讀取,直到返回-1
:
try (ZipInputStream zip = new ZipInputStream(new FileInputStream(...))) {
? ?ZipEntry entry = null;
? ?while ((entry = zip.getNextEntry()) != null) {
? ? ? ?String name = entry.getName();
? ? ? ?if (!entry.isDirectory()) {
? ? ? ? ? ?int n;
? ? ? ? ? ?while ((n = zip.read()) != -1) {
? ? ? ? ? ? ? ?...
? ? ? ? ? ?}
? ? ? ?}
? ?}
}
寫入Zip包
ZipOutputStream
是一種FilterOutputStream
,它可以直接寫入內(nèi)容到zip包。我們要先創(chuàng)建一個ZipOutputStream
,通常是包裝一個FileOutputStream
,然后,每寫入一個文件前,先調(diào)用putNextEntry()
,然后用write()
寫入byte[]
數(shù)據(jù),寫入完畢后調(diào)用closeEntry()
結(jié)束這個文件的打包。
try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(...))) {
? ?File[] files = ...
? ?for (File file : files) {
? ? ? ?zip.putNextEntry(new ZipEntry(file.getName()));
? ? ? ?zip.write(getFileDataAsBytes(file));
? ? ? ?zip.closeEntry();
? ?}
}
上面的代碼沒有考慮文件的目錄結(jié)構(gòu)。如果要實現(xiàn)目錄層次結(jié)構(gòu),new ZipEntry(name)
傳入的name
要用相對路徑。
讀取classpath資源
把資源存儲在classpath中可以避免文件路徑依賴;
Class
對象的getResourceAsStream()
可以從classpath中讀取指定資源;
根據(jù)classpath讀取資源時,需要檢查返回的InputStream
是否為null
。
如果我們把默認的配置放到j(luò)ar包中,再從外部文件系統(tǒng)讀取一個可選的配置文件,就可以做到既有默認的配置文件,又可以讓用戶自己修改配置:
Properties props = new Properties();
props.load(inputStreamFromClassPath("/default.properties"));
props.load(inputStreamFromFile("./conf.properties"));
序列化
序列化是指把一個Java對象變成二進制內(nèi)容,本質(zhì)上就是一個byte[]
數(shù)組。
為什么要把Java對象序列化呢?因為序列化后可以把byte[]
保存到文件中,或者把byte[]
通過網(wǎng)絡(luò)傳輸?shù)竭h程,這樣,就相當于把Java對象存儲到文件或者通過網(wǎng)絡(luò)傳輸出去了。
有序列化,就有反序列化,即把一個二進制內(nèi)容(也就是byte[]
數(shù)組)變回Java對象。有了反序列化,保存到文件中的byte[]
數(shù)組又可以“變回”Java對象,或者從網(wǎng)絡(luò)上讀取byte[]
并把它“變回”Java對象。
把一個Java對象變?yōu)?code>byte[]數(shù)組,需要使用ObjectOutputStream
。它負責把一個Java對象寫入一個字節(jié)流:
publicclass Main {
? ?public static void main(String[] args) throws IOException {
? ? ? ?ByteArrayOutputStream buffer = new ByteArrayOutputStream();
? ? ? ?try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
? ? ? ? ? ?// 寫入int:
? ? ? ? ? ?output.writeInt(12345);
? ? ? ? ? ?// 寫入String:
? ? ? ? ? ?output.writeUTF("Hello");
? ? ? ? ? ?// 寫入Object:
? ? ? ? ? ?output.writeObject(Double.valueOf(123.456));
? ? ? ?}
? ? ? ?System.out.println(Arrays.toString(buffer.toByteArray()));
? ?}
}
ObjectOutputStream
既可以寫入基本類型,如int
,boolean
,也可以寫入String
(以UTF-8編碼),還可以寫入實現(xiàn)了Serializable
接口的Object
。
因為寫入Object
時需要大量的類型信息,所以寫入的內(nèi)容很大。
反序列化
和ObjectOutputStream
相反,ObjectInputStream
負責從一個字節(jié)流讀取Java對象:
try (ObjectInputStream input = new ObjectInputStream(...)) {
? ?int n = input.readInt();
? ?String s = input.readUTF();
? ?Double d = (Double) input.readObject();
}
除了能讀取基本類型和String
類型外,調(diào)用readObject()
可以直接返回一個Object
對象。要把它變成一個特定類型,必須強制轉(zhuǎn)型。
readObject()
可能拋出的異常有:
ClassNotFoundException
:沒有找到對應(yīng)的Class;InvalidClassException
:Class不匹配。
對于ClassNotFoundException
,這種情況常見于一臺電腦上的Java程序把一個Java對象,例如,Person
對象序列化以后,通過網(wǎng)絡(luò)傳給另一臺電腦上的另一個Java程序,但是這臺電腦的Java程序并沒有定義Person
類,所以無法反序列化。
對于InvalidClassException
,這種情況常見于序列化的Person
對象定義了一個int
類型的age
字段,但是反序列化時,Person
類定義的age
字段被改成了long
類型,所以導(dǎo)致class不兼容。
為了避免這種class定義變動導(dǎo)致的不兼容,Java的序列化允許class定義一個特殊的serialVersionUID
靜態(tài)變量,用于標識Java類的序列化“版本”,通常可以由IDE自動生成。如果增加或修改了字段,可以改變serialVersionUID
的值,這樣就能自動阻止不匹配的class版本:
publicclass Person implements Serializable {
? ?privatestaticfinallong serialVersionUID = 2709425275741743919L;
}
要特別注意反序列化的幾個重要特點:
反序列化時,由JVM直接構(gòu)造出Java對象,不調(diào)用構(gòu)造方法,構(gòu)造方法內(nèi)部的代碼,在反序列化時根本不可能執(zhí)行。
PrintStream和PrintWriter
PrintStream
是一種FilterOutputStream
,它在OutputStream
的接口上,額外提供了一些寫入各種數(shù)據(jù)類型的方法:
寫入
int
:print(int)
寫入
boolean
:print(boolean)
寫入
String
:print(String)
寫入
Object
:print(Object)
,實際上相當于print(object.toString())
...
以及對應(yīng)的一組println()
方法,它會自動加上換行符。
我們經(jīng)常使用的System.out.println()
實際上就是使用PrintStream
打印各種數(shù)據(jù)其中,System.out
是系統(tǒng)默認提供的PrintStream
,表示標準輸出:
System.out.print(12345); // 輸出12345
System.out.print(new Object()); // 輸出類似java.lang.Object@3c7a835a
System.out.println("Hello"); // 輸出Hello并換行
System.err
是系統(tǒng)默認提供的標準錯誤輸出。
PrintStream
和OutputStream
相比,除了添加了一組print()
/println()
方法,可以打印各種數(shù)據(jù)類型,比較方便外,它還有一個額外的優(yōu)點,就是不會拋出IOException
,這樣我們在編寫代碼的時候,就不必捕獲IOException
。
PrintWriter
PrintStream
最終輸出的總是byte數(shù)據(jù),而PrintWriter
則是擴展了Writer
接口,它的print()
/println()
方法最終輸出的是char
數(shù)據(jù)。兩者的使用方法幾乎是一模一樣的:
publicclass Main {
? ?public static void main(String[] args) ? ? {
? ? ? ?StringWriter buffer = new StringWriter();
? ? ? ?try (PrintWriter pw = new PrintWriter(buffer)) {
? ? ? ? ? ?pw.println("Hello");
? ? ? ? ? ?pw.println(12345);
? ? ? ? ? ?pw.println(true);
? ? ? ?}
? ? ? ?System.out.println(buffer.toString());
? ?}
}
字節(jié)緩沖流
BufferedInputStream:字節(jié)緩沖輸入流,提高了讀取效率。
? ? 構(gòu)造方法:
? ? // 創(chuàng)建一個 BufferedInputStream并保存其參數(shù),即輸入流in,以便將來使用。
? ? BufferedInputStream(InputStream in)
? ? // 創(chuàng)建具有指定緩沖區(qū)大小的 BufferedInputStream并保存其參數(shù),即輸入流in以便將來使用
? ? BufferedInputStream(InputStream in, int size)
? ? ? ?InputStream in = new FileInputStream("test.txt");
? ? ? ?// 字節(jié)緩存流
? ? ? ?BufferedInputStream bis = new BufferedInputStream(in);
? ? ? ?byte[] bs = newbyte[20];
? ? ? ?int len = 0;
? ? ? ?while ((len = bis.read(bs)) != -1) {
? ? ? ? ? ?System.out.print(new String(bs, 0, len));
? ? ? ? ? ?// ABCD
? ? ? ? ? ?// hello
? ? ? ?}
? ? ? ?// 關(guān)閉流
? ? ? ?bis.close();
BufferedOutputStream:字節(jié)緩沖輸出流,提高了寫出效率。
? 構(gòu)造方法:
? ? // 創(chuàng)建一個新的緩沖輸出流,以將數(shù)據(jù)寫入指定的底層輸出流
? ? BufferedOutputStream(OutputStream out)
? ? // 創(chuàng)建一個新的緩沖輸出流,以將具有指定緩沖區(qū)大小的數(shù)據(jù)寫入指定的底層輸出流
? ? BufferedOutputStream(OutputStream out, int size)
? ? 常用方法:
? ? // 將指定 byte 數(shù)組中從偏移量 off 開始的 len 個字節(jié)寫入此緩沖的輸出流
? ? void write(byte[] b, int off, int len)
? ? // 將指定的字節(jié)寫入此緩沖的輸出流
? ? void write(int b)
? ? // 刷新此緩沖的輸出流
? ? void flush()
? ? ? ?BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true));
? ? ? ?// 輸出換行符
? ? ? ?bos.write("\r\n".getBytes());
? ? ? ?// 輸出內(nèi)容
? ? ? ?bos.write("Hello Android".getBytes());
? ? ? ?// 刷新此緩沖的輸出流
? ? ? ?bos.flush();
? ? ? ?// 關(guān)閉流

圣誕節(jié)快樂
總結(jié):
io流是JavaSE很重要的內(nèi)容,好好學(xué)掌握這個技能,對你理解底層實現(xiàn)也很有幫助

img
記住這張圖片,就OK了
我們開發(fā)一般都是用的BufferedInputStream與BufferedOutputStream來進行oi操作,這樣可以提高效率
通俗的理解io:Java中的IO流是輸入輸出流。至于理解,可以將輸入和輸出兩個端點看作是兩個工廠,工廠之間需要互相運輸貨物,而流則是兩工廠之間的公路,沒有公路就不能互相運輸,至于字符,字節(jié)和二進制則可以看作是運輸?shù)姆绞胶蛦挝淮笮。热缯f把二進制理解成三輪車,那么字節(jié)就是小卡車,而字符則是集卡之類的。
希望大家還是好好的學(xué)習(xí)下io流,在工作中雖然都是用的框架但是對于這些基本的技術(shù)還是要掌握扎實,俗話說:基本不好,地動山搖。


