< 筆記 > Java SE - 06 Java SE IO

06 Java SE IO

By Kevin Song

  • 06-01 IO流概述
  • 06-02 字節流和字符流
    • 06-02-01 字符流
    • 06-02-02 字節流
    • 06-02-03 轉換流
    • 06-02-04 IO流的操作規律
  • 06-03 File類
  • 06-03-01 遞歸
  • 06-04 Properties集合
  • 06-05 其他IO類
    • 06-05-01 打印流
    • 06-05-02 序列流
    • 06-05-03 ObjectStream
    • 06-05-04 RandomAccessFile類
    • 06-05-05 管道流
    • 06-05-06 DataStream
    • 06-05-07 操作數組的流
    • 06-05-08 編碼表

06-01 IO流概述

概述

  • IO流用來處理設備之間的數據傳輸
  • Java對數據的操作是通過流的方式
  • Java用於操作流的對象都在IO包中

IO流對於內存設備而言

  • 輸入:把外設中的數據讀取到內存中
  • 輸出:把內存的數寫入到外設中

IO流分類

  • 流按操作數據分爲兩種
    • 字節流
    • 字符流
  • 流按流向分爲
    • 輸入流
    • 輸出流

06-02 字節流和字符流彙總

06-02-01 字符流

IO體系

  • 字節流的頂層父類
    • InputStream
      • FileInputStream
      • BufferedInputStream
    • OutputStream
      • FileOutputStream
      • BufferedOutputStream
  • 字符流的頂層父類
    • Reader
      • FileReader
      • BufferedReader
      • InputStreamReader 轉換流
    • Writer
      • FileWirter
      • BufferedWirter
      • OutputStreamWriter 轉換流

字符流特點:只能操作文字

字符流由來:字節流讀取文字字節數據後,不直接操作,而是先查指定的編碼表。獲取對應的文字,再對這個文字進行操作

字符流 = 字節流 + 編碼表

FileWirter類

定義:字符輸出流子類,其對象可以向文件中寫入字符數據

注意

  • 該類沒有空構造方法因爲往文件中寫入文字數據必須在創建對象時明確該文件
  • 如果文件不存在,自動創建
  • 如果文件已存在,自動覆蓋

方法

  • wirte(“Hello World!”) 寫入數據到臨時存儲緩衝區
  • flush() 刷新,把數據從臨時存儲緩衝區存儲到目的地
  • close() 關閉流,關閉資源,關閉前會調用flush刷新緩衝中的數據到目的地
public class FileWriter {
    public static void main(String[] args) {
        //創建一個可以往文件中寫入字符數據的字符輸出流對象
        //創建對象時必須初始化
        FileWriter fw = new FileWriter("JAVA.txt", true);
        //把數據寫入臨時存儲緩衝區
        fw.wirte("Hello World!");
        //刷新,將數據直接寫入目的地
        fw.flush();
        //關閉流,關閉資源,關閉前會調用flush刷新緩衝中的數據到目的地
        fw.close();
    }
}

細節

  • 換行:創建變量private static final String LINE_SEPARATOR = null; 進行換行
  • 續寫:在構造方法裏寫上true,可以在原有的文件上續寫
    • new FileWirter(“JAVA.txt”,true)

IO異常處理

public class FileWriter {
    public static void main(String[] args) {

        FileWriter fw = null
        try {
            new FileWriter("JAVA.txt", );
            fw.wirte("Hello World!");
        } catch(IOException e) {
            System.out.println(e.toString());
        } finally {
            if(fw != null)
            try {
                fw.close();
            } catch(IOException e) {
                throw new RuntimeException("關閉失敗");
            }
        }
    }
}

FileReader類

定義:字符輸出流子類,其對象可以讀取一個文本文件,並且打印到控制檯

注意

  • 該類沒有空構造方法因爲讀取文件的時候該文件必須存在
  • 其實就是用一個讀取流關聯一個已存在的文件
  • 讀取時一個read只能讀取一個字符

方法

  • 讀取方式
    • 讀取方式一 read() 讀取字符,一次只能讀一個
    • 讀取方式二 read(char []) 讀取字符,存入數組
  • close() 關閉流,關閉資源,關閉前會調用flush刷新緩衝中的數據到目的地

讀取方式一

public class FileWriter {
    public static void main(String[] args) {
        //創建讀取字符數據的流對象
        //一定要確定文件是存在的
        //用一個讀取流關聯一個已存在的文件
        FileReader fr = new FileReader("JAVA.txt");

        //用Reader中的read方法讀取字符
        int ch = fr.read();
        System.out.println(ch);
        //重複讀取
        while((ch=fr.read())!= -1) {
            System.out.println((char)ch);
        }
        fr.close;
    }
}

讀取方式二

public class FileWriter {
    public static void main(String[] args) {

        FileReader fr = new FileReader("JAVA.txt");
        //創建字符數組
        char[] buf = new char[3];
        //把讀取的數據存入數組
        int num = fr.read(buf);
        System.out.println(new String(buf));
        //重複讀取
        while((len=fr.read(buf)) != -1) {
            System.out.println(new String(buf,0,len ));
        }
    }
}

讀寫練習
複製一個文件到C盤

思路

  • 讀取源數據
  • 將讀取的數據寫入目的地
  • 用字符流操作文本數據

複製方式一

public class FileTest {
    public static void main(String[] args) throws IOExcepion {
        //讀取文本文件
        FileReader fr = new FileReader("JAVA.txt");
        //存儲文本文件
        FileWriter fw = new FileWirter("JAVA_COPY.txt");
        //重複讀取
        int ch = 0;
        while((ch=fr.read()) != -1) {
            fw.wirte(ch);
        }
        fr.close();
        fw.close();
    }
}

複製方式二

public class FileTest {
    private static final int BUFFER_SIZE = 1024;
    public static void main(String[] args) throws IOExcepion {

        FileReader fr = null;
        FileWirter fw = null;
        try {
            fr = new FileReader("JAVA.txt");
            fw = new FileWirter(JAVA_COPY.txt);
            //創建一個臨時容器
            char[] buf = new char[BUFFER_SIZE];
            //定義一個變量記錄讀取到的字符數
            int len = 0while((len=fr.read(buf)) != -1)
                fw.wirte(buf, 0, len);
        } catch(Excepion e) {
            throw new RuntimeException("讀寫失敗");
        } finally {
            if(fw != null)
                try {
                    fw.close;
                } catch(IOException e) {
                    e.printStackTrace();
                }
            if(fw != null)
                try {
                    fr.close;
                } catch(IOException e) {
                    e.printStackTrace();
                }
        }
    }
}

緩衝區

提高了IO流操作效率

  • BufferedReader
  • BufferedWirter

BufferWirter類

構造方法:傳入一個要被緩衝的流對象

常用方法

  • wirte:寫入
  • newLine():換行
  • flush:刷新
  • close:關閉,緩衝區關閉之後,被緩衝的流對象也被自動關閉
public class BufferWirterDemo {
    public static void main(String[] args) {
        //創建寫入流對象
        FileWriter fw = new FileWriter("buf.txt");
        //創建一個字符寫入流的緩衝區對象
        //緩衝區對象和要被緩衝的流對象關聯
        BufferedWriter bufw = new BufferedWriter(fw);

        bufw.write("abc");
        bufw.newLine();//換行
        bufw.write("def");

        bufw.flush();
        bufw.close();
    }
}

BufferReader類

構造方法:傳入一個要被緩衝的流對象

常用方法

  • read();讀取一個字符
  • readLine():讀取一整行
    • 原理:使用了讀取緩衝區的read方法,將讀取到的字符進行緩衝並判斷換行標記,返回標記前的緩存數據
public class BufferReaderDemo {
    public static void main(String[] args) {
        //創建讀取流對象
        FileReader fr = new FileReader("buf.txt");
        //創建一個字符讀取流的緩衝區對象
        //緩衝區對象和要被緩衝的流對象關聯
        BufferedReader bufr = new BufferedReader(fr);
        String line = null;
        while((line = bufr.readLine()) != null) {
            System.out.println(line);
        }
    }
}

緩衝區複製文件
方式一

public class CopyDemo {
    public static void main(String[] args) {
        FileReader fr = new FileReader("buf.txt");
        BufferedReader bufr = new BufferedReader(fr);

        FileWriter fw = new FileWriter("buf_copy.txt");
        BufferedWirter bufw = new BufferedWirter(fw);

        inc ch = 0;
        while((ch=bufr.read())!=-1) {
            bufw.write(ch);
        }
        bufw.close();
        bufr.close();
    }
}

方式二
一行一行復制

public class CopyDemo {
    public static void main(String[] args) {
        FileReader fr = new FileReader("buf.txt");
        BufferedReader bufr = new BufferedReader(fr);

        FileWriter fw = new FileWriter("buf_copy.txt");
        BufferedWirter bufw = new BufferedWirter(fw);

        String line = null;
        while((line=bufr.readLine())!= -1) {
            bufw.write(line);
        }
        bufw.close();
        bufr.close();
    }
}

自定義BufferReader

public class MyBufferReader {
    private FileReader r;
    //緩衝區全局數組
    private char[] buf = new charp[1024];
    //操作數組中元素指針
    private int pos = 0;
    //計數器:記錄緩衝區中的數據個數
    MyBufferedReader(FileReader r) {
        this.r = r;
    }
    public int myRead() throws IOException {
        If(count == 0) {
            count = r.read(buf);
            pos = 0;
        }
        if(count < 0)
            return -1;
        char ch = buf[pos++];
        count--;
        return ch;
        /*
        if(count==0) {
            count = r.read(buf);
            if(count < 0) {
                return -1;
            }
            pos = 0;//每次獲取數據到緩衝區後,角標歸零
            char ch = buf[pos];
            pos++;
            count--;
            return ch;
        } else if(count > 0) {
            char ch = buf[pos];
            pos++;
            count--;
            return ch;
        }
        */
    }
    public String myReadLine() {
        StringBuilder sb = new StringBuilder();
        int ch = 0;
        while((ch = myRead())!=-1) {
            if(ch == '\r') {
                continue;
            } else if(ch == '\n') {
                return sb.toString();
            } else {
                //從緩衝區中讀到的字符存儲到緩存行數據的緩衝區中
                sb.append((char)ch);
            }
        }
        return null;
    }
    public void myClose() {
        r.close();
    }
}

LineNumberReader類

作用:可以讀取行數

方法

  • setLineNumber():設置起始行數
  • readLine():整行讀取
  • close():關閉
public class LineNumberReaderDemo {
    public static void main(String[] args) {
        FileReader fr = new FileReader();
        LineNumberReader lnr = new LineNumberReader(fr);

        String line = null;
        //設置起始行數
        lnr.setLineNumber(1);
        while((line=lnr.readLine())!=null) {
            System.out.println(lnr.getLineNumber()+":"+line);
        }
        lnr.close(0;)
    }
}

裝飾設計模式

定義:對一組對象的功能進行增強的設計模式

特點:裝飾類和被裝飾類都必須所屬同一個接口或者父類

裝飾和繼承異同

  • 相同點:都能實現對象功能的增強
  • 不同點
    • 裝飾比繼承靈活

裝飾靈活性的體現

傳統繼承擴展

Writer

  • TextWriter:用於操作文本
    • BufferedTextWriter
  • MediaWriter:用於操作媒體
    • BufferedMediaWriter
  • WebWriter:用於操作網頁
    • BufferedWebWriter
  • ServerWriter:用於操作服務器
    • BufferedServerWriter

裝飾設計擴展

Writer

  • TextWriter:用於操作文本
  • MediaWriter:用於操作媒體
  • WebWriter:用於操作網頁
  • ServerWriter:用於操作服務器
  • BufferedWriter:提高效率
public class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person();
        EnhancedPerson p1 = new EnhancedPerson(p);
        p1.eat();
        EnhancedPerson2 p2 = new EnhancedPerson2();
        p2.eat();
    }
}
class Person {
    void eat() {
        System.out.println("Steak");
    }
}
//裝飾
class EnhancedPerson {
    private Person p;
    EnhancedPerson(Person p) {
        this.p = p;
    }
    public void eat() {
        System.out.println("Appetizer");
        p.eat();
        System.out.println("Dessert");

    }
}
//繼承
class EnhancedPerson2 extends Person{
    public void eat() {
        System.out.println("Appetizer");
        super.eat();
        System.out.println("Dessert");
    }
}

06-02-02 字節流

  • 字節流的頂層父類
    • InputStream
      • FileInputStream
    • OutputStream
      • FileOutputStream

常用方法

  • FileInputStream
    • read();
    • available(); 獲取字節長度
  • FileOutputStream
    • write()

字節流操作文件基本演示

