Java基礎——I/O流簡介(待續)

IO流用來處理設備之間的數據傳輸。

  • 流按流向分爲:輸入流、輸出流。
    輸入流、輸出流相對於內存設備而言。將外設中的數據讀取到內存:輸入;將內存的數據寫入到外設中:輸出。
  • 流按操作數據不同分爲兩種:字節流、字符流

字節流:通用流。
字符流:基於字節流。由來:字節流讀取文字字節數據後,不直接操作而是先查指定的編碼表,獲取對應的數字,在對該文字進行操作。
ASCII:英文編碼表
GB2312/GBK:中文編碼表
UTF-8:國際通用碼錶
如果對一臺計算機使用GBK編碼存儲,那麼另一臺UTF-8的機器無法識別正確的文字,並顯示亂碼。因此,字符流可以指定編碼方式來獲取對應的文字。

二、I/O流常用基類

字符流

字節流的抽象基類:InputStream,OutputStream
字符流的抽象基類:Reader,Writer
P.S. 有着四個類派生出的子類名稱都是以其父類名作爲子類名的後綴。如InputStream的子類FileInputStream,如Reader的子類FileReader。

需求:將一些文字存儲到硬盤一個文件中。
注意:如果要操作文字數據,建議優先考慮字符流。使用FileWriter。

import java.io.*;
class FileWriterDemo throws IOException {
    public static void main(String[] args) {
        //該文件會被創建到指定目錄下。如果文件存在,則會被覆蓋。
        FileWriter fw = new FileWriter("demo.txt");
        //將數據寫入到臨時存儲緩衝區中
        fw.write("abcde");
        //刷新該流的緩衝,將臨時存放的數據寫入到目的地
        //如果不寫,則要等到緩衝區滿纔會寫入目的地
        fw.flush();
        //關閉流,關閉資源,釋放內存
        fw.close();
    }
}

I/O異常處理

import java.io.*
class FileWriterDemo2 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("abcdefg");
        } catch(IOException e) {
            System.out.println("catch:" + e.toString());
        } finally {
            try {
                if(fw != null)
                    fw.close();
            } catch(IOException e) {
                System.out.println(e.toString());
            }
        }
    }
}

對已有文件的數據續寫

import java.io.*
class FileWriterDemo3 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            //true參數,代表不覆蓋已有的文件,在已有文件的末尾處進行數據讀寫
            fw = new FileWriter("demo.txt", true);
            fw.write("hello\r\n"thanks); //記事本中按\r\n換行
        } catch (IOException e) {
            System.out.println("catch:" + e.toString());
        } finally {
            try {
                if(fw != null)
                    fw.close();
            } catch(IOException e) {
                System.out.println(e.toString());
            }
        }           
    }
}

需求:讀取一個文件,將讀取到的字符打印到控制檯。
第一種讀取方式:read()方法讀取文本文件數據

import java.io.*
public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        //創建一個文件讀取流對象
        //如果文件不存在,會拋出FileNotFountException
        FileReader fr = new FileReader("demo.txt");
        //調用讀取流對象的read()方法
        //read():一次讀一個字符,而且會自動往下讀。如果已到達流的末尾,則返回-1
        int ch = 0;
        while((ch = fr.read()) != -1) {
            System.out.println((char)ch);
        }
        fr.close;
    }
}

第二種讀取方式:使用read(char[])讀取文本文件數據

import java.io.*
public class FileReaderDemo2 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("demo.txt");
        char[] buf = new char[1024];
        int num = 0;
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf,0,num));
        }
        fr.close;
    }
}

打印一個.java文件,並打印在控制檯上

import java.io.*
class FileReaderTest throws IOException {
    public static void main(String[] args) {
        FileReader fr = new FileReader("DateDemo.java");
        char[] buf = new char[1024];
        int num = 0;
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf,0,num));
        }
        fr.close();
    }
}

