Java在使用IO流过程所涉及的编码问题

IO流

简述:

I:in,读入,输入

O:out,写出,输出

流(stream):数据在程序与设备之间传输的形式;是指一连串的数据(字节或字符)

由此,io流也被称为输入输出流

得到io的作用就是:让程序与外部设备进行数据的交互,既输入与输出

特点:

1,流是单向的:只能输入或者输出;以程序作为参考点,往外写与往进读;

2,先进先出:存数据时你是1234写进来的,那么读数据时也是1234读出去;

3,数据源与目的地;流都是有方向的,那么就一定有源头与终点,一般输入流的终点与输出流的起点都是自己所写得程序,而输入流的起点与输出流的重点就是你所要操作的目标位置,可能是文件,网络,终端等;

(bytearrayOutputStream()与charArrayWriter()并没有目标地址,也就是没有参数,因为大部分的流都是通过参数来确定来源与目的地的;解答:首先字节数组与字符数组,溯源来说,二者都是内存区域的一块(数组存的是引用,指向一块内存区)所以这两个字节与字符数组流真正操作的是内存,所以也称为内存流,内存就是java可以直接找到的,所以在你莫仍创建这两个类对象的时候,会自动指向一块内存;)

分类:

分类1:根据流的方向不同,分为输出流与输入流;

分类2:根据操作单位的不同,分为字节流与字符流;

字节流:byte,占一个字节,可以处理一切文件,包括文本,图片,视屏,音频等,

字符流:char,占两个字节,专用于处理纯文本文件

分类3:节点流与处理流(普通流与增强流)

节点流是直接处理文件的,而处理流是用来处理流的(它的参数是流对象),通过普通流来完成核心功能,并且进行增强;

字节流字符流
输入流字节输入流InputStream字符输入流Reader
输出流字节输出流OutPutStream字符输出流Writer

 

总结:哪里需要数据交互,首先就要想到IO流,专门用来进行进行数据交互的;

编码问题

编码问题其实就是中文乱码问题,针对所有的英文字符各个文件格式的编码表都是一致的,但是针对中文,不同的格式有不同的编码。

任何文件的传输过程都可能会出现乱码问题,而文件传输其实是IO的功能,所以有人直接总结,乱码问题即IO问题;

编码问题研究的就是:中文如何完整输出?,如何进行正确传输?

编码概述:计算机编码指电脑内部代表字母或数字的一种记录数据的方式。

计算机中的数据本质上是二进制的数字串;假设这个时候我们想往计算机里去存储信息,但我们不可能直接去操作这些二进制串,所以,我们就用一些数字来对应我们日常所需要的的英文中文等。

所以编码其实就是我们所能识别的字符到计算机所能识别的编号;

字符与编号所对应的表格称为编码表

然后编码解码的过程其实就是根据这张表,将字符变为数字与数字变成字符的过程;

日常使用的编码表:如ASCII编码,gbk,utf-8等

介绍:

ASCII编码:世界上第一个编码表:

GBK编码:中国的编码

中文一般占用两个字节,英文占用一个字节

UTF-8编码:统一的编码

Unicode 学术学会的组织,制订了一套编码规则-Unicode编码,支持世界上五百多种语言

因为某种原因,Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。

中文占用三个字节,英文占用一个字节

乱码问题:

第一种情况:字节—>字符

你所取得的字节是不完整的,即使编码格式一致,也不能得到完整的信息;

 问题解决:

1,获知要操作文件的字节数,创建一个符合文件数据长度的数组,一次性拿到完整的字节数据;

2,准备一个寄存点,首先将拿到的字节码都放到这个寄存区,然后整体从这个寄存区拿到所有数据;

3,java中给出的方法:字符流的出现就是解决了字节到字符的问题,直接按照字符的格式去拿数据,自然不会出现所谓一个字符拿不到对应的字节码的情况;

实例:针对同一段中文数据,你使用同一种代码逻辑去操作,使用字节流会出现乱码,而字符流不会;

代码:

