Java_IO編程


如果要進行文件內容的操作,必須依靠數據流完成,而數據流分為兩種:

字節流:InpuStream(字節輸入流)、OutputStream(字節輸出流)

字符流:Reader(字符輸入流)、Writer(字符輸出流)

字符比字節處理的多,但使用哪個,基本流程都一樣

范例:

創建File類對象,主要是指明要操作的文件路徑

通過字節流或字符流的子類為父類實例化

進行文件的讀寫操作

關閉數據流(close())

 

字節輸出流:OutputStream

字節輸出流主要以byte數據為主

 

輸出單個字節:public abstract void write(int b) throws IOException

輸出全部字節數組:public void write(byte[] b) throws IOException

輸出部分字節數組:public void write(byte[] b, int off, int len) throws IOException  //重點

OutputStream是抽象類,文件的輸出操作需要子類FileOutputStream,此類有兩個常用構造

構造方法:public FileOutputStream(File file) throws FileNotFoundException  新內容覆蓋文件

構造方法:public FileOutputStream(File file, boolean append) throws FileNotFoundException  追加文件內容

范例:實現文件的輸出(往文件里寫內容)

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Hello{
    public static void main(String[] args) throws Exception {
        //第一步:定義要輸出文件的File類對象
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        //輸出信息的時候文件可以不存在,目錄必須存在
        if(!file.getParentFile().exists()) { //父路徑不存在
            file.getParentFile().mkdirs(); //創建父路徑
        }
        //第二部:利用OutputStream的子類為父類實例化
        OutputStream output = new FileOutputStream(file);
        //第三步:輸出文字信息
        String msg = "******"; //字符串
        //為了方便輸出,需要將字符串變為字節數組
        byte data[] = msg.getBytes(); // 變為了字節數組
        output.write(data); //輸出數據 , 創建了test.TXT,並寫入了*****數據
        output.close();
    }
}

