【JAVA IO】_位元組流與字元流筆記
本章目標:
掌握流的概念
掌握位元組流與字元流的作用
掌握檔案的標準操作步驟
掌握位元組與字元操作的區別
程式中的輸入輸出都是以流的形式儲存的,流中儲存的實際上全部是位元組檔案。
3.2、位元組流與字元流
在java.io包中操作檔案內容的主要有兩大類:位元組流、字元流,兩類都分為輸入和輸出操作。在位元組流中輸出資料主要是使用OutputStream完成,輸入使的是InputStream,在字元流中輸出主要是使用Write類完成,輸入主要是使用Reader類完成。
內容操作就四個類:OutputStream、InputStream、Writer、Reader
操作流程:
A、使用File類開啟一個檔案
B、通過位元組流或字元流的子類,指定輸出的位置
C、進行讀/寫操作
D、關閉輸入/輸出
3.3、位元組流
位元組流主要是操作byte類型資料,以byte數組為準,主要操作類就是OutputStream、InputStream。
位元組輸出資料流:OutputStream
位元組輸入資料流:InputStream
Byte是位元組,肯定使用位元組流操作。所有的資料基本上都可以直接使用byte數組表示出來。
3.3.1、位元組輸出資料流:OutputStream
OutputStream類
outputStream是整個io包中位元組輸出資料流的最大父類,此類的定義如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
Closeable表示可以關閉的操作,因為程式運行到最後肯定要關閉。
Flushable表示重新整理,清空記憶體中的資料。
OutputStream類的常用方法:
No. 方法或變數 描述
1 public void close() throws IOException 關閉輸出資料流
2 public void flash() throws IOException 重新整理緩衝區
3 public void write(byte[] b) throws IOException 將一個byte數組寫入資料流
4 public void write(byte[] b,int off,int len) throws IOException 將一個指定範圍的byte數組寫入資料流
5 public abstract void write(int b) throws IOException 將一個位元組資料寫入資料流
要想使用以上方法,必須使用子類執行個體化,此時使用FileOutputStream子類,此類的構造方法如下:
public FileOutputStream(File file) throws FileNotFoundException
import java.io.File;import java.io.OutputStream;import java.io.FileOutputStream;public class OutputStreamDemo01{ public static void main(String args[])throws Exception{ //第一步、使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //第二步、通過子類執行個體化父類對象 OutputStream out = null; out = new FileOutputStream(f); //第三步、進行寫操作 String str = "Hello World!!!"; byte b[] = str.getBytes(); out.write(b); //第四步、關閉輸出資料流 out.close(); }}
在操作的時候,如果檔案本身不存在,則會為使用者自動建立新檔案。
在操作輸出資料流的時候,也可以使用write(int i)的方法寫出資料。
import java.io.File;import java.io.OutputStream;import java.io.FileOutputStream;public class OutputStreamDemo01{ public static void main(String args[])throws Exception{ //第一步、使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //第二步、通過子類執行個體化父類對象 OutputStream out = null; out = new FileOutputStream(f); //第三步、進行寫操作 String str = "Hello World!!!"; byte b[] = str.getBytes(); for(int i=0;i<b.length;i++){ out.write(b[i]); //每次唯寫一個位元組內容 } //第四步、關閉輸出資料流 out.close(); }}
以上操作中在寫入資料後,檔案之前的內容已經不存在了,因為在IO操作中預設的情況是將其內容覆蓋的,那麼如果現在想要執行追加的功能,則必須設定追加操作,找到FileOutputStream類。
構造方法:
public FileOutputStream(File file,boolean append) throws FileNotFoundException
import java.io.File;import java.io.OutputStream;import java.io.FileOutputStream;public class OutputStreamDemo01{ public static void main(String args[]) throws Exception{ //第一步、使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //第二步、通過子類執行個體化父類對象 OutputStream out = null; out = new FileOutputStream(f,true); //第三步、進行寫操作 String str = "Hello World!!!"; byte b[] = str.getBytes(); for(int i=0;i<b.length;i++){ out.write(b[i]); //每次唯寫一個位元組內容 } //第四步、關閉輸出資料流 out.close(); }}
如果在檔案操作中想換行的話,使用"\r\n"完成。
import java.io.File;import java.io.OutputStream;import java.io.FileOutputStream;public class OutputStreamDemo01{ public static void main(String args[])throws Exception{ //第一步、使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //第二步、通過子類執行個體化父類對象 OutputStream out = null; out = new FileOutputStream(f,true); //第三步、進行寫操作 String str = "\r\nHello World!!!"; byte b[] = str.getBytes(); for(int i=0;i<b.length;i++){ out.write(b[i]); //每次唯寫一個位元組內容 } //第四步、關閉輸出資料流 out.close(); }}
3.3.2、位元組輸入資料流:InputStream
定義格式:
public abstract class InputStream extends Object implements Closeable
構造方法:
public FileInputStream(File file) throws FileNotFoundException
InputStream類的常用方法
No. 方法或常量 描述
1 public int available() throws IOException 可以取得輸入檔案的大小
2 public void close() throws IOException 關閉輸入資料流
3 public abstract int read() throws IOException 讀取內容,以數位方式讀取
4 public int read(byte[] b) throws IOException 將內容讀到byte數組之中,同時返回讀入的個數。
import java.io.File;import java.io.InputStream;import java.io.FileInputStream;public class InputStreamDemo01{ public static void main(String[] args)throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 InputStream input = null; input = new FileInputStream(f); //3.進行讀操作 byte b[] = new byte[1024]; input.read(b); //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(b)); //將byte數組變為字串輸出 }}
輸出:
內容為:Hello World!!!Hello World!!!
Hello World!!!
此時內容雖然讀取出來了,但是可以發現存在的問題。
import java.io.File;import java.io.InputStream;import java.io.FileInputStream;public class InputStreamDemo01{ public static void main(String[] args)throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 InputStream input = null; input = new FileInputStream(f); //3.進行讀操作 byte b[] = new byte[1024]; int len = input.read(b); //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(b,0,len)); //將byte數組變為字串輸出 }}
能不能根據檔案的大小來開闢數組空間呢?
直接使用File類即可:public long length()
import java.io.File;import java.io.InputStream;import java.io.FileInputStream;public class InputStreamDemo01{ public static void main(String[] args)throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 InputStream input = null; input = new FileInputStream(f); //3.進行讀操作 byte b[] = new byte[(int)f.length()]; int len = input.read(b); //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(b)); //將byte數組變為字串輸出 }}
以上是直接使用byte數組的方式完成的。
現在使用public abstract int read() throws IOException讀取內容
import java.io.File;import java.io.InputStream;import java.io.FileInputStream;public class InputStreamDemo01{ public static void main(String[] args)throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 InputStream input = null; input = new FileInputStream(f); //3.進行讀操作 byte b[] = new byte[(int)f.length()]; for(int i=0;i<b.length;i++){ b[i] = (byte)input.read(); } //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(b)); //將byte數組變為字串輸出 }}
以上的操作,只適合於知道輸入資料流大小的時候,如果現在不知道大小呢?
import java.io.File;import java.io.InputStream;import java.io.FileInputStream;public class InputStreamDemo01{ public static void main(String[] args)throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 InputStream input = null; input = new FileInputStream(f); //3.進行讀操作 byte b[] = new byte[1024]; int len = 0; int temp = 0; //以下代碼顏色加深標記 while((temp = input.read())!=-1){ b[len] = (byte)temp; len++; } //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(b,0,len)); //將byte數組變為字串輸出 }}
當不知道讀取內容有多大的時候,就只能以讀取的資料是否為-1做為讀完的標誌。
3.4、字元流
在程式中一個位元組等於2個位元組,那麼java提供了Reader、Writer兩個專門操作字元流的類。
字元輸出資料流Writer
字元輸入資料流Reader
3.4.1、字元輸出資料流:Writer
Write本身是一個字元流的輸出類,此類的定義如下:
public abstract class Writer extends Object implements Appendable,Closeable,Flushable
構造方法:
public FileWriter(File file) throws IOException
Writer類的常用方法
No. 方法或常量 描述
1 public abstract void close() throws IOException 關閉輸出資料流
2 public void write(String str) throws IOException 將字串輸出
3 public void write(Char[] char) throws IOException 將字元數組輸出
4 public abstract void flush() throws IOException 強制性清空緩衝
字元流的操作比位元組流操作好在一點,就是可以直接輸出字串了。不用再像之前那樣進行轉換操作了。
import java.io.File;import java.io.Writer;import java.io.FileWriter;public class WriteDemo01{ public static void main(String args[])throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Writer out = null; out = new FileWriter(f); //3.進行寫操作 String str = "Hello World!!!"; out.write(str); //4.關閉輸出資料流 out.close(); }}
FileWriter增加追加標識
import java.io.File;import java.io.Writer;import java.io.FileWriter;public class WriteDemo01{ public static void main(String args[])throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Writer out = null; out = new FileWriter(f,true); //3.進行寫操作 String str = "\r\nLixinghuaHello World!!!"; out.write(str); //4.關閉輸出資料流 out.close(); }}
3.4.2、字元輸入資料流Reader
字元輸入資料流:Reader
定義格式:
public abstract class Reader extends Object implements Readable,Closeable
Reader本身也是抽象類別地,如果現在要從檔案中讀取內容,則可以直接使用FileReader子類。
FileReader的構造方法:
public FileReader(File file) throws FileNotFoundException
Reader類的常用方法:
No. 方法或常量 描述
1 public abstract void close() throws IOException 關閉輸出資料流
2 public int read() throws IOException 讀取單個字元
3 public int read(char[] cbuf) throws IOException 將內容讀到字元數組之中,返回讀入的長度
以字元數組的形式讀取出數組
import java.io.File;import java.io.Reader;import java.io.FileReader;public class ReaderDemo01{ public static void main(String args[])throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Reader input = null; input = new FileReader(f); //3.進行讀操作 char c[] = new char[1024]; //記住這裡的char是小寫 int len = input.read(c);//形同FileinputStream的read()方法 //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(c,0,len)); }}
可以使用迴圈的方式,通過檔案是否讀到低的形式讀取。
import java.io.File;import java.io.Reader;import java.io.FileReader;public class ReaderDemo01{ public static void main(String args[]) throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Reader input = null; input = new FileReader(f); //3.進行讀操作 char c[] = new char[1024]; int len=0; int temp=0; while((temp=input.read())!=-1){ c[len] = (char)temp; len++; } //4.關閉輸出資料流 input.close(); System.out.println("內容為:"+new String(c,0,len)); }}
3.5、位元組流與字元流的區別
位元組流和字元流使用是非常相似的,那麼除了作業碼的不同之外,還有那些不同呢?
通過一段代碼來驗證字元流使用到了緩衝。
import java.io.File;import java.io.OutputStream;import java.io.FileOutputStream;public class OutputStreamDemo01{ public static void main(String args[]) throws Exception{ //第一步、使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //第二步、通過子類執行個體化父類對象 OutputStream out = null; out = new FileOutputStream(f); //第三步、進行寫操作 String str = "Hello World!!!"; byte b[] = str.getBytes(); out.write(b); //第四步、關閉輸出資料流 //out.close(); }}
在使用位元組流操作中,即使沒有關閉,最終也是可以輸出的。
import java.io.File;import java.io.Writer;import java.io.FileWriter;public class WriteDemo01{ public void main(String args[])throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Writer out = null; out = new FileWriter(f,true); //3.進行寫操作 String str = "\r\nLixinghuaHello World!!!"; out.write(str); //4.關閉輸出資料流 //out.close(); }}
以上的操作,沒有輸出任何的內容出來,也就是說,所有的內容現在都是儲存在了緩衝區之中,而如果執行關閉的時候會強制性的重新整理緩衝區,所以可以把內容輸出。
如果現在假設,沒有關閉的話,也可以手工強制性調用重新整理方法。
public abstract void flush() throws IOException
import java.io.File;import java.io.Writer;import java.io.FileWriter;public class WriteDemo01{ public void main(String args[])throws Exception{ //1.使用File類找到一個檔案 File f = new File("d:"+File.separator+"test.txt"); //2.通過子類執行個體化父類對象 Writer out = null; out = new FileWriter(f,true); //3.進行寫操作 String str = "\r\nLixinghuaHello World!!!"; out.write(str); //4.關閉輸出資料流 out.flush(); //out.close(); }}
問題: 開發中是使用位元組流好還是字元流好?
所有的硬碟上儲存檔案或是進行傳輸的時候都是以位元組的方式進行的。包括圖片也是按位元組完成,而字元是只有在記憶體中才會形成,所以使用位元組的操作是最多的。
3.6、操作範例
import java.io.* ;public class Copy{ public static void main(String args[]){ if(args.length!=2){ // 判斷是否是兩個參數 System.out.println("輸入的參數不正確。") ; System.out.println("例:java Copy 源檔案路徑 目標檔案路徑") ; System.exit(1) ; // 系統退出 } File f1 = new File(args[0]) ; // 源檔案的File對象 File f2 = new File(args[1]) ; // 目標檔案的File對象 if(!f1.exists()){ System.out.println("源檔案不存在!") ; System.exit(1) ; } InputStream input = null ; // 準備好輸入資料流對象,讀取源檔案 OutputStream out = null ; // 準備好輸出資料流對象,寫入目標檔案 try{ input = new FileInputStream(f1) ; }catch(FileNotFoundException e){ e.printStackTrace() ; } try{ out = new FileOutputStream(f2) ; }catch(FileNotFoundException e){ e.printStackTrace() ; } if(input!=null && out!=null){ // 判斷輸入或輸出是否準備好 int temp = 0 ; try{ while((temp=input.read())!=-1){ // 開始拷貝 out.write(temp) ; // 邊讀邊寫 } System.out.println("拷貝完成!") ; }catch(IOException e){ e.printStackTrace() ; System.out.println("拷貝失敗!") ; } try{ input.close() ; // 關閉 out.close() ; // 關閉 }catch(IOException e){ e.printStackTrace() ; } } } }