將C盤一個文本文件複製到D盤
複製的原理:將C盤下的文件數據存儲到D盤的一個文件中。
步驟:
1、在D盤創建一個文件,用於存儲C盤文件的數據
2、定義讀取流和C盤文件關聯
3、通過不斷讀寫完成數據存儲
4、關閉資源

import java.io.*
class CopyText throws IOException {
    public static void main(String[] args) {
        FileWriter fw = null;
        FileReader fr = null;
        try {
            fw = new FileWriter("D:\\SystemDemo_copy.txt");
            fr = new FileReader("C:\\SystemDemo.java");

            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) {
                    e.printStackTrace();
                } 
            }
            if(fw != null) {
                try {
                    fw.close();
                } catch(IOException e) {
                    e.printStackTrace();
                } 
            }
        }
    }
}

字符流的緩衝區
緩衝區的出現提高了對數據的讀寫效率。
對應的類:BufferedWriter,BufferedReader

寫入緩衝區

FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bw = new BufferedWriter(fw);
for(int i=1; i<5; i++) {
    bw.write("abcd" + x);
    bw.newLine(); //跨平臺的換行符
    bw.flush(); //只要用到緩衝區,就要刷新
}
//關閉緩衝區,就是在關閉緩衝區中的流對象,故不需要寫fw.close()
bw.close(); 

讀取緩衝區

FileReader fr = new FileReader("buf.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
    System.out.println(line);
}
br.close();

使用緩衝區複製文本文件

BufferedReader br = null;
BufferedWriter bw = null;
try {
    br = new BufferedReader(new FileReader("xxx.java"));
    bw = new BufferedWriter(new FileWriter("xxx_copy.txt"));
    String line = null;
    while((len = br.readLine()) != null) {
        bw.write(line);
        bw.newLine(); //readLine方法返回時,只返回回車符之前的數據內容,並不返回回車符,故要加上newLine()
        bw.flush();
    }
} catch (IOException e) {
    throw new RuntimeException("讀寫失敗");
} finally {
    try {
        if(br != null) {
            br.close();
        } catch(IOException e) {
            throw new RuntimeException("讀取關閉失敗");
        }
    }
    try {
        if(bw != null) {
            bw.close();
        } catch(IOException e) {
            throw new RuntimeException("寫入關閉失敗");
        }
    }
}

寫入換行使用BufferedWriter類中的newLine()方法。
讀取一行數據使用BufferedReader類中的readLine()方法。

原理: 使用了讀取緩衝區的read方法, 將讀取到的字符進行緩衝並判斷換行標記, 將標記前的緩衝數據變成字符串返回。

字節流

基本操作與字符流類相同。但它不僅可以操作字符,還可以操作其它媒體文件。
InputStream,OutputStream

需求:操作圖片數據

public static void writeFile throws IOException() {
    FileOutputStream fos = new FileOutputStream("fos.txt");
    //數據直接寫到了目的地中
    fos.write("abcde".getBytes());
    //字節流不需要刷新
    fos.close();
}

public static void writeFile throws IOException() {
    FileInputStream fis = new FileInputStream("xxx.txt");
    byte[] buf = new byte[1024];
    int len = 0;
    while((len = fis.read(buf)) != -1) {
        System.out.println(new String(buf,0,len));
    }
    fis.close();
}

複製一個圖片
思路:
1、用字節流讀取對象和圖片關聯
2、用字節寫入流對象創建一個圖片文件,用於存儲獲取到的圖片數據
3、通過循環讀寫,完成數據的存儲
4、關閉資源

class CopyPic {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("c:\\1.bmp");
            fos = new FileOutputStream("c:\\2.bmp");
            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的複製,通過緩衝區
BufferedOutputStream
BufferedInputStream

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by = bis.read()) != -1) {
    bos.write(by);
}
bos.close();
bis.close();

轉換流
InputStreamReader
字節流通向字符流的橋樑。解碼。在構造時接受一個字節流。