實現只輸出部分內容:

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Hello{
    public static void main(String[] args) throws Exception {
        //第一步:定義要輸出文件的File類對象
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        //輸出信息的時候文件可以不存在,目錄必須存在
        if(!file.getParentFile().exists()) { //父路徑不存在
            file.getParentFile().mkdirs(); //創建父路徑
        }
        //第二部:利用OutputStream的子類為父類實例化
        OutputStream output = new FileOutputStream(file);
        //第三步:輸出文字信息
        String msg = "adfasdfadsfasdfasdfsadfasdf"; //字符串
        //為了方便輸出,需要將字符串變為字節數組
        byte data[] = msg.getBytes(); // 變為了字節數組
        output.write(data, 0, 10); //輸出數據 , 從0開始輸出10個
        output.close();
    }

使用循環的方式單個字節的輸出

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Hello{
    public static void main(String[] args) throws Exception {
        //第一步:定義要輸出文件的File類對象
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        //輸出信息的時候文件可以不存在,目錄必須存在
        if(!file.getParentFile().exists()) { //父路徑不存在
            file.getParentFile().mkdirs(); //創建父路徑
        }
        //第二部:利用OutputStream的子類為父類實例化
        OutputStream output = new FileOutputStream(file);
        //第三步:輸出文字信息
        String msg = "adfasdfadsfasdfasdfsadfasdf"; //字符串
        //為了方便輸出,需要將字符串變為字節數組
        byte data[] = msg.getBytes(); // 變為了字節數組
        for(int x = 0; x < data.length; x++) {
            output.write(data[x]); //輸出數據 

        }
        output.close();
    }
}

 現在發現每當執行完成后之前的內容都被覆蓋了,所以也可以進行數據的追加操作:

范例:追加數據(加入新數據 之前的數據不變 ),第二部加個true

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Hello{
    public static void main(String[] args) throws Exception {
        //第一步:定義要輸出文件的File類對象
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        //輸出信息的時候文件可以不存在,目錄必須存在
        if(!file.getParentFile().exists()) { //父路徑不存在
            file.getParentFile().mkdirs(); //創建父路徑
        }
        //第二部:利用OutputStream的子類為父類實例化
        OutputStream output = new FileOutputStream(file, true); //此處為true,表示追加操作
        //第三步:輸出文字信息
        String msg = "111adfasdfadsfasdfasdfsadfasdf"; //字符串
        //為了方便輸出,需要將字符串變為字節數組
        byte data[] = msg.getBytes(); // 變為了字節數組
        output.write(data); //輸出數據 
        output.close();
    }
}

進行換行操作使用“\r\n”

 

 

字節輸入流InputStream

可以實現數據讀取

三個數據讀取方法:

1. 讀取單個字節:public abstract int read() throws IOException  //每次執行此方法將讀取單個字節的數據,如果已經去取完成了,沒數據了,那么最后返回的是-1
2. 讀取數據到字節數組中:public int read(byte[]b) throws IOException  //每次講數據讀取到數組中,那么會返回一個讀取長度的數據,如果沒有數據,返回長度為-1,要考慮兩種情況:1.要讀取的內容大於開辟數組的內容,長度就是整個數組的長度  2.要讀取的內容小於開辟的數組內容,長度就是全部最后的內容長度,數組裝不滿

3. 讀取 部分內容到字節數組:public int read(byte[]b,int off, int len) throws IOException  //每次讀取內容到部分字節數組,只允許讀取滿限制的數組的字節個數,此方法依然返回讀取的長度。

InputStream是抽象類,所以要進行文件的讀取使用FileInputStream子類,子類定義的構造方法:public FileInputStream(File file) throws FileNotFoundException

范例:實現從txt的數據讀取

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;


public class Hello{
    public static void main(String[] args) throws Exception {
        //第一步:定義要輸出文件的File類對象
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        //第二步:實例化InputStream類對象
        InputStream input = new FileInputStream(file);
        //第三步:實現數據讀取操作
        byte data[] = new byte[1024];
        int len = input.read(data); //將數據讀取到數組中
        System.out.println("讀取的內容:【" + new String(data,0,len) +"");
        //第四步:關閉輸入流
        input.close();
    }
}

read()方法可以實現單個字節數據讀取操作,用此方法實現單個字節數據的讀取

范例 :讀取單個字節”

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;


public class Hello{
    public static void main(String[] args) throws Exception {
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        InputStream input = new FileInputStream(file);
        byte data[] = new byte[1024];
        int foot = 0; //控制保存的角標索引
        int temp =  0; //接收每次保存的數據
        do {
            temp = (byte)input.read(); //讀取出來的數據保存到字節數組中
            if(temp != -1) { //現在有數據
                data[foot ++] = (byte) temp;
            }
        } while(temp != -1); //表示后面可能還有數據
        System.out.println("讀取的內容:【" + new String(data,0,foot) +"");
        input.close();
    }
}

以上使用了do...while,實際開發中都用while:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;


public class Hello{
    public static void main(String[] args) throws Exception {
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        InputStream input = new FileInputStream(file);
        byte data[] = new byte[1024];
        int foot = 0; //控制保存的角標索引
        int temp =  0; //接收每次保存的數據
        while((temp = input.read())!= -1 ) {
            data[foot ++] = (byte)temp;
        }
        System.out.println("讀取的內容:【" + new String(data,0,foot) +"");
        input.close();
    }
}

 

字符輸出流:Writer

Writer是進行字符輸出操作的抽象類

之所以提供一個Writer類,是因為這個類的輸出方法有一個特別好用的:

輸出字符串:public void write(String str) throws IOException   //重點

 

范例:使用Writer輸出數據

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;


public class Hello{
    public static void main(String[] args) throws Exception {
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        if(file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        Writer out = new FileWriter(file);
        String data = "測試數據測試數據測試數據測試數據測試數據" ;
        out.write(data); //直接輸出字符串
        out.close();
    }
}

若要追加增加數據,之前的不變:

Writer out = new FileWriter(file, true);

雖然Wirter類提供字符數組的輸出操作能力,但本質上講使用Writer類就意味着要執行字符串的直接輸出。

 

字符輸入流:Reader

數據讀取:public int read(char[] cbuf) throws IOException

范例:讀取數據

import java.io.File;
import java.io.FileReader;
import java.io.Reader;


public class Hello{
    public static void main(String[] args) throws Exception {
        File file = new File("F:" + File.separator + "hello" + File.separator + "Test.txt"); 
        if(file.exists()) {
            Reader in = new FileReader(file);
            char data[] = new char[1024];
            int len = in.read(data); //向字符數組中保存數據,返回長度
            System.out.println(new String(data, 0, len));
            in.close();
        }
    }
}

Reader與InputStream類相比除了數據類型的差別之外,操作上沒有優勢

 

 

字節流與字符流的區別

這兩種流的區別就好比數據庫中的BLOB與CLOB區別

CLOB保存大文本數據,都是字符數據

BLOB保存二進制數據,例如:電影、圖片、文字,都是字節數據

通過任何終端(網絡、文件)讀取或者輸出的數據都一定是字節,但字符是通過內存處理后的數據。

字符輸入:字符輸入的時候字節(磁盤)自動轉換為字符(內存)

字符輸出:字符(內存)自動轉換為字節(磁盤)

在利用字符流輸出的時候,所有的內容實際上都只是輸出到了緩沖區中(內存)。在使用close()關閉的時候會將緩沖區的數據輸出,如果不關閉就不發進行輸出,此時可以利用flush()進行強制刷新

字符使用到了緩沖區,而字節沒有使用到緩沖區。如果處理中文使用字符流,其他任何數據都是用字節流。

 

綜合案例:文件拷貝

是模擬dos系統中的copy命令完成

編寫一個文件拷貝程序,可實現任意文件拷貝操作,通過初始化參數輸入拷貝的源文件以及拷貝的目標文件路徑,本程序暫不考慮類的設計。

dos拷貝命令:“copy 路徑1 路徑2”

兩種實現思路:

  思路一:開辟一個數組,將需拷貝的內容讀取到數組之中,而后一次性輸出到目標路徑中

  思路二:采用邊讀邊寫的方式進行拷貝,不是一次性讀取

第一種方式如果文件小沒問題,5M左右。如果文件大,基本內存就被沾滿了,

范例:初期實現

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyDemo {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) { //參數內容必須是兩個,一個源文件路徑一個目標文件路徑
            System.out.println("錯誤的命令,格式為:CopyDemo 源文件路徑 目標文件路徑。");
            System.exit(1); //退出程序
        }
        //接下來驗證源文件是否存在
        File inFile = new File(args[0]);
        if(!inFile.exists()) {
            System.out.println("路徑錯誤,請確定源文件路徑正確。");
            System.exit(1);
        }
        //如果拷貝的目標文件存在,則也不應該進行拷貝
        File outFile = new File(args[1]);
        if(outFile.exists()) { //目標文件已經存在
            System.out.println("拷貝的路徑文件已經存在,請更換路徑。");
            System.exit(1);
        }    
        long start = System.currentTimeMillis();
        InputStream in = new FileInputStream(inFile);
        OutputStream out = new FileOutputStream(outFile);
        copy(in,out); //開始文件拷貝
        in.close();
        out.close();
        long end = System.currentTimeMillis();
        System.out.println("花費的時間:" + (end - start) );
    }
    public static void copy(InputStream input, OutputStream output) throws Exception {
        int temp = 0; //保存每次讀取的字節量
        while((temp = input.read()) != -1 ) { //每次讀取一個字節
            output.write(temp);            
        }
    }
}

