JAVA IO

  • 21457
  • 0
  • Java
  • 2014-01-29

摘要:JAVA IO

IO流用來處理設備之間的資料傳輸

Java對資料的操作是通過流的方式
Java用於操作流的物件都在IO包中
流分為兩種:位元組流與字元流
位元組流抽象類:InputStream,OutputStream
字元流抽象類:Reader,Writer
 
由這四個類衍生出來的子類名稱都是以其父類名作為子類名的尾碼。
如:InputStream的子類FileInputStream。
如:Reader的子類FileReader。
 
創建流物件,建立資料存放檔
FileWriter fw = new FileWriter(“Test.txt”); //如果已有相同名稱文件,則會被覆蓋
 
調用流物件的寫入方法,將資料寫入流
fw.write(“text”); //寫入資料到流緩衝中
 
刷新流的緩衝,寫入到目的檔案內,流可繼續使用
fw.flush();
 
關閉流資源,並將流中的資料清空到檔中,流不可繼續使用
fw.close();
 
ex:
import java.io.FileWriter;
import java.io.IOException;
public class Main {
    public static void main(String[] args)throws IOException{
        FileWriter fw = new FileWriter("123.txt");
        fw.write("123");
        fw.flush();
        fw.close();
    }
}
導入IO包中的類
進行IO異常處理
 
在finally中對流進行關閉
有了垃圾回收機制為什麼還要調用close方法進行關閉。
 
建立一個流物件,將已存在的一個檔載入進流。
FileReader fr = new FileReader(“Test.txt”);
創建一個臨時存放資料的陣列。
char[] ch = new char[1024];
調用流物件的讀取方法將流中的資料讀入到陣列中。
fr.read(ch);
 
ex:
import java.io.FileWriter;
import java.io.IOException;
public class Main {
    public static void main(String[] args){
       
        FileWriter fw = null;
        try{
            fw = new FileWriter("d:\\Test.txt");
            fw.write("text");
        }catch (IOException e){
            System.out.println(e.toString());
        }finally{      
            try{
                fw.flush();
                fw.close();
            }catch (IOException e){
                System.out.println(e.toString());
            }
        }
    }
}

 

建構子:
FileWriter(String filename)
FileWriter(String filename, boolean append)
若append為true則表示不覆蓋,附加在檔案內容後
若要輸入換行,則要為\r\n (windos環境下)
 
讀取:
        FileReader fr = null;
        try {
            fr = new FileReader("C:\\Test.txt");
            char[] buf = new char[1024];
            int len = 0;
            while ((len = fr.read(buf)) != -1) { //讀完時傳回-1
                System.out.println(new String(buf, 0, len));
            }
        } catch (IOException e) {
            System.out.println("read-Exception :" + e.toString());
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    System.out.println("close-Exception :" + e.toString());
                }
            }
        }
路徑需注意:
"C:\\eclipse_project\\Object_test\\Test.txt"
 
Reader方法:
public int read()      讀出字元,返回int型,讀到結尾傳回-1
public int read(char[] buf)  將字元讀入陣列中,讀到結尾傳回-1
 
複製檔案:
public class Main {
    public static void main(String[] args)throws IOException{
        copy();
    }
    public static void copy() throws IOException{
        FileWriter fw = new FileWriter("Cpoy.txt");
        FileReader fr = new FileReader("路徑");
       
        int ch = 0;
        while((ch = fr.read()) != -1){
            fw.write(ch);
        }
        fw.close();
        fr.close();
    }
}

 

