文件内容操作

本文详细介绍了Java中的字节流和字符流,包括InputStream的构造方法、read()方法的使用和文件关闭,以及OutputStream的write()方法,以及字符流如Reader和Writer的工作原理。特别关注了数据读写时的编码问题和文件操作的最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:字节流

字节流:以字节为单位读写数据.
常用的类主要有:InputStream,OutputStream
核心操作:
(1)通过构造方法,打开文件
(2)通过read方法,读文件内容
(3)通过writer方法,写文件内容
(4)通过close方法,关闭文件.

1.1:InputStream

1.1:构造方法:

 InputStream inputStream  = new FileInputStream("d:/test.txt") ;

在这里插入图片描述

1.1.2:read()方法:

在这里插入图片描述版本一:无参数,一次读取一个字节,读取到的内容,就通过返回值来表示了.
既然一次读一个字节,返回值应该是byte类型,为什么返回int??
(1)1byte能够读取的访问0-255(无符号),但实际上byte类型是有符号的,范围是-127-128,我们期望是0-255,如果返回的类型是int ,则可以满足需求,通过int类型就可以确保读出来的字节都是整数.
(2)0-255都是表示读取的内容,256个数字都表示读取到了内容.但如果读取不到内容,就需要额外标记"到达文件末尾"返回-1这种情况.那么就存在257种情况,返回byte就不能达到.
(3)257种情况,为什么不用short,而用int??
计算机发展到现在,空间已经不再是核心矛盾了.存储设备成本越来越便宜(近段时间).
但是,随着CPU越来越强大,单次处理的数据,也变得越来越长了:
对于32位CPU,一次就是处理4个字节的数据,此时要是使用short,操作系统内部其实还是把short转成int,再按int来处理
对于64位CPU来说,一次就能处理8个字节的数据了,相比之下,short就能没什么意义了.
版本二:带有一个参数,byte[]
传入一个字符数组.

      byte[] bytes = new byte[1024];//先准备好一个空的字节数组

           int n = inputStream.read(bytes);
            //方法执行完毕后,把读到的数据放到字节数组中
            //返回值表示成功读取到的字节数
            //如果返回值为-1,则表示未成功读到任何数据

一次读取数组的长度个字节,如果不够,能读多少就读多少.

public class Demo2 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream =new FileInputStream("d:/text.txt");
        while(true){
          int n =  inputStream.read();
          if(n==-1){
              break;
          }
            System.out.printf("0x%x ",n);
        }
    }
}

public class Demo1 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream  = new FileInputStream
                ("E:\\img\\图书馆\\微信图片_20240324210435.jpg") ;
        while(true){
            byte[] bytes = new byte[1024];//先准备好一个空的字节数组

            int n = inputStream.read(bytes);
            //方法执行完毕后,把读到的数据放到字节数组中
            //返回值表示成功读取到的字节数
            //如果返回值为-1,则表示未成功读到任何数据
            System.out.println("n = "+n);
            if(n==-1){
                break;
            }
            for (int i = 0; i <n ; i++) {
                System.out.printf("0x%x ",bytes[i]);
            }
            System.out.println();
        }

    }
}

上述两种read方法中,哪个效率更高??
read():频次高,但一次读的东西太少.
read(bytes):频次低,一次读的东西多.
每次调用read,都是要通过系统api,来访问应硬盘的,访问硬盘是非常低效的操作,但一次读的东西读,还是读的东西少,开销其实是差不多的,所以read(bytes)效率是更高的.
第三个版本:
和第二个版本差不多,第二个版本,把读到的数据往整个数组填充,但三个版本,从下标off开始,最多填充len那么长.
有的时候,可能需要一个数组,里面的不同的部分表示不同的含义.

在这里插入图片描述

1.1.3:关闭文件:close

为什么要关闭文件??
打开文件的时候,会在操作系统的内核,PCB这样的结构体中,给"文件描述符表"**添加一个元素,**这个元素就是表示当前打开的文件的相关信息.
但文件描述符表(相当于一个顺序表),里面的长度是固定的,存在上限,不能自动扩容,如果一直打开文件,而不关闭,就会使这个文件描述符表被占满,一旦占满之后,再次尝试打开,就会打开文件失败(其他的操作,网络通信相关的操作,也可能会收到影响).
所以必须close,但在close前面如果出现异常/return,此时close就执行不到了.
使用finally:保证close()操作一定会被执行到

public class Demo2 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream =new FileInputStream("d:/text.txt");
        try{
            while(true){
                int n =  inputStream.read();
                if(n==-1){
                    break;
                }
                System.out.printf("0x%x ",n);
            }
        }finally {
            inputStream.close();
        }

    }
}

使用try:必须要实现Closeable接口的类,才能放到try()中:

public class Demo3 {
    public static void main(String[] args) throws IOException {
        try(  InputStream inputStream =new FileInputStream("d:/text.txt")){
            while(true){
                int n =  inputStream.read();
                if(n==-1){
                    break;
                }
                System.out.printf("0x%x ",n);
            }
        }

    }
}

1.2:OutputStream

1.2.1:write()

在这里插入图片描述版本一:一次write 一个字节,参数是 int 类型
版本二:一次write若干字节,会把参数数组里所有的字节都写入文件中.
版本三:一次write若干字节,把数组从off下标开始,连续写len个字节

public class Demo4 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt")){
       
            outputStream.write(98);
            outputStream.write(99);
            outputStream.write(100);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里我们发现:按照写方式打开文件的时候,会把文件原有的内容清空掉(不是write清空的,而是打开操作清空的)
默认的写方式打开,会清空,如果使用"追加写"方式打开,就可以了.

public class Demo4 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt",true)){

            outputStream.write(98);
            outputStream.write(99);
            outputStream.write(100);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二:字符流

字符流:以字符为单位读写数据
常用的类主要有:Reader,Writer

2.1:Reader

在这里插入图片描述这里常用的是第一个方法,表示一次读一个字符(可能是两个字节,也可能是三个字节),返回类型为char ,占两个字节.

public class Demo1 {
    public static void main(String[] args) throws FileNotFoundException {
        try(Reader reader=new FileReader("d:text.txt")){
            while(true) {
                int c = reader.read();
                if (c == -1) {
                   break;
                }
                char ch = (char) c;
                System.out.println(ch);

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class Demo2 {
    public static void main(String[] args) {
        try(Reader  reader = new FileReader("d:/text.txt")){
            while(true){
                int c = reader.read();
                if(c==-1){
                    break;
                }
                char ch = (char) c;
                System.out.print(ch+" ");

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
IDEA采用utf-8编码方式,一个汉字是占3个字节,但read一次读三个字节,但返回类型是char, 占两个字节,明显是不对的啊??
实际上,Java对上述的数据进行了编码转换.
read在读取汉字的时候,能够识别此时采用的是utf-8的编码方式,所以读的时候,读的就是三个字节,但返回成一个char的时候,把utf-8的编码方式,转成了unicode,在unicode中,一个汉字就是2个字节.
举个栗子:
假设读到了一个字符"你",此时Java通过查询unicode编码表,找到"你"这个字符的值,此时这个值就对应两个字节,就可以返回了.

2.2:Writer

在这里插入图片描述一般使用第二种方法.
这些writer()方法,也是会把原来的内容清空的,所以也需要采用"追加写"的方式,让它不要清空原来的内容.

public class Demo3 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("d:text.txt",true)){
            writer.write("hello");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十一.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值