public class ByteStreamDemo {
    public static void main(String[] args) {
        demo_read();
        demo_write();
    }
    public static void demo_read() {
        //創建字節讀取流對象,和指定文件關聯
        FileInputStream fis = new FileInputStream("bytedemo.txt");
        //一次讀取一個字節
        int ch = fis.read();
        System.out.println((char)ch);
        //全部讀取完畢
        int ch = 0;
        while((ch=fis.read())!=-1) {
            System.out.println((char)ch);
        }
        //用數組來讀取
        byte[] buf = new byte[1024];
        int len = 0;
        while((len=fis.read(buf))!=0) {
            System.out.println(new String(buf,0,len));
        }
        //用available()方法讀
        byte[] buf = new byte[fis.available()];
        fis.read(buf);
        System.out.println(new String(buf));
    }
    public static void demo_write() {
        //創建字節輸出流對象,用於操作文件
        FileOutputStream fos = new FileOutputStream("bytedemo.txt");
        //寫數據,直接寫入到目的地中
        fos.write("abc".getBytes());
    }
}

字節流讀取MP3練習

public class CopyDemo {
    public static void main(String[] args) {
        copy_1();
        copy_2();
        copy_3();
    }
    //1024字節複製一次
    public static void copy_1() throws IOException {
        FileInputStream fis = new FileInputStream("c:\\0.mp3");
        FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
        byte[] buf = new byte[1024];
        int len = 0;
        while((buf=fis.read())!=0) {
            System.out.println(new String(buf,0,len));
        }
    }
    //用Buffered的複製
    public static void copy_2() throws IOException {
        FileInputStream fis = new FileInputStream("c:\\0.mp3");
        BufferedInputStream bufis = new BufferedInputStream(fis);
        FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
        BufferedOutputStream bufos = new BufferedOutputStream(fos);

        int ch = 0;
        while((ch=bufis.read())!=-1) {
            bufos.write(ch);
            bufos.flush();
        }
        bufos.close();
        bufis.close();
    }
    public static void copy_3() throws IOException {
        FileInputStream fis = new FileInputStream("c:\\0.mp3");
        FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
        byte[] buf = new byte[fis.available()];
        fis.read(buf);
        fos.write(buf);
        fos.close();
        fis.close();
    }
}

IO流鍵盤輸入

鍵盤輸入演示

public class ReadKey {
    public static void main(String[] args) throws IOException {
        readKey1();
        readKey2();
    }
    public static void readKey1() throws IOException {
        //創建輸入流對象
        InputStream in = System.in;
        //讀取輸入流對象的內容
        int ch = in.read();
        System.out.println(ch);
    }
    public static void readKey2() throws IOException {
        inputStream in = System.in;
        int ch = 0;
        while((ch=in.read()!=-1)) {
            System.out.println(ch);
        }
    }
}

鍵盤錄入轉換成大寫

獲取用戶鍵盤錄入的數據,並且轉換成大寫顯示在控制檯上,exit退出錄入

思路

  • 因爲鍵盤錄入只讀取一個字節,要判斷是否是over,需要將讀取到的字節拼成字符串
  • 需要一個容器StringBuilder來存儲字符串
  • 回車之前把錄入的數據變成字符串判斷
public class ReadKey {
    public static void main(String[] args) throws IOException {
        readKey();
    }
    獲取用戶鍵盤錄入的數據,並且轉換成大寫顯示在控制檯上,exit退出錄入
    public static void readKey() throws IOException {
        //創建容器
        StringBuilder sb = new StringBuilder();
        //獲取鍵盤讀取流
        inputStream in = System.in;
        //定義變量記錄讀取到的字節,循環獲取
        int ch = 0;
        while((ch=in.read())!=-1) {
            if (ch=='\r')
                continue;
            if (ch=='\n') {
                String temp = sb.toString();
                    if("exit".equals(temp))
                        break;
                    System.out.println(temp.toUpperCase());
                    sb.delete(0,sb.length());
            } else {
                sb.append((char)ch);
            }
        }
    }
}

06-02-03 轉換流

  • InputStreamReader
    • 字節流 –> 字符流
    • 字節 解碼成 字符
  • OutputStreamWriter
    • 字符流 –> 字節流
    • 字符 編碼成 字節

作用

  • InputStreamReader:把字節流解碼成字符流,使其可以使用諸如readLine()之類的方法
  • OutputStreamWriter:把字符流編碼成字節流,進行輸出

轉換關係

這兩句代碼功能相同
FileWriter:相當於用了本機默認碼錶的轉換流。是一個便捷類

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");  
FileReader fr = new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"))   
FileWriter fw = new FileWriter("a.txt");

轉換流實現鍵盤錄入轉換成大寫

需求:鍵盤錄入數據顯示在控制檯上

public class TransStreamDemo {
    public static void main(String[] args) throws IOException {
        /*
        字節流獲取
        InputStream in = System.in; 
        字節流解碼成字符流
        InputStreamReader isr new InputStreamReader(in);
        字符流裝飾
        BufferedReader bufr = new BufferedReader(isr);
        */
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

        /*
        字節流
        OutputStream out = System.out;
        字符流編碼成字節流
        OutputStreamWriter osw = new OutputStreamWriter(out);
        字符流裝飾
        BufferedWriter bufw = new BufferedWriter(osw);
        */
        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));


        String line = null;
        while((line=bufr.readLine())!=null) {
            if("exit".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();
        }
    }
}

需求:鍵盤錄入數據寫入一個文件中

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"));

需求:文本文件內容顯示在控制檯上

BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out);

需求:文本文件內容寫入另一個文件中(複製)

BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"));

轉換關係

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");  
FileReader fr = new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"))   
FileWriter fw = new FileWriter("a.txt");

這兩句代碼功能相同
FileWriter:相當於用了本機默認碼錶的轉換流。是一個便捷類
如果要用別的編碼,必須使用轉換流。

用UTF-8寫

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), "UTF-8");

用UTF-8讀

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");  

轉換流使用場合

  • 源目對應的設備是字節流但是操作的確是文本數據,可以使用轉換作爲橋樑
  • 操作文本需要用制定編碼表時,必須使用轉換流

06-02-04 IO流的操作規律

四個明確

  • 明確源和目的(匯)

      • InputStream 字節流
      • Reader 字符流
    • 目的
      • OutputStream 字節流
      • Writer 字符流
  • 明確數據是否是純文本數據

      • 是純文本 Reader
      • 不是純文本 InputStream
    • 目的
      • 是純文本 Writer
      • 不是純文本 OutputStream
  • 明確據具體設備

      • 硬盤:File
      • 鍵盤:System.in
      • 內存:數組
      • 網絡:Socket流
    • 目的
      • 硬盤:File
      • 控制檯:System.out
      • 內存:數組
      • 網絡:Socket流
  • 是否需要額外功能
    • 是否需要高效(Buffer)
    • 是否需要轉換