加入緩衝copy
public class Main {
    public static void main(String[] args)throws IOException{
        copy();
    }  
    public static void copy(){
        FileWriter fw = null;
        FileReader fr = null;
           
        try{
            fw = new FileWriter("Copy2.txt");
            fr = new FileReader("c:\\Copy.txt");
               
            char[] buf = new char[1024];
            int len = 0;
               
            while((len = fr.read(buf)) != -1){
                fw.write(buf, 0, len);
            }
        }catch(IOException e){
            throw new RuntimeException("讀取失敗");
        }finally{
            if(fr != null){
                try{
                    fr.close();
                }catch(IOException e){
               
                }
            }
            if(fw != null){
                try{
                    fw.close();
                }catch(IOException e){
                   
                }
            }
        }
    }
}

 

 
緩衝區的出現提高了對資料的讀寫效率。
在創建緩衝區之前必須要先有流才可以使用,在流的基礎上對流的功能進行了增強
BufferedWriter、BufferedReader類別
public class Main {
    public static void main(String[] args)throws IOException{
        FileWriter fw = new FileWriter("Test.txt");
        BufferedWriter bufw = new BufferedWriter(fw);
       
        bufw.write("ABCDE"); //緩衝區一定要刷新
        bufw.newLine();
        bufw.write("FGHIJK");

        bufw.flush();
        bufw.close();
       
        FileReader fr = new FileReader("C:\\Test.txt");
        BufferedReader bufr = new BufferedReader(fr);
       
        String data = null;
       
        while((data = bufr.readLine()) != null){
            System.out.println("data = " + data);
        }
        bufr.close();
    }
}

 

newLine()跨平台的換行方法
readLine()一次讀取一行,不讀換行符號!
 
LineNumberReader類別可獲取文件中的行號
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;


public class Main {
    public static void main(String[] args)throws IOException{
        FileReader fr = new FileReader("C:\\Test.txt");
        LineNumberReader lnr = new LineNumberReader(fr);
       
        String line = null;
        while((line = lnr.readLine()) != null){
            System.out.println(lnr.getLineNumber() + ":"  + line);
        }
        lnr.close();
       
    }
}
位元組流
不僅可以操作位元組 ,還可以操作其他媒體檔,同樣是提高了位元組流的讀寫效率。
InputStreamReader,OutputStreamWriter為抽象類,透過操過其子類來使用
public class Main {
    public static void main(String[] args)throws IOException{
        writeFile();
        readFile();
        readFile_1();
    }
    public static void writeFile()throws IOException{
        FileOutputStream fos = new FileOutputStream("Test.txt");
        fos.write("123456789".getBytes());
        fos.close();
    }
    public static void readFile()throws IOException{
        FileInputStream fis = new FileInputStream("Test.txt");
       
        int ch = 0;
        while((ch = fis.read()) != -1){
            System.out.println((char)ch);
        }
        fis.close();
    }
    public static void readFile_1()throws IOException{
        FileInputStream fis = new FileInputStream("Test.txt");
        int num = fis.available(); //計算字元數 包含\r \n
        System.out.println(num);
        fis.close();
    }
}

 

byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1){   //若1024不夠會在循環讀
    …
}
 
將上面修改如下
byte[] buf = new byte[fis.available()];
定義一個剛剛好的緩衝區,可以不用再循環讀,可增加效率
 
複製一張圖片
  1. 用字元流讀取一張圖片
  2. 用字元寫入流物件產生一張圖片,用於儲存圖片數據
  3. 循環讀寫
  4. 關閉流
public class Main {
    public static void main(String[] args){
   
        FileOutputStream fos = null;
        FileInputStream fis = null;
   
        try{
            fos = new FileOutputStream("c:\\321.jpg");
            fis = new FileInputStream("c:\\123.jpg");
           
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = fis.read(buf)) != -1){
                fos.write(buf, 0, len);
            }
        }catch(IOException e){
            throw new RuntimeException("複製文件失敗");
        }finally{
            try{
                if(fis != null)
                    fis.close();
            }catch(IOException e){
                throw new RuntimeException("讀取關閉失敗");
            }
            try{
                if(fos != null)
                    fos.close();
            }catch(IOException e){
                throw new RuntimeException("寫入關閉失敗");
            }              
        }
    }
}

