1. 程式人生 > >IO流上:概述、字符流、緩沖區

IO流上:概述、字符流、緩沖區

character 字母 寫入文件 world input bsp 常見 ble 文件關聯

一、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:在硬盤上創建一個文件,並寫入一些文字數據

  1. class FireWriterDemo {
  2. public static void main(String[] args) throws IOException { //需要對IO異常進行處理
  3. //創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件。
  4. //而且該文件會被創建到指定目錄下。如果該目錄有同名文件,那麽該文件將被覆蓋。
  5. FileWriter fw = new FileWriter("F:\\1.txt");//目的是明確數據要存放的目的地。
  6. //調用write的方法將字符串寫到流中
  7. fw.write("hello world!");
  8. //刷新流對象緩沖中的數據,將數據刷到目的地中
  9. fw.flush();
  10. //關閉流資源,但是關閉之前會刷新一次內部緩沖中的數據。當我們結束輸入時候,必須close();
  11. fw.write("first_test");
  12. fw.close();
  13. //flush和close的區別:flush刷新後可以繼續輸入,close刷新後不能繼續輸入。
  14. }
  15. }

示例2:FileReader的reade()方法.

要求:用單個字符和字符數組進行分別讀取

  1. class FileReaderDemo {
  2. public static void main(String[] args) {
  3. characters();
  4. }
  5. /*****************字符數組進行讀取*********************/
  6. private static void characters() {
  7. try {
  8. FileReader fr = new FileReader("Demo.txt");
  9. char [] buf = new char[6];
  10. //將Denmo中的文件讀取到buf數組中。
  11. int num = 0;
  12. while((num = fr.read(buf))!=-1) {
  13. //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
  14. sop(new String(buf,0,num));
  15. }
  16. sop(‘\n‘);
  17. fr.close();
  18. }
  19. catch (IOException e) {
  20. sop(e.toString());
  21. }
  22. }
  23. /*****************單個字母讀取*************************/
  24. private static void singleReader() {
  25. try {
  26. //創建一個文件讀取流對象,和指定名稱的文件關聯。
  27. //要保證文件已經存在,否則會發生異常:FileNotFoundException
  28. FileReader fr = new FileReader("Demo.txt");
  29. //如何調用讀取流對象的read方法?
  30. //read()方法,一次讀取一個字符,並且自動往下讀。如果到達末尾則返回-1
  31. int ch = 0;
  32. while ((ch=fr.read())!=-1) {
  33. sop((char)ch);
  34. }
  35. sop(‘\n‘);
  36. fr.close();
  37. /*int ch = fr.read();
  38. sop("ch=" + (char)ch);
  39. int ch2 = fr.read();
  40. sop("ch2=" + (char)ch2);
  41. //使用結束註意關閉流
  42. fr.close(); */
  43. }
  44. catch (IOException e) {
  45. sop(e.toString());
  46. }
  47. }
  48. /**********************Println************************/
  49. private static void sop(Object obj) {
  50. System.out.print(obj);
  51. }
  52. }

示例3:對已有文件的數據進行續寫

  1. import java.io.*;
  2. class FileWriterDemo3 {
  3. public static void main(String[] args) {
  4. try {
  5. //傳遞一個參數,代表不覆蓋已有的數據。並在已有數據的末尾進行數據續寫
  6. FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true);
  7. fw.write(" is charactor table?");
  8. fw.close();
  9. }
  10. catch (IOException e) {
  11. sop(e.toString());
  12. }
  13. }
  14. /**********************Println************************/
  15. private static void sop(Object obj)
  16. {
  17. System.out.println(obj);
  18. }
  19. }



練習:

將F盤的一個文件復制到E盤。

思考:

其實就是將F盤下的文件數據存儲到D盤的一個文件中。

步驟:

1.在D盤創建一個文件,存儲F盤中文件的數據。
2.定義讀取流和F:盤文件關聯。
3.通過不斷讀寫完成數據存儲。
4.關閉資源。