需求體現

需求1:複製一個文本文件

  • 明確源目的
    • 源 InputStream Reader
    • 目的 OutputStream Writer
  • 是否純文本:是
    • 源:Reader
    • 目的:Writer
  • 明確設備
    • 源:硬盤File
      • FileReader fr = new FileReader(“a.txt”);
    • 目的:硬盤File
      • FileWriter fw = new FileWriter(“b.txt”);
  • 明確是否需要額外功能:需要高效
    • 源:
      • BufferedReader bufr = new BufferedReader(fr);
    • 目的:
      • BufferedWriter bufw = new BufferedWriter(fw);

需求2 鍵盤錄入數據,存入文件

  • 明確源目的
    • 源 InputStream Reader
    • 目的 OutputStream Writer
  • 是否純文本:是
    • 源:Reader
    • 目的:Writer
  • 明確設備
    • 源:鍵盤 System.in
      • InputStream in = System.in;
    • 目的:硬盤 File
      • FileWriter fw = new FileWriter(“b.txt”);
  • 明確是否需要額外功能:
    • 需要轉換
      • 源:
        • InputStreamReader isr = new InputStreamReader(System.in);
      • 目的:
        • FileWriter fw = new FileWriter(“b.txt”);
    • 需要高效
      • 源:
        • BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
      • 目的:
        • BufferedWriter bufw = new BufferedWriter(new FileWriter(“b.txt”));

需求3 讀取文本文件顯示在控制檯上

  • 明確源目的
    • 源 InputStream Reader
    • 目的 OutputStream Writer
  • 是否純文本:是
    • 源:Reader
    • 目的:Writer
  • 明確設備
    • 源:硬盤 File
      • FileReader fr = new FileReader(“a.txt”);
    • 目的:控制檯 System.out
      • OutputStream out = System.out;
  • 明確是否需要額外功能:
    • 需要轉換
      • 源:
        • FileReader fr = new FileReader(“a.txt”);
      • 目的:
        • OutputStreamWriter osw = new OutputStreamWriter(System.out);
    • 需要高效
      • 源:
        • BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
      • 目的:
        • BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

需求4 鍵盤錄入數據顯示在控制檯上

  • 明確源目的
    • 源 InputStream Reader
    • 目的 OutputStream Writer
  • 是否純文本:是
    • 源:Reader
    • 目的:Writer
  • 明確設備
    • 源:控制檯 System.in
      • InputStream in = System.in;
    • 目的:控制檯 System.out
      • OutputStream out = System.out;
  • 明確是否需要額外功能:中文一個字兩個字節,所以需要轉換成字符串操作
    • 需要轉換
      • 源:
        • InputStreamReader isr = new InputStreamReader(System.in);
      • 目的:
        • OutputStreamWriter osw = new OutputStreamWriter(System.out);
    • 需要高效
      • 源:
        • BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
      • 目的:
        • BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

06-03 File類

File類特點

  • 用來將文件或者文件夾封裝成對象
  • 方便對文件和文件夾的屬性信息進行操作
  • File對象可以作爲參數傳遞給流的構造方法

構造方法

  • 傳入一個字符串文件路徑
File file1 = new File("c:\\a.txt");
  • 傳入一個字符串文件夾路徑,一個文件名
File file2 = new File("c:\\", "a.txt");
  • 傳入一個文件對象,一個文件名
File f = new File("c:\\");
File file3 = new File(f, "a.txt");

分隔符的應用

File file4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
public class FileDemo {
    public static void main(String[] args) {
        constructiorDemo();
    }
    public static void constructiorDemo() {
        //可以將一個已存在的,或者不存在的文件或者目錄封裝成file對象
        File file1 = new File("c:\\a.txt");
        File file2 = new File("c:\\", "a.txt");
        File f = new File("c:\\");
        File file3 = new File(f, "a.txt");
        File file4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
    }
}

常用方法

  • 獲取
    • 獲取文件名稱:getName()
    • 獲取文件路徑
      • 獲取相對路徑:getAbsolutePath()
      • 獲取絕對路徑:getPath()
    • 獲取文件大小:getLength()
    • 獲取文件修改時間:lastModified()
public static void getDemo() {
    File file = new File("a.txt");
    String name = file.getName(); a.txt

    String absPath = file.getAbsolutePath(); C:\abc\a.txt //絕對路徑
    String path = file.getPath(); a.txt

    long len = file.length(); 123

    long time = file.lastModified(); 1236102144203
}
  • 創建與刪除
    • 創建刪除文件
      • boolean createNewFile()
        • 如果文件不存在,則創建
        • 如果文件存在,則不創建
      • boolean delete()
    • 創建刪除文件夾
      • 創建單級目錄
        • mkdir()
      • 創建多級目錄
        • mkdirs()
      • 刪除文件夾
        • boolean delete()
public static void createAndDeleteDemo() {
    File file = new File("file.txt");
    boolean a = file.createNewFile();
    System.out.println(a); true
    boolean b = file.delete();
    System.out.println(b); true
}
  • 判斷
    • 判斷是否存在 isDemo()
    • 判斷是否是文件 isFile()
    • 判斷是否是文件夾 isDirectory()
public static void isDemo() {
    File file = new File("aa.txt");
    boolean b = file.exists();
    System.out.println(b);true
}
  • 重命名
    • renameTo();
public static void isDemo() {
    File file1 = new File("aa.txt");
    File file2 = new File("bb.txt");
    file1.renameTo(file2);
}
  • 獲取系統根目錄
    • listRoots();
public static void listRootsDemo() {
    File[] file1 = File.listRoots();
    for(File file : files) {
        System.out.println(file);
    }
}
  • 獲取容量
    • getFreeSpace() 獲取空閒空間
    • getTotalSpace() 獲取總空間
    • getUsableSpace() 獲取已用空間
public static void getSpaceDemo() {
    File file = new File("d:\\");
    file.getFreeSpace();
    file.getTotalSpace();
    file.getUsableSpace();
}
  • 獲取目錄
    • String list()
      • file必須是一個目錄
      • 否則發生NullPointerException
      • 訪問系統級目錄也會發生空指針異常
      • 如果目錄沒有內容,會返回一個數組,長度爲0
      • 返回的是文件和文件夾名字
    • File listFiles()
      • 返回的是文件對象數組
public static void listDemo() {
    File file = new File("c:\\");
    String[] names = file.list();
    for(String name : names) {
        System.out.println(name);
    }
}
  • 過濾器

只要Java文件