複製mp3文件

public class Main {
    public static void main(String[] args)throws IOException{
       
        long start = System.currentTimeMillis();
        copy_1();
        long end = System.currentTimeMillis();
        System.out.println((end - start) + "毫秒");
    }
    public static void copy_1() throws IOException{
        BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\123.mp3"));
        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\321.mp3"));
       
        int by = 0;
        while((by = bufis.read()) != -1){
            bufos.write(by);
        }
        bufis.close();
        bufos.close();     
    }
}

 

讀取鍵盤輸入
System.in的類型是InputStream預設輸入裝置是鍵盤、FileStream硬碟、ArrayStream記憶體
System.out的類型是PrintStream輸出設備是螢幕、FileStream硬碟、ArrayStream記憶體
 
import java.io.IOException;
import java.io.InputStream;

public class Main {
    public static void main(String[] args)throws IOException{
        InputStream in = System.in;

        StringBuilder sb = new StringBuilder();
        while(true){
            int ch = in.read();
            if(ch == '\r')
                continue;
            if(ch == '\n'){
                String s = sb.toString();
                if("over".equals(s))   //輸入over結束
                    break;
                System.out.println(s.toUpperCase());
                sb.delete(0, sb.length()); //緩衝區清空
            }
            else{
                sb.append((char)ch);
            }
        }
    }
}

 

改良,使用轉換流操作,目的是要使用到readLine()方法來簡化

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args)throws IOException{
        InputStream in = System.in;
       
        //將字節轉成字符流物件
        InputStreamReader isr = new InputStreamReader(in);
       
        BufferedReader bufr = new BufferedReader(isr);
       
        String line = null;
        while((line = bufr.readLine()) != null){
            if("over".equals(line))
                break;
            System.out.println(line.toUpperCase());
        }
        bufr.close();
    }
}

 

InputStreamReader是位元組串流通向字元串流的橋梁
最後改良
public class Main {
    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("over".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();
        }
        bufr.close();
    }
}

 

鍵盤輸入螢幕輸出
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
 
 
將鍵盤輸入內容輸出到文件中
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Test.txt")));
 
將文件內容輸出到console中
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("Test.txt")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
 
 
了解源和目的
源:   輸入流  InputStream 、Reader
目的: 輸出流  OuputStream、Writer
 
操作的數據是否是純文本
是 字符流 Writer、Reader
不是 字節流 InputStream、OutputStream
 
設備區分
源設備: 記憶體、硬碟、鍵盤
目的設備: 記憶體、硬碟、console
 
將輸出訊息儲存到文件中,日誌製作
轉換流的應用位元組流中的資料都是字元時,轉成字元流操作 更高效。
 
常式:標準輸入輸出
System類中的欄位:in,out。
它們各代表了系統標準的輸入和輸出設備。
.
是 OutputStream的子類FilterOutputStream 的子類.
例:獲取鍵盤錄入資料,然後將資料流程向顯示器,那麼顯示器就是目 的地。
通過System類的setIn,setOut方法對預設設備進行改變。
 
System.setIn(new FileInputStream(“1.txt”));//將源改成文件1.txt。
System.setOut(new FileOutputStream(“2.txt”));//將目的改成檔2.txt
 
系統訊息
import java.io.PrintStream;
import java.util.Properties;
public class Main {
    public static void main(String[] args) throws Exception{
        Properties prop = new Properties();
       
        //Systme.out.println(prop); 這一行是產生到console上
       
        prop.list(new PrintStream("sysinfo.txt")); //輸出系統訊息到sysinfo.txt檔
    }
}
File類別:
用來將文件或文件夾封裝成物件,方便對文件與文件夾的屬性訊息進行操作,File物件可以作為參數傳遞給流的建構子
public class Main {
    public static void main(String[] args) throws Exception{
        create();
    }
    public static void create()throws IOException{
        File f = new File("a.txt");
        //創建文件,如果文件已經存在,則不創建,返回false
        //和輸出流不一樣,輸出流創建文件,一旦存在就會覆蓋
        sop("create: " + f.createNewFile());
    }
    public static void sop(Object obj){
        System.out.println(obj);
    }
}

 

