Java 初识IO流笔记

本文详细介绍了Java中InputStream的使用,包括FileInputStream的read方法,探讨了编码问题及其解决方案,如使用read(byte[])和read(byte[], int, int)处理中文乱码。还涉及了输入缓冲流BufferedInputStream的效率优势,并分析了Java中的进制转换和乱码现象。此外,通过示例展示了文件复制操作中的输入输出流结合使用。
摘要由CSDN通过智能技术生成

Java 初识IO流笔记

内容:
1.常见的输入流FileInputStream的三种read方法使用
2.过程中遇到的编码和类型转换问题分析

1.输入流

在这里插入图片描述

InputStream是抽象类(其中的read()方法为抽象方法无法直接实例化使用),所以这个类不能直接使用可以:
所以实例化时new 的是FileInputStrean这个类(这个类继承了InputStream并实现了read()方法)
所以一般的文件输入留有以下两种方式创建

 InputStream fis=new FileInputStream("url");
 FileInputStream fis=new FileInputStream("url")

url是需要读取文件的存储位置,可以是绝对路径也可以是相对路径。
先着重演示文件输入流三个不同read方法的用途

1.无参数输入的read()

需要读取文件hello.txt中存储的内容:

hello

用法
read()方法返回的是一个int类型的值,如果输入的这个文件流中还有值没有读出则返回一个字节对应的int类型值。
如果这个流已经读完了则返回-1。

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

public class test_1 {
    public static void main(String[] args) throws IOException {
        InputStream fis=new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt");
        int b;
        while ((b=fis.read())!=-1){//通过是否为-1判断流是否读完
            System.out.print((char)b);
        }
        System.out.println();

    }
}

控制台输出:

hello

若read()返回的不是-1则对应返回的int值转换为char就是对应的字符(这种情况就是一个字节翻译一个值出来根据Unicode码来翻译)
在这里插入图片描述
根据这个表可知如果返回的是65则对应字符A(对应的int类型前加一个强制转换就可以完成对应的翻译)

提示但是这种一个字节一个字节读的方式无法显示中文会出现乱码,因为中文的表示,GBK需要两个字节,UTF-8需要三个字节

如将源文件hello.txt中的文件内容改为 中文,这两个汉字

hello.txt文件改为:

中文

控制台输出:

中文  //出现乱码

所以read有以下重载方法提供解决方案

2.read(byte [])

这个方法可以解决上面中文乱码的问题,上面的那种原始read()方法因为每次只能取一个字节,所以不能不能翻译中文,所以只要能解决这个问题,一次性从流中传入一个数组的数据(一个byte存储一个字节的数据,所以byte[]数组的长度是多少就能存储多少个字节的数据)

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

public class test_2 {
    public static void main(String[] args) throws IOException {
        InputStream is=new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt");
        byte b[]=new byte[1024];//这个长度可以根据自己需要调整
        while (is.read(b)!=-1){
//            System.out.println(new String(b,"UTF-8"));//String类提供了把byte数组转化为String类的构造方法,第二个参数可以不写,如果不要第二个参数,IDEA会以平台默认的编码方式编码

        }
    }
}

控制台输出

中文      

这种方法每次从流放入数组的数据的长度是由数据决定的(每次byte数组这个容器能满就装满的意思,当然如果数据很少,可能第一次装个几字节就没了),无法手动控制长度,所以提供了以下方法

3.read(byte[] b, int off, int len)

这个方法增强了使用的灵活性

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

public class test_4 {

        public static void main(String[] args) throws IOException {
            InputStream is=new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt");
            byte b[]=new byte[1024];
            while (is.read(b,0,3)!=-1){//每次的偏移量必须是三的倍数(这种编码模式下3个字节一个中文嘛)
                System.out.println(new String(b,"UTF-8"));//这种方法可以获得正确的中文编码
            }
        }
}

控制台输出

中
文

因为用的是UTF-8的编码,一个中文需要三个字节表示,所以我们从最开始的位置开始取,每次取三个字节,中文这两个汉字取了两次,所以打印了两次

2.输入缓冲流

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class test_5 {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt"));//和一般文件流的创建略有不同
        byte[] b=new byte[1024];
        while (bis.read(b)!=-1){
            System.out.println(new String(b));//这里就是使用的默认编码方式
        }
    }
}

控制台输出:

中文                      

缓冲流比一般的流快(这个缓冲流的读取效率更高),但是需要注意,具体组件中的一些功能他是没有的。比如read(byte[]),这个方法在 BufferedInputStream中就没有,所以在用构造方法声明的时候需要传入 FileInputStream()的实例,而不只是一个源文件的地址

3.遇到的编码问题

一) java进制问题

public class test_3 {
    public static void main(String[] args) {
        int c=021;    //0开头表示八进制
        int d=0x10;   //0x打头表示16进制(x大小写都可)
        System.out.println(c);
        System.out.println(d);
        /**
         * Java所有整型的数据默认都是int,小数默认为double
         * **/
        byte e=(byte) 0x121;     //强转为byte会用十六进制(因为之前的数据是用16进制表示的)舍去高位
        System.out.println(e);   //可以发现最高位的1被舍去
        /**
         * Java运算的时候会产生类型提升
         * 范围小于int的值进行运算,运算过程中会转化为int
         * **/
        byte f=0x11;
        byte g=0x01;
        byte h=(byte)(f-g);   //这里必须强转byte,不然就会发生int赋给byte的大赋小的问题
    }
}

控制台输出

17
16
33

总结:
1.在强制转换过程中丢精度,需要根据数据的进制类型来丢,如果是16进制,就丢去16进制的高位如e=0x121,强转之后就只有0x21(转化为10进制为33)的值了
2.Java所有整型的数据默认都是int,小数默认为double
3范围比int小的值进行运算,运算过程中会转化为int(如两个byte类型的值相减)

二)乱码分析

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
 * GBK   两个字节一个字符
 * UTF-8 三个字节一个字符
 * UTF-8 中英文都可以支持所以使用更广
 * **/
public class test_2 {
    public static void main(String[] args) throws IOException {
        InputStream is=new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt");
        int len;
        while ((len=is.read())!=-1){
            System.out.println(len);
        }

    }
}

控制台输出

228
184
173
230
150
135    //此时源文件中还是存入的中文两个汉字

idea默认的编码是UTF-8,所以存入的文件也是按照一个汉字等于三个字节存储,所以最后读取的时候两个汉字读了6个字节。
而直接用char强转每一个字节的话是按照Unicode编码的,所以中文就会出现乱码,而如果存入的英文的话,一个字节就可以存储所有英文字母,Unicode是支持英文的,所以不会出现乱码。
按照这个逻辑这些int类型的值在输出流的位置不需要强转任何类型就可以写入

4.最常见的输入流和输出流结合用法(完成文件的复制)

public class test_6 {
    public static void main(String[] args)throws  Exception {
        FileInputStream fis=new FileInputStream("D:\\工作区\\SE\\IO\\srcs\\hello.txt");
        FileOutputStream fos=new FileOutputStream("D:\\工作区\\SE\\IO\\srcs\\test2.txt");
        int len;
        while ((len=fis.read())!=-1){  
            fos.write((len));   //直接写入
        }
    }
}

这里的输出流会先检查目标位置上有没有对应文件,如果没有就先则创建它,然后存在这个文件会先清空文件内容,然后写入。(当然也有不清空,直接追加内容的方法)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值