1. 程式人生 > >Java——I/O(位元組流、字元流與轉換流 )

Java——I/O(位元組流、字元流與轉換流 )

位元組流和字元流

位元組流(byte):InputStream、OutputStream 

字元流(char):Reader、Writer

  • 位元組流與字元流的區別:

位元組流是原生的操作,而字元流是經過處理後的操作。

  • 一般使用位元組流——無論是網路傳輸還是磁碟的資料儲存均以位元組為單位,只有處理中文文字時才會用到字元流。

1. 流操作流程

  • 輸入流:
  1. 準備檔案
  2. 例項化FileInputSream物件
  3. read()讀取資料
  4. 業務處理資料
  5. 關閉輸入流-finally
  • 輸出流:
  1. 準備檔案,檔案不存在自動建立,但是目錄一定要存在
  2. 例項化FileOutputSream物件
  3. 業務處理資料
  4. write()輸出資料
  5. 關閉輸入流-finally
  • 業務處理

    讀取資料,while( ){ },讀到末尾返回-1

InputStream in= null;
OutputStream out=null;
try {
     in = new FileInputStream(file);
     out=new FileOutputStream(file);
     int value=-1;
     //輸入
     while((value=in.read())!=-1){
          //程式中進行資料的處理
          value+=32;
          //輸出
          out.write(value);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
  • I/O操作屬於於資源處理,所有的資源處理操作(IO操作、資料庫操作、網路)使用後必須要進行關閉。 

2. 位元組輸出流(OutputStream)

public abstract class OutputStream implements Closeable, Flushable
//Closeable介面: 
public void close() throws IOException; 
//Flushable介面: 
public void flush() throws IOException;
  • 2.1 輸出方法

//將給定的位元組陣列內容全部輸出
public void write(byte b[]) throws IOException 
//將部分位元組陣列內容輸出
public void write(byte b[], int off, int len) throws IOException 
//輸出單個位元組
public abstract void write(int b) throws IOException;
  • 要進行檔案內容的輸出,使用FileOutputStream()
//檔案內容覆蓋
public FileOutputStream(File file) throws FileNotFoundException 
//檔案內容追加
public FileOutputStream(File file,boolean append) throws FileNotFoundException 
  • 當使用FileOutputStream進行檔案內容輸出時,只要檔案父路徑存在,FileOutputStream會自動建立檔案
import java.io.*;

/**
 * 位元組輸出流
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) throws IOException {
        //1.取得終端物件
        File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt");
        //只要檔案父路徑存在,FileOutputStream會自動建立檔案
        //OutputStream為抽象方法,需要借用子類進行例項化
        OutputStream out =null;
        OutputStream out1 =null;
        //2.取得終端物件的輸出流
        try {
            out = new FileOutputStream(file);
            //允許內容的追加
            out1 = new FileOutputStream(file,true);
            //3.進行資料的輸出
            String msg="你好世界!!!\r\n";
            //當出現中文時,最好全部輸出,避免出現亂碼
            out.write(msg.getBytes(),0,6);  //你好
            out1.write(97); //a
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            //4.關閉流
            out.close();
            out1.close();
        }
    }
}

3. 自動關閉支援AutoCloseable-JDK1.7

  • 使用前提:結合try...catch...
/**
 * 自動關閉
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        //try-with-resources try(例項化物件的程式碼,例項化物件的類實現AutoCloseable介面)
        //例項化多個物件時,用分號隔開,最後一個不用加分號
        try(Msg msg=new Msg();
        try(Msg msg1=new Msg()
        ){
            msg.print();  //normal method...   auto close...
        }catch (Exception e){

        }
    }
}

class Msg implements AutoCloseable{

    @Override
    public void close() throws Exception {
        System.out.println("auto close...");
    }

    public void print(){
        System.out.println("normal method...");
    }
}

4. 位元組輸入流(InputSream)

public abstract class InputStream implements Closeable
  • 4.1 輸入方法 

//讀取資料到位元組陣列b中
public int read(byte b[]) throws IOException 
//讀取單個位元組
public int read() throws IOException 
  • 返回值:

返回b長度:讀取資料大小>位元組陣列大小,返回位元組陣列大小

返回大於0但是小於b長度:讀取資料大小<位元組陣列大小,返回真正讀取個數

返回-1:資料讀取完畢

import java.io.*;

/**
 * 位元組輸入流
 * Author: qqy
 */
public class Test2 {
    public static void main(String[] args) throws IOException {
        //1.取得File物件
        File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt");
        //2.取得輸入流
        InputStream in= null;
        try {
            in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //3.讀取檔案內容
        byte[] data=new byte[1024];
        int res= 0;
        try {
            res = in.read(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(res);
        System.out.println(new String(data));
        //4.關閉輸入流
        in.close();
    }
}

5. 字元流

  • 5.1 字元輸出流(Writer)

除了引數為字元陣列外,多了一個傳入String物件的方法

public void write(String str) throws IOException
import java.io.*;

/**
 * 字元輸出流
 * Author: qqy
 */
public class Test3 {
    public static void main(String[] args) throws IOException {
        //1.取得File物件
        File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt");
        //2.取得輸出流
        Writer writer=new FileWriter(file);
        //3.寫入資料
        String str="你好Bonjour";
        writer.write(str);
        //4.關閉流
        writer.close();
    }
}
  • 5.2 字元輸入流(Reader)

Reader類中沒有方法可以直接讀取字串,只能通過字元陣列來讀取

import java.io.*;

/**
 * 字元輸入流
 * Author: qqy
 */
public class Test4 {
    public static void main(String[] args) throws IOException {
        //1.取得File物件
        File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt");
        //2.取得輸入流
        Reader reader= new FileReader(file);
        //3.讀取資料
        char[] data=new char[1024];
        int result=reader.read(data);
        System.out.println(result);
        System.out.println(new String(data,0,result));
        //4.關閉流
        reader.close();
    }
}

6. 位元組流與字元流

  • 開發中,優先考慮位元組流,只有處理中文時才考慮使用字元流。
  • 所有字元流操作,無論是寫入還是輸出,資料都先儲存在快取中——字元輸出流不關閉,檔案中無內容;位元組輸出流不關閉,檔案中有內容。
  • 想要將字元輸出流在檔案中顯示,要麼正常關閉—out.close(),要麼強制清空快取區—out.flush()

練習:檔案複製(位元組流)

import java.io.*;
import java.nio.file.Paths;

/**
 * 檔案複製
 * Author: qqy
 */
public class Test6 {
    public static void main(String[] args) throws IOException {
        String src="";
        String dest="";
        long start=System.currentTimeMillis(); //毫秒數
        copy(src,dest);
        long end=System.currentTimeMillis();
        System.out.println(end-start/1000+"s");  //秒數
    }

    public static void copy(String srcFilePath,String destFilePath){
        //引數校驗
        if (srcFilePath==null||srcFilePath.isEmpty()) {
            throw new IllegalArgumentException("srcFilePath not null/empty!");
        }
        if (destFilePath==null||destFilePath.isEmpty()) {
            throw new IllegalArgumentException("destFilePath not null/empty!");
        }

        File srcFile =Paths.get(srcFilePath).toFile();
        File destFile =Paths.get(destFilePath).toFile();
        //檔案校驗以及準備工作
        if(!srcFile.exists()||!srcFile.isFile()){
            throw new IllegalArgumentException("srcFilePath not exists or not file!")
        }

        File parentFile= destFile.getParentFile();
        if(!parentFile.exists()){
            if(!parentFile.mkdirs()){
                throw new RuntimeException("can't create"+parentFile.getAbsolutePath()+"directory");
            }
        }

        //檔案複製
        try(FileInputStream in=new FileInputStream(srcFile);
            FileOutputStream out =new FileOutputStream(destFile)
        ){
          //緩衝陣列
          //引入緩衝區
          byte[] buff = new byte[1024];  //1k,2k,4k,8k
          int len=-1;
          //一次只讀一個位元組,再輸出一個位元組
          while((len=in.read(buff))!=-1){
              //為了避免資料讀取不全,使用下列方式進行寫入
              out.write(buff,0,len);
          }
        }catch(IOException e){
            System.out.println(e.getMessage());
        }
    }
}

轉換流

位元組流—>字元流,用於將底層的位元組流轉為字元流供子類使用

OutputStreamWriter:位元組輸出流—>字元輸出流

InputStreamReader:位元組輸入流—>字元輸入流

import java.io.*;

/**
 * 轉換流
 * Author: qqy
 */
public class Test7 {
    public static void main(String[] args) throws IOException {
        //1.取得檔案物件
        File file = new File ("E:"+File.separator+"JAVA"+File.separator+"Test.txt");
        //2.取得輸出流
        OutputStream outputStream=new FileOutputStream(file);
        //3.位元組流變為字元流,注意編碼格式
        OutputStreamWriter out=new OutputStreamWriter(outputStream);
        out.write("你好 Bonjour");
        //4.關閉流
        out.close();
    }
}