過濾副檔名來列出檔案

class Hello{
    public static void main(String[] args)throws Exception{
        File dir = new File("d:\\");
        //匿名內部類
        String[] arr = dir.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //依dir的副檔名來判斷
                return name.endsWith(".rar");
            }
        });
       
        System.out.println("len: " + arr.length);
        for(String name: arr){
            System.out.println(name);
        }
    }  
}

 

顯示某一目錄下所有檔案,包含目錄中的子檔案,使用遞迴呼叫

class Hello{
    public static void main(String[] args)throws Exception{
        File dir = new File("d:\\");
        showDir(dir);
    }  
    public static void showDir(File dir){
        File[] files = dir.listFiles();
        for(int x = 0; x < files.length; x++){
            if(files[x].isDirectory())
                showDir(files[x]);
            else {
                System.out.println(files[x]);
            }
        }
    }
}

 

改良加入層級顯示

class Hello{
    public static void main(String[] args)throws Exception{
        File dir = new File("d:\\");
        showDir(dir, 0);
    }  
    public static void showDir(File dir, int level){
       
        System.out.println(getLevel(level) + dir.getName());
        level++;
       
        File[] files = dir.listFiles();
        for(int x = 0; x < files.length; x++){
            if(files[x].isDirectory())
                showDir(files[x], level);
            else {
                System.out.println(getLevel(level) + files[x]);
            }
        }
    }
    public static String getLevel(int level){
        StringBuilder sb = new StringBuilder();
        for(int x = 0; x < level; x++){
            sb.append("|--");
        }
        return sb.toString();
    }
}

 

刪除一個帶內容的目錄,由裡面往外面刪除
class Hello{
    public static void main(String[] args)throws Exception{
        File dir = new File("d:\\test");
        removeDir(dir);
    }
    public static void removeDir(File dir){
        File[] files = dir.listFiles();
        for(int x = 0; x < files.length; x++){
            if(files[x].isDirectory())
                removeDir(files[x]);
            else {
                System.out.println(files[x].toString() + ":-file-:" + files[x].delete());
            }
        }
        System.out.println(dir + "::dir::" + dir.delete());
    }
}

由某一路徑下存儲所有檔案

class Hello{
    public static void main(String[] args)throws IOException{
        File dir = new File("d:\\123");
        List list = new ArrayList();
        fileToList(dir, list);
       
        File file = new File(dir, "123.txt");
        writeToFile(list, file.toString());
    }
    public static void fileToList(File dir, List list){
        File[] files = dir.listFiles();
       
        for(File file: files){
            if(file.isDirectory()){
                fileToList(file, list);
            }else{
                if(file.getName().endsWith("java")){
                    list.add(file);
                }
            }
        }
    }
    //將路徑下所有符合java檔案類型文件存入到123.txt檔中, 包含路徑+檔名
    public static void writeToFile(List list, String javaListFile)throws IOException{
        BufferedWriter bufw = null;
        try{
            bufw = new BufferedWriter(new FileWriter(javaListFile));
            for(File f: list){
                String path = f.getAbsolutePath();
                bufw.write(path);
                bufw.newLine();
                bufw.flush();
            }
        }catch(IOException e){
            throw e;
        }finally{
            try{
                if(bufw != null)
                    bufw.close();
            }catch (IOException e) {
                throw e;
            }
        }
    }
}
常用IO類別:
 
管道流
PipedInputStream和PipedOutputStream輸入輸出可以直接進行連接,通過結合執行緒使用。
 
列印流
PrintWriter與PrintStream可以直接操作輸入流和檔。
 
序列流
SequenceInputStream對多個流進行合併。
 
