Java中IO流解析及代碼實(shí)例詳解
1、IO流
1.流和流的分類
什么是IO流?
I:Input (輸入)
O: Ouput(輸出)
IO流的分類?
有多種分類方式:
- 一種方式是按照流的方向進(jìn)行分類:
以內(nèi)存作為參照物
往內(nèi)存中去,叫做輸入(Input)?;蛘呓凶鲎x(Read) .
從內(nèi)存中出來,叫做輸出(output)?;蛘呓凶鰧?write) .
- 另一種方式是按照讀取藪據(jù)方式不同進(jìn)行分類:
- 有的流是按照字節(jié)的方式讀取數(shù)據(jù),一次讀取1個(gè)字節(jié)byte,等同于一次讀取8個(gè)二進(jìn)制。
- 這種流是萬能的,什么類型的文件都可以讀取。包括:文本文件,圖片,聲音文件,視頻……
- 有的流是按照字符的方式讀取數(shù)據(jù)的,一次讀取一個(gè)字符,這種流是為了方便讀取普通文本文件而存在的,這種流不能讀取:圖片、聲音、視頻等文件。只能讀取純文本文件,連word文件都無法讀取
總結(jié):流的分類
輸入流、輸出流、字節(jié)流、字符流
Java IO流的四大家族
| java.io.InputStream | 字節(jié)輸入流 |
|---|---|
| java.io.OutputStream | 字節(jié)輸出流 |
| java.io.Reader | 字符輸入流 |
| java.io.Writer | 字符輸出流 |
注意:
- 四個(gè)都是抽象類。
- 所有流都是實(shí)現(xiàn)了java.io.Closeable接口,都是可關(guān)閉的
- 流是一個(gè)管道,是內(nèi)存和硬盤之間的通道。用完后一定要關(guān)閉,不然會占用很多資源。
- 所有的輸出流都實(shí)現(xiàn)了java.io.Flushable接口,都是可刷新的
- 最終輸出后,一定要記得調(diào)用flush()方法。目的是將管道中剩余未輸出的數(shù)據(jù)強(qiáng)行輸出完(清空管道)
- 如果沒有flash(),可能會導(dǎo)致丟失數(shù)據(jù)
- 在java中只要”類名”以strean結(jié)尾的都是字節(jié)流。以"Reader/writer"結(jié)尾的都是字符流
java.io包下需要掌握的流有16個(gè):
文件專屬:
java . io.FileInputstream
java.io.FileOutputstream
java.io.FileReader
java.io.Filewriter
轉(zhuǎn)換流:(將字節(jié)流轉(zhuǎn)換成字符流)
java . io . InputstreamReader
java . io. outputstreamWriter
緩沖流專屬:
java. io. BufferedReader
java.io.BufferedWriter
java.io. BufferedInputstream
java . io.Bufferedoutputstrean
數(shù)據(jù)流專屬:
java . io . DataInputstream
java .io. Dataoutputstrean
標(biāo)準(zhǔn)輸出流:
java . io . Printwriter
java . io . Printstream
對象專屬流:
java.io.ObjectInputstream
java.io.ObjectOutputstream
一下子看到這么多流。不用怕,只需要掌握一組的使用方法就可以了,使用其他的都是一樣,一通百通。
下面以萬能的字節(jié)流(FileInputStream、FileOutputStream)來舉例說明。
2.如何使用流
1、輸入流(讀文件):FileInputStream
方法一
使用FileInputStream的read()
步驟:
1、 創(chuàng)建流對象
new FileInputStream(參數(shù))
參數(shù)可以是一個(gè)File類、String字符串表示的文件路徑
2、使用流的方法對文件進(jìn)行讀
輸入流調(diào)用read()方法,每次從流中讀取一個(gè)數(shù)據(jù)字節(jié)。返回值是讀到的字節(jié)的ASCII值
讀取一個(gè)后,他會指向下一個(gè)字符,如果到達(dá)末尾。返回-1,可以用while()來實(shí)現(xiàn)。
3、關(guān)閉流
調(diào)用close()方法
實(shí)例:
package com.io.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestFileInputStream {
//定義一個(gè)流對象
private static FileInputStream fis;
public static void main(String[] args) {
try {
//1、 創(chuàng)建流對象.參數(shù)可以是一個(gè)File類、String字符串表示的文件路徑
fis = new FileInputStream("E:\\aaa.txt");//在e盤下有一個(gè)aaa.txt的文件夾,內(nèi)容為(abcdefg)
//2、使用流的方法對文件進(jìn)行讀
while (true) {
int read = fis.read();//注意這里返回的是int類型,代表是字符的ASCII值
if (read==-1) {//讀到最后會返回-1,退出條件
break;
}
System.out.println(read);
}
} catch (FileNotFoundException e) {//異常細(xì)粒化,不同異常可以選擇不同的處理方式
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//3、關(guān)閉流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*輸出
97
98
99
100
101
102
103
*/
int read()
該方法因?yàn)槊看味际侵蛔x取一個(gè)字節(jié),這樣內(nèi)存和硬盤交互太頻繁 ,開銷大且效率不高。一般不使用,但是要了解,這是基礎(chǔ)。
方法二
一般使用這種方法
使用read(byte[] b)
一次讀取最多 b.length 個(gè)字節(jié),減少內(nèi)存和硬盤交互,提高執(zhí)行效率
該方法返回的是讀到的字節(jié)的數(shù)量
使用步驟:和前面只有第二步有些差別
byte[] b= new byte[3];
int readNum = fis.read(b);
解析
- 新建一個(gè)byte[]數(shù)組b,代表我們一次需要讀多少個(gè)字符。讀完這么多字符后,下次一讀是從當(dāng)前讀到的位置開始,和上面一樣
- 將byte數(shù)組b傳入read()方法中,返回一個(gè)我們byte數(shù)組的大小,此時(shí)readNum值為3
那么我們讀出來的數(shù)據(jù)在哪里呢。自然是存放在byte數(shù)組里。我們打印b數(shù)組看,發(fā)現(xiàn)b數(shù)組里存放的讀到的ascii值
細(xì)節(jié):
因?yàn)閿?shù)組的長度是我們設(shè)定的。如果文件讀到最后,不一定剛好符合我們設(shè)定的長度,最后一組的長度只有小于或等于數(shù)組的長度。如果小于它會返回剩余的字符的數(shù)量,讀不到返回-1,我們可以利用這個(gè)作為循環(huán)退出的條件。
另外一個(gè),因?yàn)樗拈L度小于b數(shù)組,那么它的值也是無法填滿b數(shù)組的,此時(shí),它只更新b數(shù)組中前面的n個(gè)讀到的值,b數(shù)組后面的是上一個(gè)讀取時(shí)讀取到的值。
實(shí)例:
仍然讀取aaa.txt文件,內(nèi)容為(abcdefg)
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class TestFileInputStream2 {
private static FileInputStream fis;
public static void main(String[] args) {
try {
fis = new FileInputStream("IO流\\aaa.txt");
//準(zhǔn)備一個(gè)byte數(shù)組
byte[] b= new byte[3];
int readNum = 0;
while (true) {
//先進(jìn)行讀操作。
readNum=fis.read(b);
//判斷
if (readNum == -1) {
break;
}
//將字符數(shù)組轉(zhuǎn)為String,后面兩個(gè)參數(shù)為起始位置,和長度
String str = new String(b, 0, readNum);
System.out.println(str);
}
/*輸出
abc
def
g
*/
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//關(guān)閉流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
其他常用的方法
int available()
返回流中還有多少個(gè)字符沒有讀。(相當(dāng)于獲得文件讀到的位置到末尾字符的個(gè)數(shù),如果沒開始讀,返回文件中總字符的數(shù)量)
使用這個(gè)可以對一些比較小的(字符長度)文件一次讀完,如果不超過byte數(shù)組的范圍的話
public class TestFileInputStream3 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("IO流\\aaa.txt");
byte[] bytes = new byte[fis.available()];//創(chuàng)建一個(gè)和文件字符數(shù)量一樣大的byte數(shù)組,文件不能太大。
fis.read(bytes);
System.out.println(new String(bytes));//b轉(zhuǎn)為字符串,輸出abcdefg
}
}
skip(long n)
顧名思義:從輸入流中跳過并丟棄 n 個(gè)字節(jié)的數(shù)據(jù)。
2、輸出流(寫文件):FileOutputStream
和輸入的流程差不多,過程也基本相同
write(byte[] b)
注意:
- byte的范圍是-128~127,超過會報(bào)錯(cuò)
- 寫完之后,一定要刷新
- 如果當(dāng)前路徑下文件已存在,會將原文件清空,再寫入(慎用)。
- 如果它是一個(gè)目錄,而不是一個(gè)常規(guī)文件,會報(bào)錯(cuò)。
- 或者該文件不存在,但無法創(chuàng)建它,會報(bào)錯(cuò)。
- 如果當(dāng)前路徑下文件不存在,會新建文件。
package com.io.stream.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author cyh
* @Date 2021/8/7 17:21
*/
public class Test1 {
private static FileOutputStream fos;
public static void main(String[] args) {
try {
//新建一個(gè)輸出流,參數(shù)是輸出的路徑,最后的為文件名。
fos = new FileOutputStream("IO流\\bbb.txt");
//新建一個(gè)byte數(shù)組,里面對應(yīng)的是abcd的ascii值
byte[] bytes = {97, 98, 99, 100,101,127}; //注意byte的范圍是-128~127
//輸出流調(diào)用write方法寫入byte數(shù)組,以文件形式保存到上面的路徑
fos.write(bytes);
//寫完之后,一定要刷新
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
追加寫文件
想要追加寫文件,則需要在新建流的的時(shí)候,加一個(gè)參數(shù)true。
表示將字節(jié)寫入文件末尾處,而不是寫入文件開始處
//新建一個(gè)輸出流,參數(shù)是輸出的路徑,最后的為文件名。增加true表示開啟追加寫
fos = new FileOutputStream("IO流\\bbb.txt",true);
注意:和上面一樣,不一樣的點(diǎn)只是追加寫。
write(byte[] b, int off, int len)
將指定 byte 數(shù)組中從偏移量 off 開始的 len 個(gè)字節(jié)寫入此文件輸出流.
意思就是,寫入的內(nèi)容為off~len。如果off是0,len是數(shù)組長度,那就全部寫入;如果off是數(shù)組長度-1,len是數(shù)組長度,那就只寫入了一個(gè)字符
3.文件的拷貝
- 使用FileInputStream+FileOutputStream即可完成文件的拷貝
- 拷貝的過程應(yīng)該是一邊讀、一邊寫
- 使用上面的字節(jié)流拷貝文件的時(shí)候,文件類型隨意,是萬能的。什么文件都可以拷貝
實(shí)例
package com.io.stream.copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author cyh
* @Date 2021/8/7 17:53
*/
public class TestCopy {
private static FileInputStream fis;
private static FileOutputStream fos;
public static void main(String[] args) {
try {
//創(chuàng)建一個(gè)輸入流
fis = new FileInputStream("D:\\edgeDownload\\VSCodeUserSetup-x64-1.55.0.exe");
//創(chuàng)建一個(gè)輸出流
fos = new FileOutputStream("C:\\Users\\PC\\Desktop\\copy\\b\\VSCodeUserSetup-x64-1.55.0.exe");
//核心,一邊讀、一邊寫
byte[] bytes = new byte[1024*1024];//1MB,一次最多拷貝1MB
int readNum=0;
while((readNum=fis.read(bytes))!=-1){
fos.write(bytes,0,readNum);//將bytes全部寫入
}
//刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//資源要分開釋放,不然一個(gè)出錯(cuò)會導(dǎo)致另一個(gè)無法釋放
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
騰訊云部署javaWeb項(xiàng)目的實(shí)現(xiàn)步驟
本文主要介紹了騰訊云部署javaWeb項(xiàng)目的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
Spring使用RestTemplate和Junit單元測試的注意事項(xiàng)
這篇文章主要介紹了Spring使用RestTemplate和Junit單元測試的注意事項(xiàng),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Mybatis?selectKey 如何返回新增用戶的id值
這篇文章主要介紹了Mybatis?selectKey 如何返回新增用戶的id值,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
JDBC查詢Map轉(zhuǎn)對象實(shí)現(xiàn)過程詳解
這篇文章主要介紹了JDBC查詢Map轉(zhuǎn)對象實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
AsyncHttpClient exception異常源碼流程解析
這篇文章主要為大家介紹了AsyncHttpClient的exception源碼流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

