文件内容操作

文件内容操作

一:字节流

字节流:以字节为单位读写数据.

常用的类主要有:InputStream,OutputStream

核心操作:

(1)通过构造方法,打开文件

(2)通过read方法,读文件内容

(3)通过writer方法,写文件内容

(4)通过close方法,关闭文件.

1.1:InputStream

1.1:构造方法:

java 复制代码
 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[]

传入一个字符数组.

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

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

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

java 复制代码
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);
        }
    }
}
java 复制代码
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()操作一定会被执行到

java 复制代码
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()中:

java 复制代码
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个字节

java 复制代码
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清空的,而是打开操作清空的)

默认的写方式打开,会清空,如果使用"追加写"方式打开,就可以了.

java 复制代码
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 ,占两个字节.

java 复制代码
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();
        }
    }
}
java 复制代码
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()方法,也是会把原来的内容清空的,所以也需要采用"追加写"的方式,让它不要清空原来的内容.

java 复制代码
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();
        }
    }
}
相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
LIT-涛18 小时前
JavaEE初学07
数据库·oracle·java-ee
&梧桐树夏18 小时前
JavaEE 线程安全
java-ee·多线程
界面开发小八哥18 小时前
「Java EE开发指南」如何使用Visual JSF编辑器设计JSP?(一)
java·ide·java-ee·编辑器·myeclipse
先睡18 小时前
javaEE
java·java-ee
冷心笑看丽美人18 小时前
Spring 框架七大模块(Java EE 学习笔记03)
学习·spring·架构·java-ee
郑祎亦20 小时前
JavaWeb开发:HTML 页面与接口对接
前端·后端·java-ee·html
Theodore_10221 天前
7 设计模式原则之合成复用原则
java·开发语言·jvm·设计模式·java-ee·合成复用原则
customer082 天前
【开源免费】基于SpringBoot+Vue.JS网上订餐系统(JAVA毕业设计)
java·jvm·vue.js·spring boot·spring cloud·java-ee·开源
Theodore_10222 天前
6 设计模式原则之单一职责原则
java·算法·设计模式·面试·java-ee·javaee·单一职责原则