操作物件
ObjectInputStream與ObjectOutputStream被操作的物件需要實現Serializable (標記介面);
 
操作基底資料型別
DataInputStream與DataOutputStream

操作位元組陣列
ByteArrayInputStream與ByteArrayOutputStream

操作字元陣列
CharArrayReader與CharArrayWrite

操作字串
StringReader 與StringWriter

字元流的出現為了方便操作字元。
更重要是的加入了編碼轉換。
通過子類轉換流來完成。InputStreamReader  OutputStreamWriter

在兩個物件進行構造的時候可以加入字元集。
電腦只能識別二進位資料,早期由來是電信號。
為了方便應用電腦,讓它可以識別各個國家的文字。
就將各個國家的文字用數位來表示,並一 一對應,形成一張表。
這就是編碼表

 
 
可以將字元以指定編碼格式存儲
指定編碼表的動作由構造函數完成
 
編碼:      字串         ---->   位元組陣列
解碼:位元組陣列  ----->       字串
 
Properties類別
//Properties是hashtable子類 具備map集合特點 存儲鍵值對
//用於鍵值對形式的配置文件 數據需要有固定格式: 鍵 = 值
class Hello{
    public static void main(String[] args){
        setAndGet();
    }
    public static void setAndGet(){
        Properties prop = new Properties();
        prop.setProperty("kent", "30");
        prop.setProperty("lance", "15");
        //String value = prop.getProperty("kent");
        //System.out.println(value);
        Set names = prop.stringPropertyNames();
        for(String s: names){
            System.out.println(s + ":" + prop.getProperty(s));
            //lance:15 kent:30
        }
    }
}

 

讀取txt存入Properties

class Main{
    public static void main(String[] args)throws IOException{
        setAndGet();
    }
    /**讀入txt文件中鍵值進行操作
     * 1. 使用流與txt關聯
     * 2. 讀取一行數據 將該行數據用 "=" 切割
     * 3. 等號左邊為鍵 右邊為值 存入properties中*/
    public static void setAndGet() throws IOException{
        String path = "C:\\keyValueTest.txt";
        BufferedReader bufr = new BufferedReader(new FileReader(path));
        Properties p = new Properties();
        String line = null;
        while((line = bufr.readLine()) != null){
            String[] arr = line.split("=");
            p.setProperty(arr[0], arr[1]);
            System.out.println(line);
        }
        bufr.close();
        System.out.println(p);
    }
}

 

使用Properties類的load方法,載入檔案並修改後存入檔案

class Main{
    public static void main(String[] args)throws IOException{
        setAndGet();
    }
    public static void setAndGet() throws IOException{
        String path = "C:\\keyValueTest.txt";
        FileInputStream fis = new FileInputStream(path);
        Properties p = new Properties();
        p.load(fis);
        //p.list(System.out);//-- listing properties --//lance=30, kent=25, laker=50
       
        p.setProperty("laker", "111");//修改
       
        FileOutputStream fos = new FileOutputStream(path);
        p.store(fos , "TEST");
       
        System.out.println(p);
        fos.close();
        fis.close();
    }
}

 

//用於紀錄應用程式運行次數
//若使用次數已到,顯示註冊提示
//程序結束後會自動存值 下一次啟動時也要保存上次的値
class Main{
    public static void main(String[] args)throws IOException{
        Properties p = new Properties();
        File file = new File("c:\\propertiesDemo.ini");
        if(!file.exists()){
            file.createNewFile();//不存在則創造新檔案
        }
       
        FileInputStream fis = new FileInputStream(file);
        p.load(fis);
       
        int count = 0;
        String value = p.getProperty("time");
        if(value != null){
            count = Integer.parseInt(value);
            if(count >= 5){
                System.out.println("使用次數超過");
                return  ;
            }
        }
        count++;
        p.setProperty("time", count + "");
        FileOutputStream fos = new FileOutputStream(file);
        p.store(fos, "");
        fos.close();
        fis.close();   
    }
}

 

PrintStream 字串
提供了列印方法 可以將各種數據類型的數據輸出
建構子可接收的參數類型
1. file物件 File 
2. 字串路徑 String
3. 字串輸出流 OutputStream
 
PrintWriter 字元
建構子可接收的參數類型
1. file物件 File 
2. 字串路徑 String
3. 字串輸出流 OutputStream
4. 字元輸出流 Write
 
//輸入字母 轉大寫
class Main{
    public static void main(String[] args) throws Exception{
        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))
                break;
            out.println(line.toUpperCase());
            out.flush();
        }
        out.close();
        bufr.close();
    }
}

 

SequenceInputStream
將多個檔案流合併為一個再輸出
class Hello{
    public static void main(String[] args) throws IOException{
        Vector v = new Vector();
        v.add(new FileInputStream("c:\\1.txt"));
        v.add(new FileInputStream("c:\\2.txt"));
        v.add(new FileInputStream("c:\\3.txt"));
       
        Enumeration en = v.elements();
       
        SequenceInputStream sis = new SequenceInputStream(en);
        FileOutputStream fos = new FileOutputStream("c:\\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();
    }
}

 

切割檔案後,再合併

class Hello{
    public static void main(String[] args) throws IOException{
        splitFile();
        merge();
    }
   
    public static void splitFile() throws IOException{
        FileInputStream fis = new FileInputStream("G:\\1.MP3");
        FileOutputStream fos = null;
       
        byte[] buf = new byte[1024*1024];
       
        int len = 0;
        int count = 1;
        while((len = fis.read(buf)) != -1){
            fos = new FileOutputStream("G:\\spilt\\"+ (count++) +".part");
            fos.write(buf, 0, len);
            fos.close();
        }
        fis.close();
    }
   
    public static void merge() throws IOException{
        ArrayList al = new ArrayList();
        for(int x = 1; x < 5; x++){
            al.add(new FileInputStream("G:\\spilt\\"+ x +".part"));
        }
       
        final Iterator it = al.iterator();
        Enumeration en = new Enumeration() {
            public boolean hasMoreElements(){
                return it.hasNext();
            }
            public FileInputStream nextElement(){
                return it.next();
            }
        };
       
        SequenceInputStream sis = new SequenceInputStream(en);
        FileOutputStream fos = new FileOutputStream("G:\\spilt\\0.MP3");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = sis.read(buf)) != -1){
            fos.write(buf, 0, len);
        }
        fos.close();
        sis.close();
    }
}

 

ObjectInputStram,ObjectOutputStream
操作物件的流,需實現Serializable
class Hello{
    public static void main(String[] args)throws IOException, ClassNotFoundException{
        writeObj();
        readObj();
    }
    public static void writeObj()throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("G:\\obj.txt"));
        oos.writeObject(new Person("kent", 20));
        oos.close();
    }
    public static void readObj()throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("G:\\obj.txt"));
        Person p = (Person)ois.readObject();
        System.out.println(p);
        ois.close();
    }
}

class Person implements Serializable{
    public static final long serialVersionUID = 42L;
    String name;
    int age;
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return name + ":" + age;
    }
}

 

管道流
PipedInputStream、PipedOutputStream
輸入輸出可以直接進行連接,通過結合執行緒使用
class Hello{
    public static void main(String[] args)throws IOException{
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();
        in.connect(out);
        Read r = new Read(in);
        Write w = new Write(out);
        new Thread(r).start();
        new Thread(w).start();
    }
}

class Read implements Runnable{
    private PipedInputStream in;
    Read(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);
            in.close();
        }catch(IOException e){
            throw new RuntimeException("讀取失敗");
        }
    }
}