public static void listDemo2() {
    File dir = new File("c:\\");
    String[] names = dir.list(new FilterByJava());
    for(String name : names) {
        System.out.println(name);
    }
}
public class FilterByJava implements FilenameFilter {
    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".java");
    }
}

自定義過濾器

public static void listDemo2() {
    File dir = new File("c:\\");
    String[] names = dir.list(new FilterByJava());
    for(String name : names) {
        System.out.println(name);
    }
}
public class SurffixFilter implements FilenameFilter {
    private String suffix;
    public SurffixFilter(String suffix) {
        super();
        this.suffix = suffix;
    }
    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".java");
    }
}

深度遍歷
列出所有文件和目錄

public class FileTest {
    public static void main(String[] aregs) {
        File dir = new File("e:\\demodir");
        listAll(dir);
    }
    public static void listAll(File dir) {
        System.out.println(getSpace(level)+dir.getName());
        level++;
        File[] files = dir.listFiles();
        for(int x = 0; x<files.length; x++) {
            if(files[x].idDirectory()) {
                listAll(files[x]);
            } else {
                System.out.println(getSpace(level)+files[x].getName());
            }
        }
    }
    private static String getSpace(int level) {
        StringBuilder sb = new StringBuilder;
        for(int x = 0; x<level; x++) {
            sb.append("     ");
        }
        return sb.toString();
    }
}

刪除所有文件和目錄
原理:從裏往外刪

public class FileDeleteTest {
    public static void main(String[] aregs) {
        File dir = new File("e:\\demodir");
        removeDir(dir);
    }
    public static void removeDir(File dir) {
        File[] files = dir.listFiles();
        for(File file : files) {
            if(file.isDirectory()) {
                removeDir(file);
            } else {
                file.delete();
            }
        }
        dir.delete();
    }
}

06-03-01 遞歸

定義:方法自身調用自身

注意

  • 遞歸一定要明確條件,否則容易棧溢出

轉成二進制

public static void toBinary(int num) {
    if(num>0) {
        System.out.println(num%2);
        toBinary(num/2);
    }
0
1
1
}
public static void toBinary(int num) {
    if(num>0) {
        toBinary(num/2);
        System.out.println(num%2);
    }
1
1
0
}

求和

public static int getSum(int num) {
    if(num == 1)
        return 1;
    return num+getSum(num-1);
}

求和棧內存圖解

int getNum(2 - 1) {
    if(1 == 1)
        return;                 1
    return 1 + getSum(1 - 1);
}
int getNum(3 - 1) {
    if(2 == 1)
        return;
    return 2 + getSum(2 - 1);   1+2
}
int getNum(4 - 1) {
    if(3 == 1)
        return;
    return 3 + getSum(3 - 1);   3+3
}
int getNum(5 - 1) {
    if(4 == 1)
        return;
    return 4 + getSum(4 - 1);   4+6
}
int getNum(5) {
    if(5 == 1)
        return;
    return 5 + getSum(5 - 1);   5+10
}

06-04 Properties集合

基本功能

  • Map
    • Hashtable
      • Properties
    • HashMap
    • TreeMap

Properties集合特點

  • 集合中的Key和Value都是字符串類型
  • 集合中的數據可以保存到流中,獲取從流中獲取數據

Properties集合作用:通常該集合用於操作該鍵值對形式存在的配置文件

  • 一 存取功能
    • setProperty
    • getProperty
public static void propertiesDemo() {
    //創建一個Properties集合
    Properties prop = new Properties();
    //儲存元素
    prop setProperty("Kevin", 24);
    prop setProperty("Tony", 21);
    prop setProperty("Brian", 19);
    prop setProperty("Peter", 29);
    //取出元素
    Set<String> names = prop.stringPropertyName();
    for(String name : names) {
        String value = prop.getProperty(name);
        System.out.println(name+":"+value);
    }
}
  • 二 list方法列出
public static void propertiesDemo() {
    //創建一個Properties集合
    Properties prop = new Properties();
    //儲存元素
    prop setProperty("Kevin", 24);
    prop setProperty("Tony", 21);
    prop setProperty("Brian", 19);
    prop setProperty("Peter", 29);
    //列出元素
    prop.list(System.out);
}
  • 三 store方法存儲
public static void propertiesDemo() {
    //創建一個Properties集合
    Properties prop = new Properties();
    //儲存元素
    prop setProperty("Kevin", 24);
    prop setProperty("Tony", 21);
    prop setProperty("Brian", 19);
    prop setProperty("Peter", 29);
    //儲存到文件中
    FileOutputStream fos = new FileOutputStream("info.txt");
    prop.store(fos,"name+age");
    fos.close();
}
  • 四 讀取文件,輸出到控制檯
public static void propertiesDemo() {
    //創建一個集合
    Properties prop = new Properties();
    //文件和輸入流綁定
    FileInputStream fis = new FileInputStream("info2.txt");
    //把文件加載進集合
    prop.load(fis);
    //輸出集合到控制檯
    prop.list(System.out);
}
//模擬load方法
public static void myLoad() {
    Properties prop = new Properties();
    BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
    String line = null;
    while((line=bufr.readLine())!=null) {
        if(line.startsWith("#")) {
            continue;
        } else {
            String[] arr = line.split("=");
            prop.setProperty(arr[0], arr[1]);
        }
    }
    bufr.close();
}
  • 五 對已有的配置文件進行修改

思路

  • 讀取文件
  • 把文件中的Key和Value數據存入集合
  • 通過集合修改Key和Value數據
  • 把修改後的數據存入文件
public static void propertiesDemo() {
    //文件封裝成對象
    File file = new File("info.txt");
    //判斷文件是否存在
    if(!file.exists()) {
        file.createNewFile();
    }

    //文件讀取
    FileReader fr = new FileReader(file);
    //創建集合存儲信息
    Properties prop = new Properties();
    //將流中信息存儲到集合中
    prop.load(fr);
    //修改數據
    prop.setProperties("Kevin", "24");
    //文件和輸出流綁定
    FileWriter fw = new FileWriter(file);
    //存儲修改後的數據
    prop.store(fw,"");

    fw.close();
    fr.close();
}

練習

練習一:獲取一個應用程序的運行次數,如果超過5次,給出使用次數已到請註冊的提示。並結束運行

思路

  • 計數器:每次程序啓動都計數一次
  • 計數器不能隨着程序的關閉而重置,所以儲存在硬盤裏
  • 計數器原理
    • 程序啓動時,先讀取
