Java总结IO篇之字节流与字符流转化

本篇接上篇:Java中的字符流,流的读写的细节参考上篇
本篇讲述字节流相关话题,包括字节流的读取与写出,字节流转化为字符流
1.明确是否是纯文本:纯文本 ? 字符流: 字节流
2.明确数据来源( 输入流 I )和数据流向( 输出流 O )
3.I流和O流对接,数据传输
另外:需要字符编码转换,使用字节流转换字符流

数据来源( 输入流 I ):内存、磁盘、网络、键盘    
数据流向( 输出流 O ): 内存、磁盘、网络、控制台    
1.最常见的几种流
9414344-51ddbaea0edd3a1d.png
最常见的几种流.png
2.流与流之间的相互作用:转换与包装
9414344-1bae611af7db90b2.png
转换流和包装流.png

一、FileOutputStream与FileInputStream

1.FileOutputStream:输出流,写出操作
 FileOutputStream fos = null;
 try {
     String fileName = "I:\Java\Base\Thinking\src\IOTest\FileInputStream.txt";
     fos = new FileOutputStream(fileName);
     fos.write("Line1 第一行".getBytes());//不需要刷新缓冲
 } catch (IOException e) {
     e.printStackTrace();
 } finally {
     try {
         if (fos != null) {
             fos.close();
         }
     } catch (IOException e) {
         e.printStackTrace();
     }
 }
9414344-489cac370aad7f6d.png
字节输出流.png

2.FileInputStream:输入流,读进操作
public static void main(String[] args) {
    try {
        String fileName = "I:\Java\Base\Thinking\src\IOTest\FileInputStream.txt";
        FileInputStream fis = new FileInputStream(fileName);
        //readOneByOne(fis);
        //readByByteArrayByWhile(fis);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
1)一个一个字节
private static void readOneByOne(FileInputStream fis) throws IOException {
    int ch = 0;
    while ((ch = fis.read()) != -1) {
        System.out.println(ch + "=" + (char) ch);
    }
}

一共输出了15个字节,和Line1 第一行有出入,原因:
在utf-8编码下,一个中文字符占三个字节

76=L  105=i  110=n  101=e  49=1  32=   231=ç  172=¬  172=¬  228=ä  184=¸  128=�  232=è  161=¡  140=�  
2)字节数组方式:
private static void readByByteArrayByWhile(FileInputStream fis) throws IOException {
    //字符数组循环读取
    byte[] buf = new byte[8];
    int len = 0;
    while ((len = fis.read(buf)) != -1) {
        System.out.println(new String(buf, 0, len));
    }
}

可见buf一次装个字节,由三个字节表示,被分成了两半,所以读出了乱码

//Line1 �
//�一行
文件字节数
System.out.println(fis.available());//15

二、使用字节流拷贝

视频大小:576M

1.使用FileInputStream和FileInputStream拷贝

耗时:6.162444569秒

