12_IO流_字节流

前置知识

ASCII

ASCII ( American Standard Code for Information Interchange ) :美国信息交互标准代码(包括了英文和符号)

标准的 ASCII 使用 1 个字节存储一个字符

1 字节:00000000

GBK

汉字编码字符集,包含了 2 万多个汉字等字符,GBK 中一个中文字符编码成两个字节的形式存储

注意:GBK 兼容了 ASCII 字符集

2 字节:00000000,00000000

Unicode

Unicode 是国际组织制定的,是可以容纳世界上所有文字、符号的字符集

UTF-8:英文字符、数字等只占 1 个字节(兼容标准 ASCII 编码),汉字字符占用 3 个字节

编码与解码
import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 编码
        String data = "a我b";
        byte[] bytes = data.getBytes();  // 不填参数,默认按照当前编辑器平台UTF-8进行编码
        System.out.println(Arrays.toString(bytes));

        // 按照指定字符集进行编码
        byte[] bytes1 = data.getBytes("GBK");
        System.out.println(Arrays.toString(bytes1));

        // 2. 解码
        String s1 = new String(bytes);
        System.out.println(s1);

        String s2 = new String(bytes1,"GBK");
        System.out.println(s2);
    }
}

IO 流

体系介绍

IO 流体系

  • 字节流
    • 字节输入流(InputStream)===>(FileInputStream)
    • 字节输出流(OutputStream)===>(FileOutputStream)
  • 字符流
    • 字符输入流(Reader)===>(FileReader)
    • 字符输出流(Writer)===>(FileWriter)

注意!输入流、输出流都是指对 “内存” 的输入和输出,例如:文件输入流 FileInputStream 指的是"文件对内存的输入流"

文件字节输入流
  • 每次读取一个字节
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
//        InputStream is = new FileInputStream(new File("E:/Desktop/temp.txt"));
        InputStream is = new FileInputStream("E:/Desktop/temp.txt");  // 简化写法

        // 2. 开始读取文件的字节数据(当前文件里面写有"ab"两个字母)
        // 每次读取一个字节返回,如果没有数据了,返回-1
//        int b1 = is.read();
//        System.out.println(b1);  // 97
//
//        int b2 = is.read();
//        System.out.println((char) b2);  // b
//
//        int b3 = is.read();
//        System.out.println(b3);  // -1

        // 3. 用循环改造上面代码
        int b;
        while ((b = is.read()) != -1) {  // 此方法还是有问题:读取数据性能很差!读取中文字符一定会乱码
            System.out.println((char) b);
        }
        // 运行结果
        // a
        // b

        is.close();  // 一定要记得关闭管道!释放它所占据的系统资源
    }
}
  • 每次读取多个字节
import java.io.FileInputStream;
import java.io.InputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        // 文件中的数据:abc66
        // 1. 创建文件字节输入流管道,与源文件接通
        InputStream is = new FileInputStream("E:/Desktop/temp.txt");

        // 2. 开始读取文件中的字节数据
        byte[] buffer = new byte[3];
        int len = is.read(buffer);  // 每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1
        String res = new String(buffer);
        System.out.println("读取的内容是: " + res);
        System.out.println("当次读取的字节数量: " + len);

        int len2 = is.read(buffer);
        // 注意: 读取多少,倒出多少
        String res2 = new String(buffer, 0, len2);
        System.out.println("读取的内容是: " + res2);
        System.out.println("当次读取的字节数量: " + len2);

        int len3 = is.read(buffer);
        System.out.println(len3);  // -1
        
        is.close();  // 关闭输入流管道

//        运行结果:

//        读取的内容是: abc
//        当次读取的字节数量: 3
//        读取的内容是: 66
//        当次读取的字节数量: 2
//         -1
    }
}
// 上面代码的改造

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

public class Test {
    public static void main(String[] args) throws Exception {
        // 文件中的数据:abc66
        // 1. 创建文件字节输入流管道,与源文件接通
        InputStream is = new FileInputStream("E:/Desktop/temp.txt");

        // 2. 读取文件中的字节数据(使用循环的方法)
        byte[] buffer = new byte[3];
        int len;  // 记住读取了多少个字节
        while ((len = is.read(buffer)) != -1) {
            String res = new String(buffer, 0, len);  // 将数组中的 0 ~ len转为字符串输出
            System.out.println(res);
        }
        // 性能得到了明显的提升
        // 但是!这种方案也不能避免读取汉字输出乱码的问题


        is.close();  // 关闭输入流管道
    }
}
  • 一次性读取完全部字节
// 方法一

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