public class PropertiesTest {
    public static void main (String[] args) {

    }
    public static void getAppCount() {
        File confile = new File("count.properties");
        if(!confile.exists()) {
            confile.createNewFile();
        }
        FileInputStream fis = new FileInputStream(confile);
        Properties prop = new Properties();
        prop.load(fis);

        //從集合中通過Key獲取次數
        String value = prop.getProperty("time");
        //定義計數器,記錄獲取到的次數
        int count = 0;
        if(value!=null) {
            count = Integer.parseInt(value);
            if(count >= 5) {
                System.out.println("使用次數已到");
            }
        }
        count++;
        //改變後的次數重新存儲到集合中
        prop.setProperty("time",count+"");

        FileOutputStream fos = new FileOutputStream(confile);
        fos.close();
        fis.close();
    }
}

練習二:建立一個制定擴展名的文件的列表

思路:

  • 需要進行深度遍歷
  • 要在遍歷的過程中進行過濾,將符合條件的內容存儲到容器中
  • 對容器中的內容進行遍歷,並將絕對路徑寫入文件中
public class Test {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        File dir = new File("e:\\java0331");

        FilenameFilter filter = new FilenameFilter(){
            @Override
            public boolean accept(File dir, String name) {

                return name.endsWith(".java");
            }           
        };

        List<File> list = new ArrayList<File>();

        getFiles(dir,filter,list);

        File destFile = new File(dir,"javalist.txt");

        write2File(list,destFile);

    }
    /**
     * 對指定目錄中的內容進行深度遍歷,並按照指定過濾器,進行過濾,
     * 將過濾後的內容存儲到指定容器List中。
     * @param dir
     * @param filter
     * @param list
     */
    public static void getFiles(File dir,FilenameFilter filter,List<File> list){

        File[] files = dir.listFiles();

        for(File file : files){
            if(file.isDirectory()){
                //遞歸啦!
                getFiles(file,filter,list);
            }else{
                //對遍歷到的文件進行過濾器的過濾。將符合條件File對象,存儲到List集合中。 
                if(filter.accept(dir, file.getName())){
                    list.add(file);
                }
            }
        }

    }

    public static void write2File(List<File> list,File destFile)throws IOException{

        BufferedWriter bufw = null;
        try {
            bufw = new BufferedWriter(new FileWriter(destFile));
            for(File file : list){
                bufw.write(file.getAbsolutePath());
                bufw.newLine();
                bufw.flush();
            }


        } /*catch(IOException e){

            throw new RuntimeException("寫入失敗");
        }*/finally{
            if(bufw!=null)
                try {
                    bufw.close();
                } catch (IOException e) {

                    throw new RuntimeException("關閉失敗");
                }
        }
    }

}

06-05 其他IO類

06-05-01 打印流

  • PrintStream 字節
  • PrintWriter 字符

裝飾其它輸出流。它能爲其他輸出流添加了功能,使它們能夠方便地打印各種數據值表示形式。

PrintStream

特點

  • 提供了print方法,可以對多種數據類型值進行打印,並保持數據的表示形式
  • 不拋出IOException

構造方法:能接收三種類型的值

  • 字符串路徑 (String fileName)
  • File對象 (File file)
  • 字節輸出流 (OutputStream out)

方法

  • write(97)
    • 輸出a:只寫最低8位
  • print(97)
    • 輸出97:把97變成字符保持原樣將數據打印到目的地
public class PrintDemo {
    public static void main(String[] args) {
        PrintStream out = new PrintStream("print.txt");
        out.write(97); a
        out.print(97); 97
    }
}

PrintWriter

字符打印流

構造方法

  • 字符串路徑
  • File對象
  • 字節輸出流
  • 字符輸出流
public class PrintWriterDemo {
    public static void main(String[] args) {
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(System.out);
        String line = null;
        while((line = bufr.readLine())!=null) {
            if("over".equals(line))
                out.println(line.toUpperCase());
                out.flush();
        }
        out.close();
        bufr.close();
    }
}

06-05-02 序列流

SequenceInputStream

作用:把其他輸入流進行邏輯串聯

構造方法

  • SequenceInputStream(InputStream s1, InputStream s2)

低效率三個文件合成一個

public class SequenceInputStreamDemo {
    public static void main() {
        Vector<FileInputStream> v = new Vector<FileInputStream>)();

        v.add(new FileInputStream("1.txt"));
        v.add(new FileInputStream("2.txt"));
        v.add(new FileInputStream("3.txt"));

        Enumeration<FileInputStream> en = v.elements();

        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream("4.txt");

        byte[] buf = new byte[1024];

        int len = 0;

        while((len=sis.read(buf))!=-1) {
            fos.write(buf,0,len);
        }
        fos.close();
        sis.close();
    }
}

高效率三個文件合成一個

public class SequenceInputStreamDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {


        /*
         * 需求:將1.txt 2.txt 3.txt文件中的數據合併到一個文件中。
         */

//      Vector<FileInputStream> v = new Vector<FileInputStream>();      
//      v.add(new FileInputStream("1.txt"));
//      v.add(new FileInputStream("2.txt"));
//      v.add(new FileInputStream("3.txt"));
//      Enumeration<FileInputStream> en = v.elements();

        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for(int x=1; x<=3; x++){
            al.add(new FileInputStream(x+".txt"));
        }

        Enumeration<FileInputStream> en = Collections.enumeration(al);



        /*
        final Iterator<FileInputStream> it = al.iterator();
        Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){

            @Override
            public boolean hasMoreElements() {

                return it.hasNext();
            }

            @Override
            public FileInputStream nextElement() {

                return it.next();
            }

        };*/

        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream("1234.txt");

        byte[] buf = new byte[1024];

        int len = 0;

        while((len=sis.read(buf))!=-1){
            fos.write(buf,0,len);
        }

        fos.close();
        sis.close();

    }

}

文件切割合併

文件切割

  • 按照文件個數切
    • 切成固定等分
  • 按照文件大小切
    • 切成固定大小
public class SplitFileDemo {
    private static final int SIZE = 1024*1024;
    public static void main(String[] args) {
        File file = new File("c:\\0.bmp");
        splitFile(file);
    }
    public static void splitFile(File file) {
        //讀取流關聯文件
        FileInputStream fis = new FileInputStream(file);
        //定義一個1M的緩衝區
        byte[] buf = new byte[SIZE];
        //創建目的
        FileOutputStream fos = null;

        int len = 0;
        int count = 1;

        File dir = new File("c:\\partfiles");
        if(!dir.exists())
            dir.mkdirs();

        while((len=fis.read(buf))!=-1) {
            fos = new FileOutputStream(new File((count++)+".part"));
            fos.write(buf,0,len);
        }
        fos.close();
        fis.close();
    }
}