private static void copy() {
    FileOutputStream fos = null;
    FileInputStream fis = null;
    try {
        fis = new FileInputStream("I:\Java\Base\Thinking\src\IOTest\video.avi");
        fos = new FileOutputStream("F:\javaTest\IO\video.avi");
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (fos != null) {
                fos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2.使用包装类BufferedOutputStream和BufferedInputStream拷贝:

方法耗时:33.478968503秒

private static void copyByBuf() {
    BufferedOutputStream bfos = null;
    BufferedInputStream bfis = null;
    try {
        FileInputStream fis = new FileInputStream("I:\Java\Base\Thinking\src\IOTest\video.avi");
        bfis = new BufferedInputStream(fis);
        FileOutputStream fos = new FileOutputStream("F:\javaTest\IO\video.avi");
        bfos = new BufferedOutputStream(fos);
        int b = 0;
        while ((b = bfis.read()) != -1) {
            bfos.write(b);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (bfis != null) {
                bfis.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (bfos != null) {
                bfos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、字节流转化为字符流

场景一:将键盘录入写入到本地磁盘
分析:键盘录入是一个字节输入流: InputStream in = System.in;
由于输入的都是字符,使用字符流将比较方便(当然字节流也可以,不过麻烦一点)
1.用字符流InputStreamReader将字节流转化
2.再用字符包装流BufferedReader包装一下(当然也可以不包装,不过麻烦一点)
9414344-1bae611af7db90b2.png
转换流和包装流.png
public class Save2File {
    public static void main(String[] args) throws Exception {

        //数据源----键盘录入字节流转化为字符流后包装成BufferedReader
        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
        String path = "I:\Java\Base\Thinking\src\IOTest\键盘录入";
        //数据流向 :"I:\Java\Base\Thinking\src\IOTest\键盘录入" 文件
        BufferedWriter brw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));

        String line = null;
        while ((line=bfr.readLine())!=null){
            if ("over".equals(line)) {
                break;
            }
            brw.write(line);
            brw.newLine();
            brw.flush();
        }
        bfr.close();
        brw.close();
    }
}
9414344-b0dfa3726a76811e.png
键盘录入到文件.png
场景二:将键盘录入写入到本地磁盘:指定字符编码

默认字符编码为utf-8,这里使用GBK测试

public class Save2File {
    public static void main(String[] args) throws Exception {
        //数据源----键盘录入字节流转化为字符流后包装成BufferedReader
        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
        String path = "I:\Java\Base\Thinking\src\IOTest\键盘录入-GKB";
        //数据流向 :"I:\Java\Base\Thinking\src\IOTest\键盘录入" 文件
        BufferedWriter brw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path),"GBK"));

        String line = null;
        while ((line=bfr.readLine())!=null){
            if ("over".equals(line)) {
                break;
            }
            brw.write(line);
            brw.newLine();
            brw.flush();
        }
        bfr.close();
        brw.close();
    }
}
9414344-4c519228680a3a3e.png
GBK存储.png

可见两者的字节数不同,一个GBK的汉字占2个字节(2*5+ =12) ,一个UTF-8汉字占3个字节(3*5+ =17)

场景3:读取文件输出到控制台
分析:控制台输出是一个字节输出流:PrintStream out = System.out;
由于输出的都是字符,使用字符流将比较方便(当然字节流也可以,不过麻烦一点)
1.用字符流OutputStreamWriter将字节流转化
2.再用字符包装流BufferedWriter包装一下(当然也可以不包装,不过麻烦一点)
public class ReadFile2Console {
    public static void main(String[] args) throws Exception {
        //数据源----本地文件
        String path = "I:\Java\Base\Thinking\src\IOTest\Activity.md";
        BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
        //数据流向 :"I:\Java\Base\Thinking\src\IOTest\键盘录入" 文件
        BufferedWriter brw = new BufferedWriter(new OutputStreamWriter(System.out));
        String line = null;
        while ((line = bfr.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            brw.write(line);
            brw.newLine();
            brw.flush();
        }
        bfr.close();
        brw.close();
    }
}
9414344-e9614229e272ca27.png
文件输出到控制台.png
场景4:改变系统流的流向

可以改变系统的录入流(数据来源),和控制台输出流(数据流向)

System.setIn(InputStream 输入流); 自定义System.in数据来源(默认键盘录入)
System.setOut(PrintStream 输出流);自定义System.out数据流向(默认控制台)
public class ReadFile2Console {
    public static void main(String[] args) throws Exception {
        //数据源----本地文件
        String path = "I:\Java\Base\Thinking\src\IOTest\Activity.md";

        System.setIn(new FileInputStream(path));//将键盘源改为了磁盘文件源
        System.setOut(new PrintStream("F:\hell.txt"));//将流向控制台改为流向磁盘文件

        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
        //数据流向 :"I:\Java\Base\Thinking\src\IOTest\键盘录入" 文件
        BufferedWriter brw = new BufferedWriter(new OutputStreamWriter(System.out));
        String line = null;
        while ((line = bfr.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            brw.write(line);
            brw.newLine();
            brw.flush();
        }
        bfr.close();
        brw.close();
    }
}


后记:捷文规范

1.本文成长记录及勘误表
项目源码 日期 备注
V0.1--无 2018-10-10 Java中的字节流与字符流转化
V0.2--无 - -
2.更多关于我
笔名 QQ 微信 爱好
张风捷特烈 1981462002 zdl1994328 语言
我的github 我的简书 我的CSDN 个人网站
3.声明

1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持

原文地址:https://www.cnblogs.com/toly-top/p/9781849.html