IO流上:概述、字元流、緩衝區(java基礎)
一、IO流概述
概述:
IO流簡單來說就是Input和Output流,IO流主要是用來處理裝置之間的資料傳輸,Java對於資料的操作都是通過流實現,而java用於操作流的物件都在IO包中。
分類:
按運算元據分為:位元組流和字元流。 如:Reader和InpurStream
按流向分:輸入流和輸出流。如:InputStream和OutputStream
IO流常用的基類:
* InputStream , OutputStream
字元流的抽象基類:
* Reader , Writer
由上面四個類派生的子類名稱都是以其父類名作為子類的字尾:
如:FileReader和FileInputStream
二、字元流
1. 字元流簡介:
* 字元流中的物件融合了編碼表,也就是系統預設的編碼表。我們的系統一般都是GBK編碼。
* 字元流只用來處理文字資料,位元組流用來處理媒體資料。
* 資料最常見的表現方式是檔案,字元流用於操作檔案的子類一般是FileReader和FileWriter。
2.字元流讀寫:
注意事項:
* 寫入檔案後必須要用flush()重新整理。
* 用完流後記得要關閉流
* 使用流物件要丟擲IO異常
* 定義檔案路徑時,可以用“/”或者“\\”。
* 在建立一個檔案時,如果目錄下有同名檔案將被覆蓋。
* 在讀取檔案時,必須保證該檔案已存在,否則出異常示例1:在硬碟上建立一個檔案,並寫入一些文字資料
- class FireWriterDemo {
- public static void main(String[] args) throws IOException { //需要對IO異常進行處理
- //建立一個FileWriter物件,該物件一被初始化就必須要明確被操作的檔案。
- //而且該檔案會被建立到指定目錄下。如果該目錄有同名檔案,那麼該檔案將被覆蓋。
- FileWriter fw = new FileWriter("F:\\1.txt");//目的是明確資料要存放的目的地。
- //呼叫write的方法將字串寫到流中
- fw.write("hello world!");
- //重新整理流物件緩衝中的資料,將資料刷到目的地中
- fw.flush();
- //關閉流資源,但是關閉之前會重新整理一次內部緩衝中的資料。當我們結束輸入時候,必須close();
- fw.write("first_test");
- fw.close();
- //flush和close的區別:flush重新整理後可以繼續輸入,close重新整理後不能繼續輸入。
- }
- }
示例2:FileReader的reade()方法.
要求:用單個字元和字元陣列進行分別讀取
- class FileReaderDemo {
- public static void main(String[] args) {
- characters();
- }
- /*****************字元陣列進行讀取*********************/
- private static void characters() {
- try {
- FileReader fr = new FileReader("Demo.txt");
- char [] buf = new char[6];
- //將Denmo中的檔案讀取到buf陣列中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字元
- sop(new String(buf,0,num));
- }
- sop('\n');
- fr.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /*****************單個字母讀取*************************/
- private static void singleReader() {
- try {
- //建立一個檔案讀取流物件,和指定名稱的檔案關聯。
- //要保證檔案已經存在,否則會發生異常:FileNotFoundException
- FileReader fr = new FileReader("Demo.txt");
- //如何呼叫讀取流物件的read方法?
- //read()方法,一次讀取一個字元,並且自動往下讀。如果到達末尾則返回-1
- int ch = 0;
- while ((ch=fr.read())!=-1) {
- sop((char)ch);
- }
- sop('\n');
- fr.close();
- /*int ch = fr.read();
- sop("ch=" + (char)ch);
- int ch2 = fr.read();
- sop("ch2=" + (char)ch2);
- //使用結束注意關閉流
- fr.close(); */
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.print(obj);
- }
- }
示例3:對已有檔案的資料進行續寫
- import java.io.*;
- class FileWriterDemo3 {
- public static void main(String[] args) {
- try {
- //傳遞一個引數,代表不覆蓋已有的資料。並在已有資料的末尾進行資料續寫
- FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true);
- fw.write(" is charactor table?");
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
練習:
將F盤的一個檔案複製到E盤。
思考:
其實就是將F盤下的檔案資料儲存到D盤的一個檔案中。
步驟:
1.在D盤建立一個檔案,儲存F盤中檔案的資料。
2.定義讀取流和F:盤檔案關聯。
3.通過不斷讀寫完成資料儲存。
4.關閉資源。原始碼:
- import java.io.*;
- import java.util.Scanner;
- class CopyText {
- public static void main(String[] args) throws IOException {
- sop("請輸入要拷貝的檔案的路徑:");
- Scanner in = new Scanner(System.in);
- String source = in.next();
- sop("請輸入需要拷貝到那個位置的路徑以及生成的檔名:");
- String destination = in.next();
- in.close();
- CopyTextDemo(source,destination);
- }
- /*****************檔案Copy*********************/
- private static void CopyTextDemo(String source,String destination) {
- try {
- FileWriter fw = new FileWriter(destination);
- FileReader fr = new FileReader(source);
- char [] buf = new char[1024];
- //將Denmo中的檔案讀取到buf陣列中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字元
- fw.write(new String(buf,0,num));
- }
- fr.close();
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.println(obj);
- }
- }
三、緩衝區
1. 字元流的緩衝區:BufferedReader和BufferedWreiter
* 緩衝區的出現時為了提高流的操作效率而出現的.
* 需要被提高效率的流作為引數傳遞給緩衝區的建構函式
* 在緩衝區中封裝了一個陣列,存入資料後一次取出
BufferedReader示例:
讀取流緩衝區提供了一個一次讀一行的方法readline,方便對文字資料的獲取。
readline()只返回回車符前面的字元,不返回回車符。如果是複製的話,必須加入newLine(),寫入回車符newLine()是java提供的多平臺換行符寫入方法。
- import java.io.*;
- class BufferedReaderDemo {
- public static void main(String[] args) throws IOException {
- //建立一個字元讀取流流物件,和檔案關聯
- FileReader rw = new FileReader("buf.txt");
- //只要將需要被提高效率的流作為引數傳遞給緩衝區的建構函式即可
- BufferedReader brw = new BufferedReader(rw);
- for(;;) {
- String s = brw.readLine();
- if(s==null) break;
- System.out.println(s);
- }
- brw.close();//關閉輸入流物件
- }
- }
BufferedWriter示例:
- import java.io.*;
- class BufferedWriterDemo {
- public static void main(String[] args) throws IOException {
- //建立一個字元寫入流物件
- FileWriter fw = new FileWriter("buf.txt");
- //為了提高字元寫入效率,加入了緩衝技術。
- //只要將需要被提高效率的流作為引數傳遞給緩衝區的建構函式即可
- BufferedWriter bfw = new BufferedWriter(fw);
- //bfw.write("abc\r\nde");
- //bfw.newLine(); 這行程式碼等價於bfw.write("\r\n"),相當於一個跨平臺的換行符
- //用到緩衝區就必須要重新整理
- for(int x = 1; x < 5; x++) {
- bfw.write("abc");
- bfw.newLine(); //java提供了一個跨平臺的換行符newLine();
- bfw.flush();
- }
- bfw.flush(); //重新整理緩衝區
- bfw.close(); //關閉緩衝區,但是必須要先重新整理
- //注意,關閉緩衝區就是在關閉緩衝中的流物件
- fw.close(); //關閉輸入流物件
- }
- }
2.裝飾設計模式
裝飾設計模式::::
要求:自定義一些Reader類,讀取不同的資料(裝飾和繼承的區別)
MyReader //專門用於讀取資料的類
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
如果將他們抽取出來,設計一個MyBufferReader,可以根據傳入的型別進行增強
class MyBufferReader {
MyBufferReader (MyTextReader text) {}
MyBufferReader (MyMediaReader media) {}
MyBufferReader (MyDataReader data) {}
}
但是上面的類擴充性很差。找到其引數的共同型別,通過多型的形式,可以提高擴充性
class MyBufferReader extends MyReader{
private MyReader r; //從繼承變為了組成模式 裝飾設計模式
MyBufferReader(MyReader r) {}
}
優化後的體系:
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader //增強上面三個。裝飾模式比繼承靈活,
避免繼承體系的臃腫。降低類與類之間的耦合性
裝飾類只能增強已有的物件,具備的功能是相同的。所以裝飾類和被裝飾類屬於同一個體系
MyBuffereReader類: 自己寫一個MyBuffereReader類,功能與BuffereReader相同
- class MyBufferedReader1 extends Reader{
- private Reader r;
- MyBufferedReader1(Reader r){
- this.r = r;
- }
- //一次讀一行資料的方法
- public String myReaderline() throws IOException {
- //定義一個臨時容器,原BufferReader封裝的是字元陣列。
- //為了演示方便。定義一個StringBuilder容器。最終要將資料變成字串
- StringBuilder sb = new StringBuilder();
- int ch = 0;
- while((ch = r.read()) != -1)
- {
- if(ch == '\r')
- continue;
- if(ch == '\n') //遇到換行符\n,返回字串
- return sb.toString();
- else
- sb.append((char)ch);
- }
- if(sb.length()!=0) //當最後一行不是以\n結束時候,這裡需要判斷
- return sb.toString();
- return null;
- }
- /*
- 需要覆蓋Reader中的抽象方法close(),read();
- */
- public void close()throws IOException {
- r.close();
- }
- public int read(char[] cbuf,int off, int len)throws IOException { //覆蓋read方法
- return r.read(cbuf,off,len);
- }
- public void myClose() throws IOException{
- r.close();
- }
- }
一、位元組流
1.概述:
1、位元組流和字元流的基本操作是相同的,但是要想操作媒體流就需要用到位元組流。
2、位元組流因為操作的是位元組,所以可以用來操作媒體檔案。(媒體檔案也是以位元組儲存的)
3、讀寫位元組流:InputStream 輸入流(讀)和OutputStream 輸出流(寫)
4、位元組流操作可以不用重新整理流操作。
5、InputStream特有方法:
int available();//返回檔案中的位元組個數
注:可以利用此方法來指定讀取方式中傳入陣列的長度,從而省去迴圈判斷。但是如果檔案較大,而虛擬機器啟動分配的預設記憶體一般為64M。當檔案過大時,此陣列長度所佔記憶體空間就會溢位。所以,此方法慎用,當檔案不大時,可以使用。練習:
需求:複製一張圖片F:\java_Demo\day9_28\1.BMP到F:\java_Demo\day9_28\2.bmp
- import java.io.*;
- class CopyPic {
- public static void main(String[] args){
- copyBmp();
- System.out.println("複製完成");
- }
- public static void copyBmp() {
- FileInputStream fis = null;
- FileOutputStream fos = null;
- try {
- fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp"); //寫入流關聯檔案
- fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp"); //讀取流關聯檔案
- byte[] copy = new byte[1024];
- int len = 0;
- while((len=fis.read(copy))!=-1) {
- fos.write(copy,0,len);
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("複製檔案異常");
- }
- finally {
- try {
- if(fis!=null) fis.close();
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("讀取流");
- }
- }
- }
- }
2. 位元組流緩衝區
* 位元組流緩衝區跟字元流緩衝區一樣,也是為了提高效率。
注意事項:
1. read():會將位元組byte()提升為int型值
2. write():會將int型別轉換為byte()型別,保留最後的8位。
練習:
1.複製MP3檔案 1.MP3 --> 2.MP3
2.自己寫一個MyBufferedInputStream緩衝類,提升複製速度
程式碼:
- import java.io.*;
- //自己的BufferedInputStream
- class MyBufferedInputStream {
- private InputStream in; //定義一個流物件
- private byte [] buf = new byte[1024*4];
- private int count = 0,pos = 0;
- public MyBufferedInputStream(InputStream in){
- this.in = in;
- }
- public int MyRead() throws IOException{
- if(count==0) { //當陣列裡的資料為空時候,讀入資料
- count = in.read(buf);
- pos = 0;
- byte b = buf[pos];
- count--;
- pos++;
- return b&255; //提升為int型別,在前面三個位元組補充0。避免1111 1111 1111 1111
- }
- else if(count > 0) {
- byte b = buf[pos];
- pos++;
- count--;
- return b&0xff; //提升為int型別,在前面三個位元組補充0。避免1111 1111 1111 1111
- }
- return -1;
- }
- public void myClose() throws IOException{
- in.close();
- }
- }
- class BufferedCopyDemo {
- public static void main(String[] args) {
- long start = System.currentTimeMillis();
- copy();
- long end = System.currentTimeMillis();
- System.out.println("時間:"+(end-start)+"ms");
- start = System.currentTimeMillis();
- copy1();
- end = System.currentTimeMillis();
- System.out.println("時間:"+(end-start)+"ms");
- }
- public static void copy1() { // 應用自己的緩衝區緩衝資料
- MyBufferedInputStream bis = null;
- BufferedOutputStream bos = null;
- try {
- bis = new MyBufferedInputStream(new FileInputStream("馬旭東-入戲太深.mp3"));//匿名類,傳入一個InputStream流物件
- bos = new BufferedOutputStream(new FileOutputStream("3.mp3"));
- int buf = 0;
- while((buf=bis.MyRead())!=-1) {
- bos.write(buf);
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("複製失敗");
- }
- finally {
- try {
- if(bis!=null) {
- bis.myClose();
- bos.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
二、流操作規律
1. 鍵盤讀取,控制檯列印。
System.out: 對應的標準輸出裝置:控制檯 //它是PrintStream物件,(PrintStream:列印流。OutputStream的子類)
System.in: 對應的標準輸入裝置:鍵盤 //它是InputStream物件
示例:
- /*================從鍵盤錄入流,列印到控制檯上================*/
- public static void InOutDemo(){
- //鍵盤的最常見的寫法
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- try {
- /*InputStream ips = System.in; //從鍵盤讀入輸入位元組流
- InputStreamReader fr = new InputStreamReader(ips); //將位元組流轉成字元流
- bufr = new BufferedReader(fr); */ //將字元流加強,提升效率
- bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取位元組並將其解碼為字元
- bufw = new BufferedWriter(new OutputStreamWriter(System.out)); //OutputStreamWriter:要寫入流中的字元編碼成位元組
- String line = null;
- while((line = bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase()); //列印
- bufw.newLine(); //為了相容,使用newLine()寫入換行符
- bufw.flush(); //必須要重新整理。不然不會顯示
- }
- if(bufw!=null) {
- bufr.close();
- bufw.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
2. 整行錄入
1.從鍵盤錄入資料,並儲存到檔案中。
2. 我們在鍵盤錄入的是時候,read()方法是一個一個錄入的,能不能整行的錄入呢?這時候我們想到了BufferedReader中ReadLine()方法。
3. 轉換流
為了讓位元組流可以使用字元流中的方法,我們需要轉換流。
1. InputStreamReader:位元組流轉向字元流;
a、獲取鍵盤錄入物件。InputStream in=System.in;
b、將位元組流物件轉成字元流物件,使用轉換流。
InputStreamReaderisr=new InputStreamReader(in);
c、為了提高效率,將字串進行緩衝區技術高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//鍵盤錄入最常見寫法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
2.OutputStreamWriter:字元流通向位元組流
示例:
- /*================把鍵盤錄入的資料存到一個檔案中==============*/
- public static void inToFile() {
- //鍵盤的最常見的寫法
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- try {
- /*InputStream ips = System.in; //從鍵盤讀入輸入位元組流
- InputStreamReader fr = new InputStreamReader(ips); //將位元組流轉成字元流
- bufr = new BufferedReader(fr); */ //將字元流加強,提升效率
- bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取位元組並將其解碼為字元
- bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt"))); //OutputStreamWriter:要寫入流中的字元編碼成位元組
- String line = null;
- while((line = bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase()); //列印
- bufw.newLine(); //為了相容,使用newLine()寫入換行符
- bufw.flush(); //必須要重新整理。不然不會顯示
- }
- if(bufw!=null) {
- bufr.close();
- bufw.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
4. 流操作基本規律
為了控制格式我將其寫入了Java程式碼段中,如下:
示例1:文字 ~ 文字
- /*
- 流操作的基本規律。
- 一、兩個明確:(明確體系)
- 1. 明確源和目的
- 源:輸入流 InputStream Reader
- 目的:輸出流 OutputStream Writer
- 2. 操作的資料是否是純文字
- 是: 字元流
- 否: 位元組流
- 二、明確體系後要明確具體使用的物件
- 通過裝置區分:記憶體,硬碟,鍵盤
- 目的裝置:記憶體,硬碟,控制檯
- 示例1:將一個文字檔案中的資料儲存到另一個檔案中: 複製檔案
- 一、明確體系
- 源:檔案-->讀取流-->(InputStream和Reader)
- 是否是文字:是-->Reader
- 目的:檔案-->寫入流-->(OutputStream Writer)
- 是否純文字:是-->Writer
- 二、 明確裝置
- 源:Reader
- 裝置:硬碟上一個文字檔案 --> 子類物件為:FileReader
- FileReader fr = new FileReader("Goods.txt");
- 是否提高效率:是-->加入Reader中的緩衝區:BufferedReader
- BufferedReader bufr = new BufferedReader(fr);
- 目的:Writer
- 裝置:鍵盤上一個文字檔案 --> 子類物件:FileWriter
- FileWriter fw = new FileWriter("goods1.txt");
- 是否提高效率:是-->加入Writer的緩衝區:BufferedWriter
- BufferedWriter bufw = new BufferedWriter(fw);
- 示例2:將一個圖片檔案資料複製到另一個檔案中:複製檔案
- 一、明確體系
- 源:檔案-->讀取流-->(InputStream和Reader)
- 是否是文字:否-->InputStream
- 目的:檔案-->寫入流-->(OutputStream Writer)
- 是否純文字:否-->OutputStream
- 二、 明確裝置
- 源:InputStream
- 裝置:硬碟上一個媒體檔案 --> 子類物件為:FileInputStream
- FileInputStream fis = new FileInputStream("Goods.txt");
- 是否提高效率:是-->加入InputStream中的緩衝區:BufferedInputStream
- BufferedInputStream bufi = new BufferedInputStream(fis);
- 目的:OutputStream
- 裝置:鍵盤上一個媒體檔案 --> 子類物件:FileOutputStream
- FileOutputStream fos = new FileOutputStream("goods1.txt");
- 是否提高效率:是-->加入OutputStream的緩衝區:BufferedOutputStream
- BufferedOutputStream bufo = new BufferedOutputStream(fw);
- 示例3:將鍵盤錄入的資料儲存到一個文字檔案中
- 一、明確體系
- 源:鍵盤-->讀取流-->(InputStream和Reader)
- 是否是文字:是-->Reader
- 目的:檔案-->寫入流-->(OutputStream Writer)
- 是否純文字:是-->Writer
- 二、 明確裝置
- 源:InputStream
- 裝置:鍵盤 --> 對用物件為:System.in --> InputStream
- 為了操作方便,轉成字元流Reader --> 使用Reader中的轉換流:InputStreamReader
- InputStreamReader isr = new InputStreamReader(System.in);
- 是否提高效率:是-->加入Reader中的緩衝區:BufferedReader
- BufferedReader bufr = new BufferedReader(isr);
- 目的:Writer
- 裝置:鍵盤上一個文字檔案 --> 子類物件:FileWriter
- FileWriter fw = new FileWriter("goods1.txt");
- 是否提高效率:是-->加入Writer的緩衝區:BufferedWriter
- BufferedWriter bufw = new BufferedWriter(fw);
5.指定編碼表(轉換流可以指定編碼表)
要求:用UTF-8編碼儲存一個文字檔案
- import java.io.*;
- public class IOStreamLaw {
- /**
- * @param args
- */
- public static void main(String[] args) throws IOException {
- //鍵盤的最常見寫法
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("goods1.txt"),"UTF-8"));
- String line = null;
- while((line=bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- bufr.close();
- }
- }
相關文章
- Java基礎(八)——IO流2_緩衝流、轉換流Java
- Java基礎(八)——IO流1_位元組流、字元流Java字元
- Java的位元組流,字元流和緩衝流對比探究Java字元
- Java緩衝流概述詳解(原理畫圖分析)Java
- [java IO流]之 IO概述Java
- Java™ 教程(緩衝流)Java
- stdio流緩衝區
- C 標準庫IO緩衝區和核心緩衝區的區別
- IO流(02)--屬性集、緩衝流、轉換流
- Java之IO流基礎流物件Java物件
- Java 基礎(九)字元流Java字元
- JAVA_基礎IO流物件流(三)Java物件
- Java NIO:緩衝區Java
- Java_轉換流和緩衝流Java
- Java IO: 其他字元流(下)Java字元
- Java IO5:字元流Java字元
- RMAN的IO記憶體緩衝區記憶體
- Java NIO 之緩衝區Java
- Java整數緩衝區Java
- Java IO之有緩衝的文字輸入Java
- Java IO之有緩衝的文字輸出Java
- Java基礎 Java-IO流 深入淺出Java
- 檔案的複製通過字元流和緩衝流(Buffered)字元
- java基礎學習_io流之FileInputStreamJava
- IO 字元流字元
- java基礎(四):談談java中的IO流Java
- Java基礎14-java進階(5)【IO流】Java
- Java NIO 之 Buffer(緩衝區)Java
- Java NIO2:緩衝區Java
- IO流下:位元組流、流操作規律(java基礎)Java
- Java IO流字元流簡介及基本使用Java字元
- Java緩衝輸出位元組流BufferedOutputStreamJava
- Java基礎之IO轉換流學習Java
- java的IO操作:位元組流與字元流操作Java字元
- Java-NIO之Buffer(緩衝區)Java
- Java 基於字元的IO Char Based IOJava字元
- [java]利用IO流中的位元組流和緩衝流寫一個複製資料夾的小程式Java
- Java基礎知識回顧之六 —– IO流Java