public class Test {
    public static void main(String[] args) throws Exception {
        // 文件中的数据:abcd我爱你66

        // 一次性读取完文件中的所有字节到数组中去
        // 1.创建文件字节输入流管道,与源文件接通
        InputStream is = new FileInputStream("E:/Desktop/temp.txt");
        // 2.准备一个字节数组,它的大小需要和文件的大小正好一样大
        File f = new File("E:/Desktop/temp.txt");
        long size = f.length();
        byte[] buffer = new byte[(int) size];

        int len = is.read(buffer);
        System.out.println(new String(buffer));
        System.out.println(len);
        System.out.println(size);
        is.close();  // 关闭输入流管道

        // 运行结果
//        abcd我爱你66
//        15
//        15
    }
}
// 方法二

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

public class Test {
    public static void main(String[] args) throws Exception {
        // 文件中的数据:abcd我爱你66

        // 一次性读取完文件中的所有字节到数组中去

        // 1.创建文件字节输入流管道,与源文件接通
        InputStream is = new FileInputStream("E:/Desktop/temp.txt");

        // 2.使用封装好的功能
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));  // abcd我爱你66

        is.close();  // 关闭输入流管道
    }
}
文件字节输出流
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个字节输出流管道与目标文件接通(默认是覆盖原文件内容的)
//        OutputStream ops =  new FileOutputStream("E:/Desktop/a.txt");

        // 如果是想要一个能够追加数据的管道:请将参数append的值设为true
        OutputStream ops = new FileOutputStream("E:/Desktop/a.txt", true);

        // 2. 开始写字节数据出去了
        // write() : 如果直接写内容进去,每次只能写一个字节; 如果用byte[]数组,则不受限制
        ops.write(97);
        ops.write('b');
//        ops.write('王');  // UTF-8字符集下,汉字占3个字节,因此这里开始会乱码

        byte[] bytes = "okok我爱你abc".getBytes();
        ops.write(bytes);

        // 换行符 : 为了不仅在 Windows 上能使用,我们建议写全,即:把 \n 写为 \r\n
        byte[] bytes1 = "\r\n".getBytes();
        ops.write(bytes1);

        ops.close();  // 关闭输出流管道,释放被占用的系统资源
    }
}
文件复制案例
// 以下代码,可以复制一切文件
// 原因:任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后文件格式一致就没问题!

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

public class Test {
    public static void main(String[] args) throws Exception {
        // 复制照片
        // 1. 创建一个字节输入流管道与源文件接通
        InputStream inputStream = new FileInputStream("E:/Desktop/photo.jpg");

        // 2. 创建一个字节输出流管道与目标文件接通
        OutputStream outputStream = new FileOutputStream("E:/Desktop/aaa/photo.jpg");

        // 3. 创建一个字节数组,负责转移字节数据
        byte[] buffer = new byte[1024];  // 1KB

        // 4. 从字节输入流中读取字节数据,写出去到字节输出流中,读多少写多少
        int len;  // 记住每次读取了多少个字节
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
        System.out.println("Successful!");
    }
}
释放资源
// 方式一 : 手动释放

import java.io.*;

public class Test {
    public static void main(String[] args) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            System.out.println(10 / 0);  // 错误代码(测试用)
            // 1. 创建一个字节输入流管道与源文件接通
            inputStream = new FileInputStream("E:/Desktop/photo.jpg");

            // 2. 创建一个字节输出流管道与目标文件接通
            outputStream = new FileOutputStream("E:/Desktop/aaa/photo.jpg");

            // 3. 创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024];  // 1KB

            // 4. 从字节输入流中读取字节数据,写出去到字节输出流中,读多少写多少
            int len;  // 记住每次读取了多少个字节
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 释放资源的操作
            try {
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();
                System.out.println("Successful!");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }
}
// 方式二 : 自动释放

import java.io.*;

public class Test {
    public static void main(String[] args) {
        try (
                // 注意: 小括号这里面只能放置资源对象(流对象)

                // 1. 创建一个字节输入流管道与源文件接通
                InputStream inputStream = new FileInputStream("E:/Desktop/photo.jpg");
                // 2. 创建一个字节输出流管道与目标文件接通
                OutputStream outputStream = new FileOutputStream("E:/Desktop/aaa/photo.jpg");

        ) {
//            System.out.println(10 / 0);  // 错误代码(测试用)

            // 3. 创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024];  // 1KB

            // 4. 从字节输入流中读取字节数据,写出去到字节输出流中,读多少写多少
            int len;  // 记住每次读取了多少个字节
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            System.out.println("Successful!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值