class Write implements Runnable{
    private PipedOutputStream out;
    Write(PipedOutputStream out){
        this.out = out;
    }
    public void run(){
        try{
            out.write("輸出此內容!".getBytes());
            out.close();
        }catch(IOException e){
            throw new RuntimeException("讀取失敗");
        }      
    }
}
RandomAccessFile
隨機訪問文件,自身具備讀寫
該類別不算是IO體系中子類而是直接繼承自Object
但是他是IO包中成員,因為他具備讀與寫功能,內部封裝了一個陣列,通過指標對數組的元素進行操作,可以通過getFilePointer獲取指標位置,同時可以通過seek改變指標位置
能完成讀寫的原理就是內部封裝了位元組流
 
通過建構子可以看出,該類只能操作文件,而且操作方式還有mode:  只讀(r)、讀寫(rw)
若該物件的建構子要操作的文件不存在,會自動創建,如果存在則不會覆蓋
 
模式為r,不會創建文件,會去讀取一個已存在文件,如果該文件不存在,則會出現異常
模式為rw,操作的文件不存在,會自動創建,如果存在則不會覆蓋
 
class Main{
    public static void main(String[] args) throws Exception{
        writeFile();
        read();
    }
    public static void writeFile() throws Exception{
        RandomAccessFile raf = new RandomAccessFile("d:\\test.txt", "rw");
        raf.write("kent".getBytes());
        raf.writeInt(97);
        raf.write("kobe".getBytes());
        raf.writeInt(97);
        raf.close();
    }
   
    public static void read()throws Exception{
        RandomAccessFile raf = new RandomAccessFile("d:\\test.txt", "r");
        //調整物件中的指標
        raf.seek(8); //跳過指定的字元數  raf.skipBytes(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();
    }
}

 

DataInputStream、DataOutputStream
可以用於操作基本數據類型的數據流物件
class Main{
    public static void main(String[] args) throws Exception{
        //writeData();
        //readData();
        writeUTF();
        readUTF();
    }
    public static void writeData() throws Exception{
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\test.txt")); 
        dos.writeInt(546);
        dos.writeBoolean(true);
        dos.writeDouble(154.12);
        dos.close();
    }
    public static void readData()throws Exception{
        DataInputStream dis = new DataInputStream(new FileInputStream("D:\\test.txt"));
        int num = dis.readInt();
        boolean b = dis.readBoolean();
        double d = dis.readDouble();
        System.out.println("num = " + num + ", b = " + b + ", d = " + d);
        dis.close();
    }
    public static void writeUTF() throws Exception{
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\UTF.txt"));
        dos.writeUTF("測試");
    }
    public static void readUTF() throws Exception{
        DataInputStream dis = new DataInputStream(new FileInputStream("D:\\UTF.txt"));
        String s = dis.readUTF();
        System.out.println(s);
    }
}

 

操作位元組
ByteArrayInputStream與ByteArrayOutputStream
ByteArrayInputStream在建構子時,需要接收數據源,而且數據源是ㄧ個位元組陣列
ByteArrayOutputStream在建構子時,不用定義數據源目的,因為該物件中已經內部封裝了可變長度的位元組陣列
因為這兩個流物件都操作的陣列,並沒有使用系統資源,所以不用進行close關閉
class Main{
    public static void main(String[] args) throws Exception{
        ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEF".getBytes());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
       
        int by = 0;
        while((by = bis.read()) != -1 ){
            bos.write(by);
        }
        System.out.println(bos.size());
        System.out.println(bos.toString());
    }
}

 

編碼表
ASCII:美國標準資訊交換碼。用一個位元組的7位元可以表示。
ISO8859-1:拉丁碼表。歐洲碼表用一個位元組的8位元表示。
GB2312:中文編碼表。
GBK:中文編碼表升級,融合了更多的中文字元。
Unicode:國際標準碼,融合了多種文字。所有文字都用兩個位元組來表示,Java語言使用的就是unicode
UTF-8:最多用三個位元組來表示一個字元。
 