文件合併

public class MergeFile {
    public static void static main(String[] args) {
        File dir = new File("c:\\partfiles");
        mergeFile(fir);
    }
}
public static void mergeFile(File dir) {
    ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();

    for (int x = 1; x <= 3; x++) {
        a1.add(new FileInputStream(new File(dir, x+".part")));
    }

    SequenceInputStream sis = new SequenceInputStream(en);

    FileOutputStream fos = new FileOutputStream(new File(dir, "1.bmp"));

    byte[] buf = new byte[1024];

    int len = 0;
    while((len = fos.read(buf))!= -1) {
        fos.write(buf,0,len);
    }
    fos.close();
    sis.close();
}

文件切割合併

public class SplitFileDemo {
    private static final int SIZE = 1024 * 1024;
    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        File file = new File("c:\\aa.mp3");
        splitFile_2(file);
    }
    private static void splitFile_2(File file) throws IOException {
        // 用讀取流關聯源文件。
        FileInputStream fis = new FileInputStream(file);
        // 定義一個1M的緩衝區。
        byte[] buf = new byte[SIZE];
        // 創建目的。
        FileOutputStream fos = null;
        int len = 0;
        int count = 1;
        /*
         * 切割文件時,必須記錄住被切割文件的名稱,以及切割出來碎片文件的個數。 以方便於合併。
         * 這個信息爲了進行描述,使用鍵值對的方式。用到了properties對象
         * 
         */
        Properties prop  = new Properties();

        File dir = new File("c:\\partfiles");
        if (!dir.exists())
            dir.mkdirs();
        while ((len = fis.read(buf)) != -1) {
            fos = new FileOutputStream(new File(dir, (count++) + ".part"));
            fos.write(buf, 0, len);
            fos.close();
        }
        //將被切割文件的信息保存到prop集合中。
        prop.setProperty("partcount", count+"");
        prop.setProperty("filename", file.getName());
        fos = new FileOutputStream(new File(dir,count+".properties"));
        //將prop集合中的數據存儲到文件中。 
        prop.store(fos, "save file info");
        fos.close();
        fis.close();
    }
}
    public static void mergeFile_2(File dir) throws IOException {
        /*
         * 獲取指定目錄下的配置文件對象。
         */
        File[] files = dir.listFiles(new SuffixFilter(".properties"));
        if(files.length!=1)
            throw new RuntimeException(dir+",該目錄下沒有properties擴展名的文件或者不唯一");
        //記錄配置文件對象。
        File confile = files[0];


        //獲取該文件中的信息================================================。

        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream(confile);

        prop.load(fis);

        String filename = prop.getProperty("filename");     
        int count = Integer.parseInt(prop.getProperty("partcount"));

        //獲取該目錄下的所有碎片文件。 ==============================================
        File[] partFiles = dir.listFiles(new SuffixFilter(".part"));

        if(partFiles.length!=(count-1)){
            throw new RuntimeException(" 碎片文件不符合要求,個數不對!應該"+count+"個");
        }
        //將碎片文件和流對象關聯 並存儲到集合中。 
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for(int x=0; x<partFiles.length; x++){
            al.add(new FileInputStream(partFiles[x]));
        }
        //將多個流合併成一個序列流。 
        Enumeration<FileInputStream> en = Collections.enumeration(al);
        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream(new File(dir,filename));

        byte[] buf = new byte[1024];

        int len = 0;
        while((len=sis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        fos.close();
        sis.close();
    }

06-05-03 ObjectStream

ObjectStream

  • ObjectOutputStream
    • ObjectOutputStream把Java對象的基本數據類型和圖形通過序列化的方式寫入硬盤
  • ObjectInputStream
    • ObjectInputStream可以通過反序列化的方式讀取對象

序列化

  • 對象通過序列化永久存儲到硬盤,實現持久化

反序列化

  • 通過反序列化讀取硬盤上的對象進內存

注意

  • 被序列化的對象的類必須實現Serializable接口
  • Serializable是標記接口
  • 一般擴展名爲 .object
public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException {
        writeObj();
        readObj();
    }
    public static void writeObj() throws IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
        oos.writeObject(new Person("Steve", 30));
        oos.close();
    }
    public static void readObj() throws IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInpuStream("obj.object"));
        Person obj = (Person)ois.readObject();
        System.out.println(p.getName()+":"+p.getAge());
    }
}

Serializable接口

作用:用於給被序列化的類加入ID號(serialVersionUID)用於判斷類和對象是否是同一版本

注意:如果不自定義UID,系統會默認使用UID,不過如果被序列化的對象的類被改變就會改變UID而導致無法被反序列化

自定義ID號

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

transient關鍵字 transient修飾的非靜態數據,不可以被序列化

06-05-04 RandomAccessFile類

特點

  • 該對象可以讀寫
  • 該對象內部維護了一個byte數組,並通過指針可以操作數組中的元素
  • 可以通過getFilePointer方法獲取指針的位置,通過seek方法設置指針的位置
  • 該對象把字節輸出流輸入流進行了封裝
  • 該對象的目的只能是文件

常見方法

  • 寫入
    • 如果文件不存在,則創建
    • 如果文件存在,不創建
public class RandomAccessFileDemo {
    public static void main(String[] args) {
        writeFile();
    }
    //使用RandomAccessFile對象寫入一些人員信息
    public static void writeFile() throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");
        raf.write("Tony".getBytes());
        raf.write(97);
        raf.write("Steve".getBytes());
        raf.write(97);

        raf.close();
    }
    public static void readFile() throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ranacc.txt","r");
        //通過seek設置指針位置
        ref.seek(1*8);//隨機的讀取,指定指針的位置即可

        byte[] buf = new byte[4];
        raf.read(buf);

        String name = new String(buf);
        int age = raf.readInt();

        System.out.println("name="+name);
        System.out.println("age="+age);

        raf.close();
    }
}

隨機寫入
用seek方法設置寫入位置

public static void randomWrite() throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ranacc.txt","r");
        //從指定位置開始寫入
        raf.seek(3*8);//從第三個八位開始寫
        raf.write("Steve".getBytes());
        raf.writeInt(102);

        raf.close();
    }

06-05-05 管道流

PipedStream

  • PipedInputStream
  • PipedOutputStream
public class PipedStream {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        PipedInputStream input = new PipedInputStream();
        PipedOutputStream output = new PipedOutputStream();

        input.connect(output);

