• 文件操作和IO


    文件:File这个概念,在计算机中是一词多用的

    狭义的“文件”:指的是硬盘上的文件和目录(文件夹

    广义的“文件”:泛指计算机中的很多软硬件资源,操作系统中,把很多的硬件设备和软件资源抽象成了文件,按照文件的方式来统一管理。后面的网络编程,操作系统也会把网卡当成了一个文件

    目录

    路径

    文件类型 

    Java中操作文件

    文件内容的读写

    InputStream读取文件

    OutputStream写文件

    Reader读取文件

    Writer写文件

    Scanner搭配流对象使用


    路径

    每个文件,在硬盘上都有一个具体的“路径”。在路径这里,有两种表示路径的风格:

    1.绝对路径,以C、D盘符开头的路径

    2.相对路径,以当前所在的目录为基准,以.或者..开头(又是可以省略),找到指定的路径

    当前所在的目录称为工作目录,每个程序运行的时候都有一个工作目录。

    例如当前的工作目录是D:/tmp

    定位到111这个目录,就可以表示成./111(./就表示当前的目录)

    文件类型 

    word,exe,图片,视频,音频,源代码,动态库,这一些不同的文件,整体可以归纳到两类中:

    1.文本文件(存的是文本,字符串):每一个字符都是通过一个数字来表示的,这个文本文件中存的数组,一定是合法的字符,都是在你指定的字符编码的码表之内的数据

    2.二进制文件(存的是二进制数据,不一定是字符串):没有任何限制,可以储存任何想要的数据

    Java中操作文件

    1.针对文件系统操作(文件的创建、删除、重命名)

    2.针对文件内容操作(文件的读和写)

    Java的标准库,提供了一个File这个类,通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有File 对象,并不代表真实存在该文件。

     File file = new File("d:/test.txt");

    不要求在d:/这里真的有个test.txt,如果没有的话可以手动用createNewFile创建,不能自动创建。

    对于这样一个绝对路径:

     但是对于相对路径来说,当前的相对路径就是当前IDEA文件所在的目录

    在调用getCanonicalPath这个方法时需要用到的异常,这个异常也是我们之后需要频繁用到的~

    对于这样一个绝对路径:

    对于这样一个相对路径:

    是因为当前相对路径下(这个项目所在路径)没有一个test.txt文件,我们可以用代码创建,用createNewFile后项目里面也就有了一个test.txt文件

     和这个类似的还有mkdir,mk->make,dir->directory,也就是创建一个目录。

    文件内容的读写

    我们通过数据流来对文件内容进行读写

    因此就把读写文件的相关对象称为“流对象”,这个比喻并非是Java独有的,其实是操作系统api就是这样设定的。

    Java标准库的流对象,从类型上分为两个大类:

    1.字节流,操作二进制数据的,如InputStream,FileInputStream,OutStream,FileOutputStream

    2.字符流,操作文本数据的,Reader,FileReader,Writer,FileWriter

    这些类的使用方式是非常固定的,核心就是四个操作:

    1.打开文件(构造对象)

    2.关闭文件(close)

    3.读文件(read)=>针对InputStream/Reader

    4.写文件(write)=>针对OutPutStream/Writer

    InputStream读取文件

    通过InputStream来完成对文件的读取,创建inputStream对象的时候,使用绝对路径和相对路径都是可以的,也可以使用FIle对象。打开文件就是通过这样的一个构造方法来打开文件。

    1. public static void main(String[] args) throws IOException {
    2. InputStream inputStream = new FileInputStream("D:/test.txt");
    3. while(true){
    4. int b = inputStream.read();
    5. if(b == -1){
    6. return;
    7. }
    8. System.out.printf("%x\n",(byte)b);
    9. }
    10. }

    通过while循环来读取文件,read方法一次性读取的就是一个字节,虽然是用int类型接收的,但是最后我们打印的时候可以转换成byte。

    read的第二个版本,需要调用者提前准备好一个数组

    1. public static void main(String[] args) throws IOException {
    2. InputStream inputStream = new FileInputStream("D:/test.txt");
    3. while(true){
    4. byte[] buffer = new byte[1024];
    5. int len = inputStream.read(buffer);
    6. if(len == -1){
    7. return;
    8. }
    9. for(int i = 0 ; i < len ; i++){
    10. System.out.printf("%x\n",buffer[i]);
    11. }
    12. }
    13. }

    通过read来读取文件,然后存取到buffer这个数组中去。这里的传参操作,相当于是把刚才准备好的数组,交给read方法,让read方法内部针对这个数组进行填写。

    read会尽可能的把参数传进来的数组给填满。

    上面这里给的数组长度是1024,read就会尽可能的读取1024个字节,填到数组里。

    实际上,文件剩余长度超过1024时,此时1024个字节都会填满,返回值就是1024了。如果当前剩余的长度不足1024,此时有多少就填多少,read方法就会返回当前实际读取的长度。

    OutputStream写文件

    对于OutputStream来说,默认情况下,打开一个文件就会清空文件原有的内容(如果不想清空,流对象还提供了一个“追加写”对象,通过这个就可以不清空文件,把新内容追加写到后面)

    1. public static void main(String[] args) throws IOException {
    2. OutputStream outputStream = new FileOutputStream("D:/test.txt");
    3. outputStream.write(101);
    4. outputStream.write(102);
    5. outputStream.write(103);
    6. outputStream.write(104);
    7. outputStream.close();
    8. }

     和InputStream类似,也是通过构造方法来写入文件。

     最后的close需要额外注意一下:

    这里的close操作,含义是关闭文件。

    每次打开文件操作,都会在文件描述符表中,申请一个位置,把这个信息放进去,每次关闭文件也会把这个文件描述符表对应的表项给释放掉。

    如果这个close操作没写会写会怎么样呢?

     那如何确保这个close被执行到呢?

    1. public static void main(String[] args) throws IOException {
    2. try(OutputStream outputStream = new FileOutputStream("D:/test.txt")) {
    3. outputStream.write(101);
    4. outputStream.write(102);
    5. outputStream.write(103);
    6. outputStream.write(104);
    7. }
    8. }

    我们用try with resources这样的写法,这个写法虽然没有显示的写close,但是实际上会执行的,只要try语句块执行完毕,就可以自动执行close。

     以上方法是字节流的用法,我们接下来介绍字符流。

    Reader读取文件

    1. public static void main(String[] args) throws IOException {
    2. Reader reader = new FileReader("D:/test.txt");
    3. while(true){
    4. int ch = reader.read();
    5. if(ch == -1){
    6. return;
    7. }
    8. System.out.println("" + (char)ch);
    9. }
    10. }

    用reader的构造方法,通过read来读取文件

    Writer写文件

    1. public static void main(String[] args) throws IOException {
    2. Writer writer = new FileWriter("D:/test.txt");
    3. writer.write("hello world");
    4. }

    但是这样写后,会发现test.txt没有出现hello world

    所以我们需要用write.close来触发缓冲区的更新(刷新操作就是把缓冲区里面的内容写到硬盘中),除了close以外,还可以用flush方法也能刷新缓冲区。

    writer.flush();

    Scanner搭配流对象使用

    1. public static void main(String[] args) throws IOException {
    2. InputStream inputStream = new FileInputStream("D:/test.txt");
    3. Scanner scanner = new Scanner(inputStream);
    4. scanner.next();
    5. }

    此时scanner的内容就是从test.txt这个文件来读取。

    虽然这一部分的相关知识并不会在面试中出现,但是以后工作中会有非常高频的使用场景~

  • 相关阅读:
    【我的前端】前端项目小练习:CSS创建3D圆柱旋转效果
    从零开始搭建gitea代码管理平台
    webrtc QOS笔记四 Nack机制浅析
    Vue笔记_transition组件(过渡样式)
    prettytable:一款像数据库一样可完美格式化输出的 Python 库
    QT7_视频知识点笔记_67_项目练习(页面以及对话框的切换,自定义数据类型,DB数据库类的自定义及使用)
    全网最完整php 禁止eval函数讲解
    点云从入门到精通技术详解100篇-基于点云和图像的智能交通路侧感知(续)
    自动驾驶域控制器nvidia环境搭建
    Unity Debug的简单封装
  • 原文地址:https://blog.csdn.net/m0_62319039/article/details/133486815