轉換流
class Main{
    public static void main(String[] args) throws Exception{
        writeTest();
        readTest();
    }
    public static void writeTest() throws Exception{
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\UTF-8.txt"), "UTF-8");
        //"UTF-8" 每一个字占3Byte
        osw.write("测试");
        osw.close();
    }
    public static void readTest() throws Exception{
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\UTF-8.txt"), "UTF-8");
        char[] buf = new char[30];
        int len = isr.read();
        String str = new String(buf, 0, len);
        System.out.println(str);
        isr.close();
    }
}

 

編碼: 字串變成位元陣列
解碼: 位元陣列變成字串
//String -> byte[];   使用 str.getBytes(charsetName);
//byte[] -> String;   使用 new String(byte[], charsetName);
class Main{
    public static void main(String[] args) throws Exception{
        String s = "測試";
        byte[] b1 = s.getBytes("GBK");
        System.out.println(Arrays.toString(b1));//[-100, 121, -44, -121]
        byte[] b2 = s.getBytes("UTF-8");
        System.out.println(Arrays.toString(b2));//[-26, -72, -84, -24, -87, -90]
       
        String s1 = new String(b1, "GBK");
        System.out.println(s1);//測試
        String s2 = new String(b2, "UTF-8");
        System.out.println(s2);//測試
    }
}
//測試(GBK)寫    --->   ??(UTF-8)讀   ----|
//測試(GBK)讀    <---   ??(UTF-8)寫   <---|
//有5個學生 3門課
//從鍵盤輸入成績(姓名 成績)
//把結果依分數高低存入"stud.txt中"

/**
 * 1. 描述學生物件
 * 2. 定義一個可操作學生物件的工具類
 * 1. 通過獲取鍵盤輸入一行數據,並將該行中的訊息取出封裝成學生物件
 * 2. 使用集合(TreeSet)
 * 3. 將集合的訊息寫入到一個文件中
 * */

class Main{
    public static void main(String[] args) throws Exception{
        Comparator cmp = Collections.reverseOrder();
        Set stus = StudentInfoTool.getStudents();
        StudentInfoTool.writeToFile(stus);
    }
}

class Student implements Comparable{
    private String name;
    private int a, b, c;
    private int sum;
    Student(String name, int a, int b, int c){
        this.name = name;
        this.a = a;
        this.b = b;
        this.c = c;
        sum = a + b + c;
    }
    public String getName(){
        return name;
    }
    public int getSum(){
        return sum;
    }
    public int hashCode(){
        return name.hashCode() + sum*78;
    }
    public boolean equals(Object obj){
        if(!(obj instanceof Student)){
            throw new ClassCastException("非學生類");
        }
        Student s = (Student)obj;
        return this.name.equals(s.name) && this.sum == s.sum;
       
    }
    public String toString(){
        return "student[" + name + ", " + a + ", " + b + ", " + c+ "]";
    }
    public int compareTo(Student s){
        int num = new Integer(this.sum).compareTo((new Integer(s.sum)));
        if(num == 0)
            return this.name.compareTo(s.name);
        return num;
    }  
}

class StudentInfoTool{
    public static Set getStudents() throws Exception{
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        Set stus = new TreeSet();
        while((line = bufr.readLine()) != null){
            if("over".equals(line))
                break;
            String[] info = line.split(",");
            Student stu = new Student(info[0], Integer.parseInt(info[1]),
                    Integer.parseInt(info[2]), Integer.parseInt(info[3]));
            stus.add(stu);
        }
        bufr.close();
        return stus;
    }
    public static void writeToFile(Set stus) throws IOException{
        BufferedWriter bufw = new BufferedWriter(new FileWriter("D:\\stuinfo.txt"));
        for(Student stu: stus){
            bufw.write(stu.toString() + "\t");
            bufw.write(stu.getSum() + "");
            bufw.newLine();
            bufw.flush();
        }
    }
}