//部分的代码有冲突,拷贝或运行时需要注意
public class test1_字节与字符问题引入 {
    public static void main(String[] args) throws Exception {
        String path="src/test1.txt";
        //1,问题代码
        //获取流
//      InputStream in=new FileInputStream(path);
        
        //操作流
//      byte arr[]=new byte[5];
//      int len=-1;
//      StringBuilder stringBuilder=new StringBuilder();
//      while((len=in.read(arr))!=-1) {
//          String string=new String(arr,0,len);
//          System.out.println("输入过程的输出:"+string);
//          stringBuilder.append(string);
//      }
        
//      System.out.println("最终效果:"+stringBuilder.toString());
        //2.1,大数组一次性拿到所有的字节码数据
        
//      int length=in.available();
//      byte arr[]=new byte[length];
//      
//      int size=in.read(arr);
//      
//      String string=new String(arr);
//      System.out.println("通过字节获得的字符换是完整的:"+string);
//      System.out.println("数组的长度与读取的数据长度:"+(length==size));
        
        //2.2通过字节数组流将文件先放在内存,然后一次性拿出
//      ByteArrayOutputStream out=new ByteArrayOutputStream();
//      int len=-1;
//      byte arr[]=new byte[5];
//      while((len=in.read(arr))!=-1) {
//          out.write(arr, 0, len);
//          String string=new String(arr,0,len);
//          System.out.println("输入过程的输出:"+string);
//      }
//      byte array[]=out.toByteArray();
//      String string=new String(array);
//      System.out.println(string);
        
        //2.3,使用字符流操作文本文件
        Reader in=new FileReader(path);
        char arr[]=new char[5];
        int len=-1;
        StringBuilder stringBuilder=new StringBuilder();
        while((len=in.read(arr))!=-1) {
            String string=new String(arr,0,len);
            System.out.println("输入过程的输出:"+string);
            stringBuilder.append(string);
        }
        
        System.out.println("最终效果:"+stringBuilder.toString());
        //关闭流
        in.close();
    }
}
​

第二种情况:字符—>字符

编码格式不一致的问题;

一个gbk的文件,使用gbk去解析,将其拿到程序中,你拿到的仍是gbk格式的完整字节信息,也是以gbk的格式去写到另一个文件,但是另一个文件的格式是UTF-8;所以最终的情况就是在utf-8的文件上,放着gbk格式的文本数据,自然乱码;

使用一种编码格式,去解析另一种编码格式生成的编码,就好比谍战剧中,我方截获敌方加密情报,你用我方的密码本,当然不能解密情报,只有敌方的密码本才能解密出情报;(这也就是密码本在谍战剧中价值高的原因吧,我的情报你不能解密,你就是拿去了也没用啊!)

 

问题解决:

outputStreamWriter与inputStreamReader,转换流

可以指定文件传入的数据格式,以及传出时的数据格式,输入字符流;

通过转换流,可以让输入流通过指定的编码格式解析文本文件,又以指定的编码格式写入指定的文件;

要想不出现乱码,就要遵循上面的规则:输入流按指定文件的格式来获取数据,以目标格式的输出流来写出数据;

代码:

public class Main {
    public static void main(String[] args) throws Exception {
        //OutputStreamWriter;
        //InputStreamReader
        String sourcePath="src/test1.txt";
        String endPath="src/test2.txt";
        //获取流
//      Reader reader=new FileReader(sourcePath);
//      Writer writer=new FileWriter(endPath);
        
        InputStreamReader reader=new InputStreamReader(new FileInputStream(sourcePath),"GBK");
        OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream(endPath),"UTF-8");
        
        //操作流
        char arr[]=new char[5];
        int len=-1;
        StringBuilder stringBuilder=new StringBuilder();
        while((len=reader.read(arr))!=-1) {
            //核心写入操作
            writer.write(arr, 0, len);
            //验证我们在程序中拿到的数据
            String string=new String(arr, 0, len);
            System.out.println(string);
            stringBuilder.append(string);           
        }
        System.out.println("拷贝结果:"+stringBuilder.toString());
        
        //关闭流
        writer.close();
        reader.close();
    }
}
​

总结:

(1)IO流就是用来进行数据交互的,外部设备的信息输出与输入依赖IO流来完成

(2)针对乱码问题

第一:虽然字节流处理一切文件,但是操作文本文件就使用字符流;

第二:保证程序包括程序所操作的文件格式是一致的;

第三:针对不同编码格式的文件,可以通过转换流来操作;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值