1. 程式人生 > >轉換流(OutputStreamWriter/InputStreamReader) 檔案拷貝 字元編碼(亂碼)

轉換流(OutputStreamWriter/InputStreamReader) 檔案拷貝 字元編碼(亂碼)

一:轉換流</fon
在這篇部落格中介紹了位元組流和字元流:
https://blog.csdn.net/sophia__yu/article/details/84678506

其實可以將位元組流轉換為字元流,也就是轉換流。
轉換流用於將底層的位元組流轉為字元流供子類使用。
位元組輸出流–>字元輸出流:OutputStreamWriter。

 public OutputStreamWriter(OutputStream out)

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

public InputStreamReader(InputStream in) </font><br />

流的繼承關係:

public class FileWriter extends OutputStreamWriter;
public class OutputStreamWriter extends Writer;

public class FileReader extends InputStreamReader;
public class InputStreamReader extends Reader

在這裡插入圖片描述
將位元組流轉換為字元流例項:

package CODE.IO;


import java.io.*;
//將位元組流轉換為字元流
public class Zhunhuan
{ //取得終端物件:這裡的終端是檔案 public static void main(String[] args) throws Exception{ File file=new File("C:"+File.separator+"Users"+ File.separator+ "lenovo"+File.separator+"Desktop"+ File.separator+"Test.txt"); //取得終端輸出流 OutputStream out=new FileOutputStream
(file); OutputStreamWriter wr=new OutputStreamWriter(out); //將位元組輸出流轉換為字元輸出流 wr.write("hello pick"); //字元輸入流的字串寫入 wr.close(); //關閉流 } }

檔案拷貝

資料的拷貝是通過流的方式來完成,而流分為位元組流和字元流。一般位元組流用於拷貝圖片音樂等,字元流可以用於中文的拷貝。
拷貝資料可以採用邊讀邊寫(讀一個位元組拷一個位元組);也可以採用利用緩衝區(開闢一個數據),一次性讀很多資料放在緩衝區,然後進行寫入。

1.讀一個位元組拷一個位元組:

package CODE.JavaIo;

import java.io.*;

//拷貝圖片
public class Copy {
    public static void main(String[] args) throws  Exception{
        String sourceFilePath="C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"pick.jpg";
        String destFilePath="C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"sophia.jpg";
        copyFile(sourceFilePath,destFilePath);

    }
    public static boolean copyFile(String sourceFilePath,String destFilPath) throws Exception
    {
        //1.取得終端物件,終端是檔案
        File sourceFile=new File(sourceFilePath);
        File destFile=new File(destFilPath);
        if(!sourceFile.getParentFile().exists())
        {
            System.out.println("原始檔父目錄不存在");
            sourceFile.getParentFile().mkdirs();
            return false;
        }
        if(!sourceFile.exists())
        {
            System.out.println("拷貝原始檔不存在");
            return false;
        }
        if(!destFile.getParentFile().exists())
        {
            System.out.println("目標檔案父目錄不存在");
            destFile.getParentFile().mkdirs();
            return false;
        }
        //現在具備拷貝條件
        //2.取得檔案的輸入輸出流
        InputStream in=new FileInputStream(sourceFile); //從原始檔讀取資料
        OutputStream out=new FileOutputStream(destFile); //目標檔案是寫入資料

        //3.讀取或寫入資料
        long start=System.currentTimeMillis();
        int len=0;
        while((len=in.read())!=-1) //in.read()是一次讀取一個位元組,返回的是讀取的一個位元組資料,當返回-1讀取完畢
        {
            out.write(len); //將讀取到1位元組資料寫入目標檔案
        }
        long end=System.currentTimeMillis();
        System.out.println("拷貝耗時:"+(end-start)+"毫秒"); //1642毫秒
        //關閉流
        in.close();
        out.close();
        return true;
    }
}

2.利用緩衝區:

public class Copy {
    public static void main(String[] args) throws  Exception{
        String sourceFilePath="C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"pick.jpg";
        String destFilePath="C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"sophia.jpg";
        copyFile(sourceFilePath,destFilePath);

    }
    public static boolean copyFile(String sourceFilePath,String destFilPath) throws Exception
    {
        //1.取得終端物件,終端是檔案
        File sourceFile=new File(sourceFilePath);
        File destFile=new File(destFilPath);
        if(!sourceFile.getParentFile().exists())
        {
            System.out.println("原始檔父目錄不存在");
            sourceFile.getParentFile().mkdirs();
            return false;
        }
        if(!sourceFile.exists())
        {
            System.out.println("拷貝原始檔不存在");
            return false;
        }
        if(!destFile.getParentFile().exists())
        {
            System.out.println("目標檔案父目錄不存在");
            destFile.getParentFile().mkdirs();
            return false;
        }
        //現在具備拷貝條件
        //2.取得檔案的輸入輸出流
        InputStream in=new FileInputStream(sourceFile); //從原始檔讀取資料
        OutputStream out=new FileOutputStream(destFile); //目標檔案是寫入資料

        //3.讀取或寫入資料
        long start=System.currentTimeMillis();
        int len=0;
        
        byte[] data=new byte[1024]; //緩衝區為1024位元組
        while((len=in.read(data))!=-1) //in.read(data)將讀取的資料放入data陣列,返回的是實際讀取位元組數,當返回-1,讀取完畢
        {
            out.write(data); //將data陣列內容寫入
        }
        
        long end=System.currentTimeMillis();
        System.out.println("拷貝耗時:"+(end-start)+"毫秒"); //16毫秒
        //關閉流
        in.close();
        out.close();
        return true;
    }
}

字元編碼

常用字元編碼

	1. GDK DB2312:國際編碼。
	  GBK既包含簡體中文也包含繁體中文。
	  DB2312只包含簡體中文。
	2. UNICODE :java提供的16進位制編碼,可以描述世界上任意的文字。由於採用16進位制編碼,導致編碼的體積太大,造成網路傳輸負擔。
	3. ISO8859-1 :瀏覽器預設編碼,國際通用編碼,不支援中文。
	4. UTF 編碼:(UTF-8:8進位制UTF編碼):相當於結合了ISO-8859-1和UNICODE編碼,支援所有語言而且體積小。
	
    所以在實際開發中,採用UTF-8編碼。

亂碼產生原因

產生亂碼的95%原因一般是編解碼不一致。

System.getProperties().list(System.out); //當前作業系統的預設編碼格式:UTF-8

如果系統所用的編碼與程式所用編碼不同,那麼強制轉換就會出現亂碼。

package CODE.JavaIo;


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

//亂碼
public class Unicode {
    public static void main(String[] args) throws  Exception{
        //System.getProperties().list(System.out); //當前作業系統的預設編碼格式:UTF-8
        File file=new File("C:"+File.separator+"Users"+
                File.separator+ "lenovo"+File.separator+"Desktop"+
                File.separator+"Test.txt");
        OutputStream out=new FileOutputStream(file);
        String str="哈嘍 pick";
        out.write(str.getBytes("ISO8859-1"));
        //以ISO--8859-1格式寫入,但是作業系統預設解碼是UTF-8,會出現亂碼
        out.close();
    }
}

在這裡插入圖片描述

ISO8859-1不支援中文,所以對"哈嘍"解碼時出現亂碼。