要先執行以下再輸入路徑。此種方法只能復制很小的文件。

用數組來提升拷貝性能,可以將數據讀取到數組中,而后一次性將數組輸出。

修改拷貝方法:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyDemo {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) { //參數內容必須是兩個,一個源文件路徑一個目標文件路徑
            System.out.println("錯誤的命令,格式為:CopyDemo 源文件路徑 目標文件路徑。");
            System.exit(1); //退出程序
        }
        //接下來驗證源文件是否存在
        File inFile = new File(args[0]);
        if(!inFile.exists()) {
            System.out.println("路徑錯誤,請確定源文件路徑正確。");
            System.exit(1);
        }
        //如果拷貝的目標文件存在,則也不應該進行拷貝
        File outFile = new File(args[1]);
        if(outFile.exists()) { //目標文件已經存在
            System.out.println("拷貝的路徑文件已經存在,請更換路徑。");
            System.exit(1);
        }    
        long start = System.currentTimeMillis();
        InputStream in = new FileInputStream(inFile);
        OutputStream out = new FileOutputStream(outFile);
        copy(in,out); //開始文件拷貝
        in.close();
        out.close();
        long end = System.currentTimeMillis();
        System.out.println("花費的時間:" + (end - start) );
    }
    public static void copy(InputStream input, OutputStream output) throws Exception {
        int temp = 0; //保存每次讀取的字節量
        byte data[] = new byte[2048];
        //數據向數組中讀取
        while((temp = input.read(data)) != -1 ) { //每次讀取一個字節
            output.write(data, 0 , temp); //輸出數組            
        }
    }
}

特別快。

對於File、InputStream、OutputStream最直接操作就體現在本程序中

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM