
一、IO概念
• I/O 即輸入Input/ 輸出Output的縮寫,其實就是計算機排程把各個存儲中(包括記憶體和外部存儲)的資料寫入寫出的過程;
• java中用“流(stream)”來抽象表示這麼一個寫入寫出的功能,封裝成一個“類”,都放在 http:// java.io 這個包裡面。
二、來了解“流”是什麼?
通過“流”的形式允許java程式使用相同的方式來通路不同的輸入/輸出源。stream是從起源(source)到接收的(sink)的有序資料。我們這裡把輸入/輸出源對比成“水桶”,那麼流就是“管道”,這個“管道”的粗細、單向性等屬性也就是區分了不同“流”的特性。
三、IO流的分類
可以從三個不同的次元進行分類:
• 1、按照流的方向(輸出輸入都是站在程式所在記憶體的角度劃分的)• 輸入流:隻能從中讀取資料【主要由InputStream和Reader作為基類】
• 輸出流:隻能向其寫入資料【主要由outputStream和Writer作為基類】
在下圖中,從磁盤讀取資料到記憶體是輸入流,從client讀取資料到server是輸入流;同樣,把記憶體資料寫到磁盤是輸出流,把server資料寫到client是輸出流
• 3、按照流的角色劃分• 位元組流:以位元組為單元,可操作任何資料【主要由InputStream和outPutStream作為基類】
• 字元流:以字元為單元,隻能操作純字元資料,比較友善【主要由Reader和Writer作為基類】
• 節點流:可以從/向一個特定的IO裝置(如磁盤,網絡)讀/寫資料的流,也叫【低級流,主要由】
• 處理流:用于對一個已存在的流進行連接配接和封裝,通過封裝後的流來實作資料的讀/寫功能,也叫【進階流】
下圖中可以看出來,處理流就是在基礎的位元組流上,進行了封裝,增加了特定的功能,使得傳輸更适合特定的場景。
四、流的原理以及一共有多少IO流
• 1、流的原了解析流其實我們可以想象成一個“水管”,源端和目的端就是兩個“水桶”,資料是通過這個“水管”進行流動傳輸的,以InputStream和Reader為例,水管的每個“水滴”就是具體的資料,如果是位元組流,那麼一個“水滴”就是一個位元組,如果是字元流,那麼一個“水滴”就是一個字元。
當建立一個流對象的時候,如fis=new FileInputStream(“…xxxx.txt”),記錄指針來表示目前正準備從哪個“水滴”開始讀取,每當程式從InputStream或者Reader裡面取出一個或者多個“水滴”後,記錄指針自定向後移動;除此之外,InputStream和Reader裡面都提供了一些方法來控制記錄指針的移動。
如果是處理流的話,就相當于在這個水管上面裝了一些“控制閥門”,最終使用者隻要關心“閥門”具備的能力就行
http://java.io中子類有40個“流”類,我們用以下表格來綜合劃分,當然這些流你不用都去花時間一個一個看過來,我們隻要熟悉掌握幾類常用的“流”就足夠了,後續項目中如果用到陌生的“流”,知道原理的話可以快速地去檢索學習下就ok了。
上圖中我們可以看到,InputStream/Reader,OutputStream/Writer 是整個I/O體系的基類,他們本身不能用來建立執行個體,下面開始逐一對常見的I/O類進行實戰
五、常見IO流的實戰
1、通路操作檔案(FileInputStream/FileReader ,FileOutputStream/FileWriter)FileInputStream中包含以使用FileInputStream為例,類中包含的屬性及方法,我們可以線上檢視jdk的api文檔http://tool.oschina.net/apidocs/apidoc?api=jdk-zh),下面隻是截圖了FileInputStream的構造方法:
1)使用FileInputStream,從檔案讀取資料
import java.io.*;
public class TestFileImportStream {
public static void main(String[] args) {
int b=0;
FileInputStream in = null;
try {
in =new FileInputStream("C:Users41639DesktopjavaFileTextsrcTestFileImportStream.java");
}catch(FileNotFoundException e){
System.out.println("file is not found");
System.exit(-1);
}
try {
long num=0;
while ((b=in.read())!=-1) {
System.out.println((char)b);
num++;
}
in.close();
System.out.println();
System.out.println("共讀取了"+num+"個位元組");
}catch(IOException e) {
System.out.println("IO異常,讀取失敗");
System.exit(-1);
}
}
}
2)使用FileOutputStream,往檔案裡寫資料
import java.io.*;
public class TextFileOutputStream {
public static void main(String[] args) {
int b=0;
FileInputStream in = null;
FileOutputStream out = null;
try {
in =new FileInputStream("C:Users41639DesktopjavaFileTextsrcTestFileImportStream.java");
out=new FileOutputStream("C:Users41639Desktopjavatempout.java");
}catch(FileNotFoundException e){
System.out.println("file is not found");
System.exit(-1);
}
try {
while ((b=in.read())!=-1) {
out.write(b);
}
in.close();
out.close();
}catch(IOException e) {
System.out.println("IO異常,讀取失敗");
System.exit(-1);
}
System.out.println("檔案複制完成");
}
}
PS:大家也可以嘗試使用FileReader、FileWriter,看看和FileInputStream、FileOutputStream有什麼差別
2、緩存流的使用(BufferedInputStream/BufferedOutputStream,BufferedReader/BufferedWriter)import java.io.*;
public class TestBufferStream {
public static void main (String[] args) throws IOException{
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
FileInputStream fis = new FileInputStream("C:Users41639DesktopjavaFileTextsrcTestFileImportStream.java");
FileOutputStream fos = new FileOutputStream("C:Users41639Desktopjavatempout2.java");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int off=0;
while ((off=bis.read(b))>0) {
bos.write(b,0,off);
}
bis.close();
bos.close();
}catch (IOException e) {
e.printStackTrace();
}finally {
bis.close();
bos.close();
}
}
}
從代碼中可以看到,他們最基本的其實也是FileInputStream和FileOutputStream,在這個“流”的基礎上,又加了緩存的功能流BufferedInputStream和BufferedOutputStream。相對比較好了解。
3、轉換流的使用(InputStreamReader/OutputStreamWriter)字面意思了解,轉化流就是用來轉化的,那麼到底是什麼轉什麼呢?我們可以通過以下的例子來熟悉。讀取鍵盤輸入的每一行内容,并寫入到文本中,直到遇到over行結束輸入
import java.io.*;
public class TransStreamTest {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter("C:Users41639Desktopjavatemptest1031.txt"));
String line =null;
while ((line=br.readLine())!=null) {
if ("over".contentEquals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
PS:readLine()方法在進行讀取一行時,隻有遇到回車(r)或者換行符(n)才會傳回讀取結果,這就是“讀取一行的意思”,有興趣的同學檢視readLine()源碼
4、對象流的使用(FileInputStream/ObjectOutputStream)前面講了位元組和字元流,包括封裝在他們上面的處理流,那麼我們想,在程式設計的過程中,我們都是用類和對象來描述定義,能不能直接把對象進行傳輸。答案當然是肯定的,對象流其實就是一種特殊的處理流水,也是在基礎的位元組流上去作封裝。【可以應用于遊戲存盤】
下面程式使用一個對象流,把對象直接寫到檔案中
import java.io.*;
public class ObjectStreamTest {
public static void main(String[] args) throws Exception{
try {
Person P=new Person("Jeccica",26);
FileOutputStream fos=new FileOutputStream("C:UsersadminDesktopJavatemp22.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(P);
oos.flush();
oos.close();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
FileInputStream fis=new FileInputStream("C:UsersadminDesktopJavatemp22.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Person P2=(Person)ois.readObject();
System.out.println(P2.name+"的年齡為"+P2.age);
}
}
class Person implements Serializable{
String name=null;
int age=0;
Person(String _name,int _age){
name=_name;
age=_age;
}
}
5、位元組數組流的使用(ByteArrayInputStream/ByteArrayOutputStream)【通常結合資料流DataInputStream/DataOutputStream】 我們分析了常見的節點流和常見的處理流等,經常而言我們都是針對檔案的操作,然後帶上緩沖的節點流進行處理,但有時候為了提升效率,我們發現頻繁的讀寫檔案并不是太好,那麼于是出現了位元組數組流,即存放在記憶體中,是以又稱之為記憶體流;其中位元組數組流也一種節點流;除了節點流外,我們也将學習另外一種處理流,即資料流。資料處理流是用于針對資料類型傳輸處理的,是一種處理流,即是在節點流之上的增強處理,一般用于序列化和反序列化的時候用到。
import java.io.*;
public class DataStream {
public static void main(String[] args) {
ByteArrayOutputStream baos=new ByteArrayOutputStream();//建立位元組數組流,同時會在記憶體裡面建立數組
DataOutputStream dos=new DataOutputStream(baos);//對位元組數組流外封裝成資料處理流
try {
dos.writeDouble(Math.random());//利用資料流裡面的寫入方法,寫一個Double類型的随機資料
dos.writeBoolean(true);
ByteArrayInputStream bias=new ByteArrayInputStream(baos.toByteArray());//toByteArray()方法是建立一個新配置設定的位元組數組。數組的大小和目前輸出流的大小。這裡指的是baos這個位元組數組
System.out.println(bias.available());
DataInputStream dis=new DataInputStream(bias);
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
dos.close();
dis.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
感謝你看到這裡,我是
程式員麥冬,一個java開發從業者,深耕行業六年了,每天都會分享java相關技術文章或行業資訊
歡迎大家關注和轉發文章,後期還有福利贈送!