源碼:

  1. import java.io.*;
  2. import java.util.Scanner;
  3. class CopyText {
  4. public static void main(String[] args) throws IOException {
  5. sop("請輸入要拷貝的文件的路徑:");
  6. Scanner in = new Scanner(System.in);
  7. String source = in.next();
  8. sop("請輸入需要拷貝到那個位置的路徑以及生成的文件名:");
  9. String destination = in.next();
  10. in.close();
  11. CopyTextDemo(source,destination);
  12. }
  13. /*****************文件Copy*********************/
  14. private static void CopyTextDemo(String source,String destination) {
  15. try {
  16. FileWriter fw = new FileWriter(destination);
  17. FileReader fr = new FileReader(source);
  18. char [] buf = new char[1024];
  19. //將Denmo中的文件讀取到buf數組中。
  20. int num = 0;
  21. while((num = fr.read(buf))!=-1) {
  22. //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
  23. fw.write(new String(buf,0,num));
  24. }
  25. fr.close();
  26. fw.close();
  27. }
  28. catch (IOException e) {
  29. sop(e.toString());
  30. }
  31. }
  32. /**********************Println************************/
  33. private static void sop(Object obj) {
  34. System.out.println(obj);
  35. }
  36. }

三、緩沖區

1. 字符流的緩沖區:BufferedReader和BufferedWreiter

* 緩沖區的出現時為了提高流的操作效率而出現的.

* 需要被提高效率的流作為參數傳遞給緩沖區的構造函數

* 在緩沖區中封裝了一個數組,存入數據後一次取出

BufferedReader示例:

讀取流緩沖區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。
readline()只返回回車符前面的字符,不返回回車符。如果是復制的話,必須加入newLine(),寫入回車符

newLine()是java提供的多平臺換行符寫入方法。

  1. import java.io.*;
  2. class BufferedReaderDemo {
  3. public static void main(String[] args) throws IOException {
  4. //創建一個字符讀取流流對象,和文件關聯
  5. FileReader rw = new FileReader("buf.txt");
  6. //只要將需要被提高效率的流作為參數傳遞給緩沖區的構造函數即可
  7. BufferedReader brw = new BufferedReader(rw);
  8. for(;;) {
  9. String s = brw.readLine();
  10. if(s==null) break;
  11. System.out.println(s);
  12. }
  13. brw.close();//關閉輸入流對象
  14. }
  15. }

BufferedWriter示例:

  1. import java.io.*;
  2. class BufferedWriterDemo {
  3. public static void main(String[] args) throws IOException {
  4. //創建一個字符寫入流對象
  5. FileWriter fw = new FileWriter("buf.txt");
  6. //為了提高字符寫入效率,加入了緩沖技術。
  7. //只要將需要被提高效率的流作為參數傳遞給緩沖區的構造函數即可
  8. BufferedWriter bfw = new BufferedWriter(fw);
  9. //bfw.write("abc\r\nde");
  10. //bfw.newLine(); 這行代碼等價於bfw.write("\r\n"),相當於一個跨平臺的換行符
  11. //用到緩沖區就必須要刷新
  12. for(int x = 1; x < 5; x++) {
  13. bfw.write("abc");
  14. bfw.newLine(); //java提供了一個跨平臺的換行符newLine();
  15. bfw.flush();
  16. }
  17. bfw.flush(); //刷新緩沖區
  18. bfw.close(); //關閉緩沖區,但是必須要先刷新
  19. //註意,關閉緩沖區就是在關閉緩沖中的流對象
  20. fw.close(); //關閉輸入流對象
  21. }
  22. }

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相同

    1. class MyBufferedReader1 extends Reader{
    2. private Reader r;
    3. MyBufferedReader1(Reader r){
    4. this.r = r;
    5. }
    6. //一次讀一行數據的方法
    7. public String myReaderline() throws IOException {
    8. //定義一個臨時容器,原BufferReader封裝的是字符數組。
    9. //為了演示方便。定義一個StringBuilder容器。最終要將數據變成字符串
    10. StringBuilder sb = new StringBuilder();
    11. int ch = 0;
    12. while((ch = r.read()) != -1)
    13. {
    14. if(ch == ‘\r‘)
    15. continue;
    16. if(ch == ‘\n‘) //遇到換行符\n,返回字符串
    17. return sb.toString();
    18. else
    19. sb.append((char)ch);
    20. }
    21. if(sb.length()!=0) //當最後一行不是以\n結束時候,這裏需要判斷
    22. return sb.toString();
    23. return null;
    24. }
    25. /*
    26. 需要覆蓋Reader中的抽象方法close(),read();
    27. */
    28. public void close()throws IOException {
    29. r.close();
    30. }
    31. public int read(char[] cbuf,int off, int len)throws IOException { //覆蓋read方法
    32. return r.read(cbuf,off,len);
    33. }
    34. public void myClose() throws IOException{
    35. r.close();
    36. }
    37. }

IO流上:概述、字符流、緩沖區