目錄
??IO流理論概述
1.什么是IO
2.IO流的分類
3.流的四大家族
4.需要掌握的十六個(gè)流
??字節(jié)輸入流FileInputStream
1.FileInputStream初步理解
2.FileInputStream常用方法
??字節(jié)輸出流FileOutputStream
??任意文件拷貝
??FileReader && FileWriter && 普通文件拷貝
1.字符輸入流FileReader
2.字符輸出流FileWriter
3.普通文件拷貝
??IO流理論概述
1.什么是IO
??什么是IO?IO有什么用?
????????I代表Input,把硬盤里的文件放到內(nèi)存里,就叫做輸入(Input),也就是讀
? ? ? ??O代表Output,把內(nèi)存里的文件放到硬盤里,就叫做輸出(Output),也就是寫
??通過IO流可以完成文件的讀和寫!并且讀和寫都是以內(nèi)存為參照的!
2.IO流的分類
??IO流的分類?有多種分類方式:
? ? ??第一種方式是按照流的方向進(jìn)行分類(以內(nèi)存作為參照物):?? ??? ??? ?
? ? (1)往內(nèi)存中去,叫做輸入(Input)?;蛘呓凶鲎x(Read)。
? ? (2)從內(nèi)存中出來,叫做輸出(Output)?;蛘呓凶鰧?Write)。
? ? ??另一種方式是按照讀取數(shù)據(jù)方式不同進(jìn)行分類:?
? ? (1)有的流是按照字節(jié)的方式讀取數(shù)據(jù),一次讀取1個(gè)字節(jié)byte,等同于一次讀取8個(gè)二進(jìn)制位。這種流是萬能的,什么類型的文件都可以讀取。包括:文本文件,圖片,聲音文件,視頻文件等....
? ? ?例:假設(shè)文件file1.txt,采用字節(jié)流的話是這樣讀的:
?? ????????? a中國bc張三fe
?? ????????? 第一次讀:一個(gè)字節(jié),正好讀到'a'
?? ? ????????第二次讀:一個(gè)字節(jié),正好讀到'中'字符的一半,一個(gè)漢字是占用兩個(gè)字節(jié)的。
?? ? ????????第三次讀:一個(gè)字節(jié),正好讀到'中'字符的另外一半。
? ?(2)有的流是按照字符的方式讀取數(shù)據(jù),一次讀取一個(gè)字符,這種流是為了方便讀取
? ?普通文本文件而存在的,這種流不能讀取:圖片、聲音、視頻等文件。只能讀取純文本文件,連word文件都無法讀取。
? ?例:假設(shè)文件file1.txt,采用字符流的話是這樣讀的:
? ? ? ? ? ?a中國bc張三fe
? ? ? ? ? ?第一次讀:'a'字符('a'字符在windows系統(tǒng)中占用1個(gè)字節(jié)。)
? ? ? ? ? ?第二次讀:'中'字符('中'字符在windows系統(tǒng)中占用2個(gè)字節(jié)。)
? ??綜上所述:流的分類
? ? ? ? (1)輸入流、輸出流(按照流的方向)
? ? ? ? (2)字節(jié)流、字符流(按照字節(jié)的讀取方式)
3.流的四大家族
??Java中的IO流都已經(jīng)寫好了,我們最主要還是掌握,在java中已經(jīng)提供了哪些流,每個(gè)流的特點(diǎn)是什么,每個(gè)流對(duì)象上的常用方法有哪些?
??????java中所有的流都是在:java.io.*;???????java中主要還是研究:怎么new流對(duì)象?調(diào)用流對(duì)象的哪個(gè)方法是讀?哪個(gè)方法是寫?
??java IO流這塊有四大家族:
?? ???四大家族的四個(gè)首領(lǐng):(都是抽象類)
?? ??? ?java.io.InputStream ?????????????字節(jié)輸入流(讀)
?? ??? ?java.io.OutputStream? ? ? ?字節(jié)輸出流(寫)?? ??? ?java.io.Reader?? ??? ???????????????字符輸入流(讀)
?? ??? ?java.io.Writer?? ???? ? ? ? ? ? ? 字符輸出流(寫)?? ??所有的流都實(shí)現(xiàn)了:
? ? ? ? ? ?(1)java.io.Closeable接口,都是可關(guān)閉的,都有close()方法。
? ? ? ? ? ?(2) 流,畢竟是一個(gè)管道,這個(gè)是內(nèi)存和硬盤之間的通道,用完之后一定要關(guān)閉,
? ? ? ? ? ? ?不然會(huì)耗費(fèi)(占用)很多資源。養(yǎng)成好習(xí)慣,用完流一定要關(guān)閉。?? ??所有的輸出流都實(shí)現(xiàn)了:
? ? ? ? ? ?(1)?java.io.Flushable接口,都是可刷新的,都有flush()方法。
? ? ? ? ? ?(2)養(yǎng)成一個(gè)好習(xí)慣,輸出流在最終輸出之后,一定要記得flush()刷新一下,
? ? ? ? ? ? ?這個(gè)刷新表示將通道/管道當(dāng)中剩余未輸出的數(shù)據(jù)強(qiáng)行輸出完(清空管道),
? ? ? ? ? ?(3)注意:??刷新的作用就是清空管道;如果沒有flush()可能會(huì)導(dǎo)致丟失數(shù)據(jù)。
??注意:在java中只要“類名”以Stream結(jié)尾的都是字節(jié)流。????????????????以“Reader/Writer”結(jié)尾的都是字符流。
4.需要掌握的十六個(gè)流
??java.io包下需要掌握的流有16個(gè):
???文件專屬:
?? ??? ?java.io.FileInputStream(掌握)
?? ??? ?java.io.FileOutputStream(掌握)
?? ??? ?java.io.FileReader
?? ??? ?java.io.FileWriter???緩沖流專屬:
????????java.io.BufferedInputStream
?? ??? ?java.io.BufferedOutputStream
?? ??? ?java.io.BufferedReader
?? ??? ?java.io.BufferedWriter???轉(zhuǎn)換流:(將字節(jié)流轉(zhuǎn)換成字符流)
?? ??? ?java.io.InputStreamReader
?? ??? ?java.io.OutputStreamWriter???數(shù)據(jù)流專屬:
?? ??? ?java.io.DataInputStream
?? ??? ?java.io.DataOutputStream???標(biāo)準(zhǔn)輸出流:
????????java.io.PrintStream(掌握)
?? ??? ?java.io.PrintWriter???對(duì)象專屬流:
?? ??? java.io.ObjectInputStream(掌握)
?? ??? java.io.ObjectOutputStream(掌握)
??字節(jié)輸入流FileInputStream
1.FileInputStream初步理解
??java.io.FileInputStream:
? ? 1、字節(jié)輸入流,萬能的,任何類型的文件都可以采用這個(gè)流來讀。
? ? 2、字節(jié)的方式,完成輸入的操作,完成讀的操作(硬盤---> 內(nèi)存)? ? 3、調(diào)用read()方法進(jìn)行讀,返回的是int類型(字符對(duì)應(yīng)的ASCII碼);沒有元素的話,返回的是-1
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) {
// 創(chuàng)建文件字節(jié)輸入流對(duì)象
// 文件路徑://C:\Java學(xué)習(xí)\temp.txt
//(里面存的是abc,IDEA會(huì)自動(dòng)把\編程\\,因?yàn)閖ava中\(zhòng)表示轉(zhuǎn)義)
// FileInputStream會(huì)拋出異常,父類是Exception,屬于編譯時(shí)異常,需要處理
FileInputStream fis = null; //寫到外面,主要是為了finally里面能夠調(diào)用
try { //C:/Java學(xué)習(xí)/temp.txt,路徑寫成這樣也是可以的
fis = new FileInputStream("C:\\Java學(xué)習(xí)\\temp.txt");
//1、讀文件,從此輸入流中讀取一個(gè)字節(jié)
int readDate = fis.read();
System.out.println(readDate); //97
readDate = fis.read();
System.out.println(readDate); //98
readDate = fis.read();
System.out.println(readDate); //99
readDate = fis.read();
System.out.println(readDate); //-1;最終沒數(shù)據(jù)了,就返回-1
//2、循環(huán)讀
while(true){
int readDate1 = fis.read();
if(readDate1 == -1){ // 沒有數(shù)據(jù)返回的是-1
break;
}
System.out.println(readDate1);
}
//3、優(yōu)化while
int readDate1 = 0;
while((readDate1 = fis.read()) != -1){
System.out.println(readDate1);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) { //read時(shí)候,補(bǔ)充的異常處理
e.printStackTrace();
} finally {
// 加上finally關(guān)鍵字,無論最終有沒有異常,都需要關(guān)閉這個(gè)流
// 在finally語句塊當(dāng)中確保流一定關(guān)閉
if (fis != null) { //生成這個(gè)的快捷鍵ifn
// 關(guān)閉流的前提,流不是null;是空沒必要關(guān)閉
try {
fis.close(); //有異常,try...catch
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
??分析上面這個(gè)程序的缺點(diǎn):
(1)一次讀取一個(gè)字節(jié)byte,這樣內(nèi)存和硬盤交互太頻繁,基本上時(shí)間/資源都耗費(fèi)在交互上面了。所以能不能一次讀取多個(gè)字節(jié)呢?答案是可以的。(2)int read(byte[] b);?一次最多讀取 b.length 個(gè)字節(jié)。
? ? 減少硬盤和內(nèi)存的交互,提高程序的執(zhí)行效率;往byte[]數(shù)組當(dāng)中讀。(3)這里我們不在使用絕對(duì)路徑,而是相對(duì)路徑;那么IDEA默認(rèn)的路徑是什么呢?
工程Project的根就是IDEA的默認(rèn)當(dāng)前路徑;
注意:對(duì)于一個(gè)一個(gè)字節(jié)讀取,調(diào)用read()方法返回的是字符對(duì)應(yīng)的ASCII值;對(duì)于一次讀取一個(gè)byte數(shù)組,調(diào)用read()方法返回的是一次讀取的數(shù)據(jù)個(gè)數(shù)
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest02 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 我們寫成相對(duì)路徑方式,在這里要先理解在IDEA默認(rèn)的當(dāng)前路徑是哪里?
// 工程Project的根就是IDEA的默認(rèn)當(dāng)前路徑;例如我的:C:\Users\86177\IdeaProjects\JavaSe1
//fis = new FileInputStream("tempfile.txt"); //這是在工程下面的tempfile.txt
// 如果是day06模塊下的src包下有一個(gè)tempfile.txt,怎么調(diào)用呢?
fis = new FileInputStream("day06/src/tempfile.txt"); //存放的是abcdef
// 開始讀,采用byte數(shù)組,一次讀取多個(gè)字節(jié)。最多讀取“數(shù)組.length”個(gè)字節(jié)。
byte[] bytes = new byte[4]; 準(zhǔn)備一個(gè)4個(gè)長度的byte數(shù)組,一次最多讀取4個(gè)字節(jié)
// 1、普通打印
int readCount = fis.read(bytes); // 返回的是當(dāng)前的讀取到的字節(jié)數(shù)量(不是字節(jié)本身)
System.out.println(readCount); // 4;第一次讀到了4個(gè)字節(jié)
//System.out.println(new String(bytes)); //abcd,將字符數(shù)組全部轉(zhuǎn)換成字符串
// 實(shí)際上應(yīng)該讀到多少個(gè),就轉(zhuǎn)換多少個(gè)
System.out.println(new String(bytes,0,readCount)); // abcd
readCount = fis.read(bytes);
System.out.println(readCount); // 2;第二次只能讀取到2個(gè)字節(jié)
//System.out.println(new String(bytes)); //efcd,將字符數(shù)組全部轉(zhuǎn)換成字符串,這里就出了問題
System.out.println(new String(bytes,0,readCount)); //ef
readCount = fis.read(bytes);
System.out.println(readCount); //1個(gè)字節(jié)都沒有讀取到返回-1
//2、 寫成循環(huán)
while(true){
int readCount = fis.read(bytes);
if(readCount == -1){
break;
}
System.out.print(new String(bytes,0,readCount)); // abcdef
}
//3、 代碼優(yōu)化
int readCount = 0;
while((readCount = fis.read(bytes)) != -1){
// 將讀取到的將字符數(shù)組全部轉(zhuǎn)換成字符串
System.out.print(new String(bytes,0,readCount)); // abcdef
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.FileInputStream常用方法
??FileInputStream類的其它常用方法:
?int available():返回流當(dāng)中剩余的沒有讀到的字節(jié)數(shù)量
?long skip(long n):跳過幾個(gè)字節(jié)不讀
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest03 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("tempfile.txt"); // 存的abcdef
// 先讀一個(gè)字節(jié)
int readByte = fis.read();
System.out.println(readByte); // 97
//1、available方法,還剩下多少字節(jié)
System.out.println(fis.available()); // 5,還剩下5個(gè)字節(jié)
// available方法有什么用?
// 我們知道當(dāng)前有的字節(jié)數(shù),就不用使用循環(huán)了,直接指定當(dāng)前長度就行
// 這種方式不太適合太大的文件,因?yàn)閎yte[]數(shù)組不能太大。
byte[] bytes = new byte[fis.available()]; //不需要循環(huán),直接讀一次就行
int readCount = fis.read(bytes);
System.out.println(new String(bytes,0,readCount));
// 2、skip方法,跳過幾個(gè)字節(jié)
fis = new FileInputStream("tempfile.txt");
// 跳過3個(gè)字節(jié)
fis.skip(3);
System.out.println(fis.read()); //100(d)
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
??字節(jié)輸出流FileOutputStream
??文件字節(jié)輸出流,從內(nèi)存到硬盤,負(fù)責(zé)寫;怎么寫呢?
??如果當(dāng)前文件不存在,會(huì)自動(dòng)創(chuàng)建!
??如果當(dāng)前文件已經(jīng)存在,會(huì)把原來文件的內(nèi)容進(jìn)行清空覆蓋!如果不想清空原有的數(shù)據(jù),需要多傳一個(gè)參數(shù)true
??調(diào)用write()方法進(jìn)行寫,一般write后面的參數(shù)直接跟的是byte數(shù)組;
??如果是字符串,字符串轉(zhuǎn)成字節(jié)數(shù)組需要用getBytes()方法,把字符串轉(zhuǎn)換成byte數(shù)組;
?????而把byte數(shù)組轉(zhuǎn)成字符串用的是new String(byte數(shù)組)???????
?數(shù)據(jù)寫完后,一定要flush()刷新一下!
package com.bjpowernode.java.io;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//1、 myfile文件如果不存在的時(shí)候會(huì)自動(dòng)新建!
// 這種方式謹(jǐn)慎使用,會(huì)先將原文件清空,然后重新寫入。
fos = new FileOutputStream("myfile");
//2、以追加的方式在文件末尾寫入。不會(huì)清空原文件內(nèi)容。
fos = new FileOutputStream("myfile",true);
//3、開始寫,寫到數(shù)組里
byte[] bytes = {97,98,99,100};
fos.write(bytes); // 寫進(jìn)去abcd
//4、將byte數(shù)組的一部分寫出
fos.write(bytes,0,2); //寫進(jìn)去ab
//5、寫一個(gè)字符串,然后把字符串轉(zhuǎn)換成byte數(shù)組
String s = "我是一個(gè)中國人!";
//將一個(gè)字符串轉(zhuǎn)換成byte數(shù)組
byte[] byts = s.getBytes();
fos.write(byts); //寫進(jìn)去“我是一個(gè)中國人!”
//6、寫完之后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
??任意文件拷貝
有了上面的輸入流和輸出流學(xué)習(xí),我們是不是就可以嘗試完成一個(gè)文件拷貝的功能,無非就是讀、寫的結(jié)合應(yīng)用,下面我們先看一下原理圖:
?使用FileInputStream + FileOutputStream完成文件的拷貝;拷貝的過程應(yīng)該是一邊讀,一邊寫。
?使用字節(jié)流拷貝文件的時(shí)候,文件類型隨意,什么樣的文件都能拷貝。
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTest {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1、 創(chuàng)建一個(gè)輸入流對(duì)象
fis = new FileInputStream("C:\\Java學(xué)習(xí)\\javaSE學(xué)習(xí)\\2.JavaSE初學(xué)習(xí)筆記\\2.第一章:Java環(huán)境搭建\\HelloWorld.java");
//2、 創(chuàng)建一個(gè)輸出流對(duì)象
fos = new FileOutputStream("C:\\Java學(xué)習(xí)\\HelloWorld.java");
//3、 最核心的部分:一邊讀,一邊寫
byte[] bytes = new byte[1024 * 1024]; // 1MB(一次最多拷貝1MB。)
int readCount = 0;
while((readCount = fis.read(bytes)) != -1) {
fos.write(bytes, 0, readCount);
}
//4、 刷新,輸出流最后要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 分開try,不要一起try。
// 一起try的時(shí)候,其中一個(gè)出現(xiàn)異常,可能會(huì)影響到另一個(gè)流的關(guān)閉。
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
??FileReader && FileWriter && 普通文件拷貝
1.字符輸入流FileReader
(1)對(duì)于字符輸入輸出流FileReader 和?FileWriter的用法,與字節(jié)輸入輸出流FileInputStream 和 FileOutputStream的用法很相似;后者我們已經(jīng)學(xué)過使用byte數(shù)組,前者是使用char數(shù)組!
(2)FileReader: 文件字符輸入流,只能讀取普通文本。 讀取文本內(nèi)容時(shí),比較方便,快捷。
package com.bjpowernode.java.io;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest01 {
public static void main(String[] args) {
FileReader reader = null;
try {
// 創(chuàng)建文件字符輸入流
reader = new FileReader("C:\\Java學(xué)習(xí)\\javaSE學(xué)習(xí)\\2.JavaSE初學(xué)習(xí)筆記\\2.第一章:Java環(huán)境搭建\\HelloWorld.java");
// 開始讀
char[] chars = new char[4]; // 一次讀取4個(gè)字符
// 第一種方法
int readCount = 0;
while((readCount = reader.read(chars)) != -1){
System.out.print(new String(chars,0,readCount));
}
// 補(bǔ)充
reader.read(chars); // 往char數(shù)組中讀
// 按照字符的方式讀取,一次讀取一個(gè)字符
for(char c :chars){
System.out.println(c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.字符輸出流FileWriter
(1)FileWriter:文件字符輸出流,寫;只能輸出普通文本!例如:圖片、聲音、視頻、word文件等,都不可以!
(2)后面的參數(shù)直接跟的是char數(shù)組;也可以直接跟字符串!
注:對(duì)于字節(jié)輸出流FileOutStream,我們寫的時(shí)候如果是字符串,必須調(diào)用getBytes方法轉(zhuǎn)換成byte數(shù)組,才能完成寫入操作;對(duì)于字符輸出流FileWriter,可以直接寫入一個(gè)字符串!文章來源:http://www.zghlxwxcb.cn/news/detail-411055.html
package com.bjpowernode.java.io;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest01 {
public static void main(String[] args) {
FileWriter writer = null;
try {
//1、 創(chuàng)建文件字符輸出流對(duì)象
writer = new FileWriter("file",true); //file,沒有會(huì)自動(dòng)創(chuàng)建
//2、 開始寫
char[] chars = {'我','是','中','國','人'};
// 寫整個(gè)數(shù)組的內(nèi)容
writer.write(chars);
// 也可以只寫數(shù)組的一部分
writer.write(chars,0,2);
// 后面也可以直接跟字符串
writer.write("\n"); // 換行
writer.write("我很驕傲");
//3、 刷新
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.普通文件拷貝
使用FileReader 和 FileWriter進(jìn)行拷貝,只能拷貝“普通文本”文件(能用記事本編輯的)!文章來源地址http://www.zghlxwxcb.cn/news/detail-411055.html
package com.bjpowernode.java.io;
import java.io.*;
public class CopyTest02 {
public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
{
try {
// 創(chuàng)建字符輸入流
reader = new FileReader("file");
// 創(chuàng)建字符輸出流
writer = new FileWriter("myfile");
// 邊讀邊寫
char[] chars = new char[1024*1024]; // 1MB
int readCount = 0;
while((readCount = reader.read(chars)) != -1){
writer.write(chars,0,readCount);
}
// 刷新
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
到了這里,關(guān)于JavaSE進(jìn)階 | 深入理解Java IO流(文件專屬流)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!