讀取轉換流:
需求:當錄入一行數據後,就將該行數據進行打印。如果錄入的數據是over,那麼停止錄入。

//獲取鍵盤錄入對象
InputStream in = System.in;
//將字節流轉換成字符流對象
InputStreamReader isr = new InputStreamReader(in);
//爲了提高效率,將字符串進行緩衝區技術高效操作,使用BufferedReader
BufferedReader br = new BufferedReader(isr);
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;  
    System.out.println(line.toUpperCase());
}
br.close();

寫入轉換流:
OutputStreamWriter
字符通向字節的橋樑。編碼。在構造時接收一個輸出流。

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush(); //務必寫上
}
br.close();

需求:將鍵盤錄入的數據寫入到一個文件中。

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush();
}

需求:將一個文件的數據打印在控制檯上。

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx.java")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush();
}

流操作的基本規律
通過兩個明確來完成流對象的選擇:
1、明確源和目的。
源:輸入流 – InputStream Reader
目的:輸出流 – OutputStream Writer
2、操作的數據是否是純文本。
是:字符流
不是:字節流
3、當體系明確後,再明確使用哪個具體的對象。通過設備來進行區分。
源設備:內存、硬盤、鍵盤
目的設備:內存、硬盤、控制檯

需求1:複製一個文本文件
源:InputStream / Reader
是否操作文本文件?是。選擇Reader。
接下來明確要使用該體系中的哪個對象。
明確設備:硬盤上的文件
Reader體系中可以操作文件的對象是FileReader
是否需要提高效率?是。加入Reader體系中的緩衝區BufferedReader
FileReader fr = new FileReader(“a.txt”);
BufferedReader br = new BufferedReader(fr);

目的:OutputStream / Writer
是否純文本:是。選擇Writer
設備:硬盤上的文件
Writer體系中可以操作文件的對象是FileWriter.
是否需要提高效率?是。加入Writer體系中的緩衝區BufferedWriter
FileWriter fw = new FileWriter(“b.txt”);
BufferedWriter bw = new BufferedWriter(fw);

File類

用來將文件或文件夾封裝成對象的類,可以操作文件與文件夾的屬性信息。File對象可以作爲參數傳遞給流的構造函數。
流只能操作數據,如果要操作數據的文件對象,必須用到File對象。

File常用方法:
1、獲取
文件名稱getName()
文件路徑getPath(),getAbsolutePath
文件大小length()
文件修改時間lastModified()
2、創建和刪除
創建 boolean createNewFile()
刪除 delete()
3、判斷
是否可執行 canExcecute()
是否可讀 canRead()
是否可寫 canWrite()
是否存在 exists()
是否是文件 isFile()
是否是目錄 isDirectory()

打印流:該流提供了打印方法,可以將各種數據類型的數據都原樣打印。
字節打印流:PrintStream
構造函數可以接受的參數類型:
1、file對象。File
2、字符串路徑。String
3、字節輸出流。OutputStream
PrintStream永遠不會拋出IOException

字符打印流:PrintWriter
構造函數可以接受的參數類型:
1、file對象。File
2、字符串路徑。String
3、字節輸出流。OutputStream
4、字符輸出流。Writer

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt"), true)); //可以自動刷新
String line = null
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    out.println(line.toUpperCase());
    //out.flush();
}
out.close();
br.close();

序列流SequenceInputStream
對多個流進行合併。

Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> 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();

切割流

public static void merge() {
    ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();
    for(int x=1; x<=3; x++) {

    }
}

public static void splitFile() throws IOException {
    FileInputStream fis = new FileInputStream("c:\\1.bmp");
    FileOutputStream fos = null;

    byte[] buf = new byte[1024*1024];
    int len = 0;
    int count = 1;
    while((len = fis.read(buf)) != -1) {
        fos = new FileOutputStream("c:\\splitfiles\\"+(count++)".part");
        fos.write(buf,0,len);
        fos.close();
    }
    fis.close();
}
發佈了37 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章