        new Thread(new Input(input)).start();
        new Thread(new Output(output)).start();
    }
}
class Input implements Runnable{
    private PipedInputStream in;
    Input(PipedInputStream in){
        this.in = in;
    }
    public void run(){
        try {
            byte[] buf = new byte[1024];
            int len = in.read(buf);

            String s = new String(buf,0,len);

            System.out.println("s="+s);
            in.close();
        } catch (Exception e) {
            // TODO: handle exception
        }

    }
}
class Output implements Runnable{
    private PipedOutputStream out;
    Output(PipedOutputStream out){
        this.out = out;
    }
    public void run(){
        try {
            Thread.sleep(5000);
            out.write("hi,管道來了!".getBytes());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

06-05-06 DataStream

操作基本數據類型的流對象

public class DataSteamDemo {
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
//      writeData();
        readData();

    }
    public static void readData() throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

        String str = dis.readUTF();

        System.out.println(str);
    }
    public static void writeData() throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

        dos.writeUTF("你好");

        dos.close();
    }
}

06-05-07 操作數組的流

操作字節數組的流

  • ByteArrayStream
    • ByteArrayInputStream
    • ByteArrayOutputStream

操作字符數組的流

  • CharArrayReader
  • CharArrayWriter

操作字符串

  • StringReader
  • StreamWriter

ByteArrayStream

public class ByteArrayStreamDemo {
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) {
        ByteArrayInputStream bis = new ByteArrayInputStream("abcedf".getBytes());

        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        int ch = 0;

        while((ch=bis.read())!=-1){
            bos.write(ch);
        }
        System.out.println(bos.toString());
    }
}

06-05-08 編碼表

常見的編碼表

  • ASCII:美國標準信息交換碼
    • 用一個字節的7位可以表示
  • ISO8859-1:歐洲碼錶
    • 用一個字節的8位表示
  • GB2312:中國的中文編碼表
  • GBK:中國的中文編碼表,融合了更多的中文符號
  • Unicode:國際標準碼錶
    • 所有文字都用兩個字節來表示,Java語言就是用的Unicode
  • UTF-8:8-bit Unicode Transformation Format最多用三個字節表示一個字符

簡單的編碼解碼

  • 字符串 –> 字節數組 編碼
  • 字節數組 –> 字符串 解碼
public class EncodeDemo {
    public static void main(String[] args) {
        String str = "你好";
        //你好:GBK -60 -29 -70 -61
        //你好:UTF-8 -28 -67 -96 -27 -91 -67
        //編碼
        byte[] buf = str.getBytes(“utf-8”);
        printBytes(buf);
        //解碼
        String s1 = new String(buf);
    }

    private static vodi printBytes(byte[] buf) {
        for(byte b : buf) {
            System.out.println(b);
        }
    }
}
public class EncodeDemo {
    public static void main(String[] args) throws IOException {
            /*
             * 字符串 --> 字節數組:編碼。
         * 字節數組 --> 字符串:解碼。
         * 
         * 你好:GBK:  -60 -29 -70 -61
         * 
         * 你好: utf-8: -28 -67 -96 -27 -91 -67 
         * 
         * 如果你編錯了,解不出來。
         * 如果編對了,解錯了,有可能有救。
         */
        String str = "謝謝";

        byte[] buf = str.getBytes("GBK");//用GBK編碼
        String s1 = new String(buf,"UTF-8");//用UTF-8解碼
        System.out.println("s1="+s1);//解碼失敗,用特殊編碼表示原來的編碼
        byte[] buf2 = s1.getBytes("UTF-8");//獲取源字節.
        printBytes(buf2);

        String s2 = new String(buf2,"GBK");//用GBK解碼
        System.out.println("s2="+s2);//有可能可以解碼
//      encodeDemo(str);
    }
    /**
     * @param str
     * @throws UnsupportedEncodingException
     */
    public static void encodeDemo(String str)
            throws UnsupportedEncodingException {
        //編碼;
        byte[] buf = str.getBytes("UTF-8");
//      printBytes(buf);
        //解碼:
        String s1 = new String(buf,"UTF-8");
        System.out.println("s1="+s1);
    }
    private static void printBytes(byte[] buf) {
        for(byte b : buf){
            System.out.print(b +" ");
        }
    }
}

聯通問題
聯通這兩個字的UTF-8和GBK的編碼一樣,所以導致GBK編碼的聯通系統會自動用UTF-8解碼,導致亂碼

public class LianTong {
    public static void main(String[] args) throws IOException {
    String str = "聯通";
    /*
    11000001
    10101010
    11001101
    10101000
    */
    byte[] buf = str.getBytes("gbk");
    for(byte b :buf){
        System.out.println(Integer.toBinaryString(b&255));
    }
    }
}

按字節截取字符串

在java中,字符串“abcd”與字符串“ab你好”的長度是一樣,都是四個字符。但對應的字節數不同,一個漢字佔兩個字節。
定義一個方法,按照最大的字節數來取子串。如:對於“ab你好”,如果取三個字節,那麼子串就是ab與“你”字的半個,那麼半個就要捨棄。如果去四個字節就是“ab你”,取五個字節還是“ab你”.

public class Test {
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        String str = "ab你好cd謝謝";
//      str = "ab琲琲cd琲琲";
//      int len = str.getBytes("gbk").length;       
//      for(int x=0; x<len; x++){
//          System.out.println("截取"+(x+1)+"個字節結果是:"+cutStringByByte(str, x+1));
//      }
        int len = str.getBytes("utf-8").length;     
        for(int x=0; x<len; x++){
            System.out.println("截取"+(x+1)+"個字節結果是:"+cutStringByU8Byte(str, x+1));
        }
//      String str = "琲";
//      byte[] buf = str.getBytes("gbk");
//      for(byte b : buf){
//          System.out.println(b);//-84  105 
//      }
    }
    /*

     */
    public static String cutStringByU8Byte(String str, int len) throws IOException {
        byte[] buf = str.getBytes("utf-8");
        int count = 0;
        for(int x=len-1; x>=0; x--){
            if(buf[x]<0)
                count++;
            else
                break;
        }
        if(count%3==0)
            return new String(buf,0,len,"utf-8");
        else if(count%3==1)
            return new String(buf,0,len-1,"utf-8");
        else 
            return new String(buf,0,len-2,"utf-8");

    }
    public static String cutStringByByte(String str,int len) throws IOException{

        byte[] buf = str.getBytes("gbk");

        int count = 0;
        for(int x=len-1; x>=0; x--){
            if(buf[x]<0)
                count++;
            else
                break;
        }
        if(count%2==0)
            return new String(buf,0,len,"gbk");
        else
            return new String(buf,0,len-1,"gbk");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章