学习文件IO,让你从操作系统内核的角度去理解输入和输出(Java实践篇)

news2024/11/16 11:46:08

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

引言

在数字化时代,数据的存储、访问与处理已成为推动科技进步与社会发展的核心动力。

想象一下,从个人电脑的文档管理到企业级的数据中心,从智能手机上的照片备份到云端服务的海量数据存储,无一不依赖于一个关键而基础的技术—— 文件输入输出(File IO)

文件IO,作为连接数据世界与现实世界的桥梁,其重要性不言而喻。它不仅关乎数据的安全与效率,更是各类应用程序、操作系统乃至整个信息技术架构的基石。

让我们一同踏入这场探索之旅,揭开文件IO技术的神秘面纱,共同见证数据如何在指尖流转,成为推动世界前行的强大力量。

本篇文章中我们讲学习到以下内容

目录

  1. 文件系统操作

  2. 文件内容操作

  3. 文件综合运用操作

一. 文件系统操作

对于一个文件来说,我们可以得到一个文件的各种属性: 文件名,文件目录,文件路径。这里的就涉及到文件系统操作。

1. File类

Java标准库 中就封装了一个 FIle类 来获取文件的各种信息和属性

来自 java.io.File 这个包。

在这里插入图片描述

2. 常用方法

而作为一个后端开发的程序猿我们只需要了解 Java标准库 中的 File 类 中常用的几个方法即可:

  • 得到该 对象的文件名和上一个路径的文件

在这里插入图片描述

  • 得到该 对象的路径

在这里插入图片描述

  • 判断该对象是否是 绝对路径 或者 是否是一个目录

在这里插入图片描述

  • 判断该对象是否是 一个文件

在这里插入图片描述

  • 得到该目录下的 所有文件和目录

在这里插入图片描述

3. 代码演示

package FileDemo;

import java.io.File;
import java.io.IOException;



public class MyFileTest {
    public static void main(String[] args) throws IOException {
        File file = new File("./demo.txt");

//        得到文件的绝对路径
        System.out.println(file.getAbsoluteFile());

//        判断是否是目录
        if (file.isDirectory()) {
            System.out.println("是目录!");
        } else {
            System.out.println("不是目录!");
        }

//        判断是否是路径
        if (file.isAbsolute()) {
            System.out.println("是路径!");
        } else {
            System.out.println("不是路径!");
        }

//        得到上一级的文件
        File[] files = file.getParentFile().listFiles();


//        开始遍历
        for (File f : files) {
//           判断是否是文件
            if (f.isFile()) {
                System.out.println(f.getName());
            }
        }


    }
}

在这里插入图片描述

在上面的演示中

主要分为两部进行

  1. 文件对象的实例
File file = new File("./demo.txt");
  1. 进行各种文件系统操作
//        得到文件的绝对路径
        System.out.println(file.getAbsoluteFile());

等… 这些操作将在下面内容中结合 文件内容操作 一起配合使用~

鱼式疯言

  1. 使用 File 类来实例化对象 时, 也是会成功的,

但需要判断的是是否是 符合要求目录路径

  1. 需要抛出 异常 IOException 这个异常, 并且导入 Java.io.IOException 这个包.

二. 文件内容操作

在文件内容操作的之前,小伙伴们必须先了解一下流对象,以及流对象的表示形式。

1. 流对象

什么是流 ? ? ?

流可以说水流,气流等…

但在文件IO这里,流的作用主要是处理各种各样的文件形式而形成的一种 统一的概念

而流分为两种:

1) 字节流

2) 字符流

<1>. 字节流

字节流的含义就好比现在你有一百个字节数据

如果一个字节一个字节取,就需要取一百次;
如果五个字节五个字节取,就需要取二十次;
如果十个字节十个字节取,就需要取十次;
如果二十个字节二十个字节取,就需要取五次;
如果一百个字节一百个字节取,只需取一次。

这就是字节流,先把数据 以字节为基本单位 进行划分,根据 需求 得到每次 需要取出字节的个数 来进行 文件IO内容操作

代表的类:

  • 以字节为单位的读操作的类

InputStream

  • 以字节为单位的写操作的类

OutputStream

<2>. 字符流

字符流的含义就好比现在你有一百个字符数据

如果一个字符一个字节取,就需要取一百次;
如果五个字符五个字节取,就需要取二十次;
如果十个字符十个字节取,就需要取十次;
如果二十个字符二十个字节取,就需要取五次;
如果一百个字符一百个字节取,只需取一次。

字符流是以字符为 基本单位对文件内容进行划分并操作

代表的类:

  • 以字符为单位的读操作的类:
    Reader

  • 以字符为单位的写操作的类:
    Writer

2. 字符流代码演示

<1>. 读操作


package MyIODemo;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class ReaderDemo {
    public static void main(String[] args) throws IOException {

        // 实例化字符流读操作的FileReader类
        // 打开文件
        Reader reader = new FileReader("demo1.txt");


//        利用文件流对文件进行读操作
//        通过循环遍历每次读的字符
        while(true) {

            // 将每次读到的字符 用 n 来接收
            int n = reader.read();

            // 一旦返回 -1 说明读取到文件的最后一个位置,读取完毕
            if(n== -1) {
                break;
            }

            // 转化为字符并打印输出
            char buffer = (char) n;
            System.out.print(buffer);
        }


//        关闭文件流
        reader.close();
    }
}

在这里插入图片描述

读操作 用到的 Reader类 来自 java.io.Reader 这个包, 而且需要抛出 IOException 这个类.

鱼式疯言

总结一 :

文件内容操作的流程三部曲:

  1. 打开文件
  1. 读写文件内容
  1. 关闭文件

总结二 :

FileNotFoundException 是进行打开文件是 所需要抛出的异常 , 但属于 IOException , 所以这里我们只需要抛出 IOException 即可。

<2>. 写操作

package MyIODemo;


import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Scanner;

public class WriterDemo {
    public static void main(String[] args) throws IOException {

//       打开文件
        Writer writer = new FileWriter("demo1.txt",true);

        Scanner in = new Scanner(System.in);
        String  buffer = in.nextLine();

//        写文件
        writer.write(buffer);


//        关闭文件
        writer.close();

    }
}

在这里插入图片描述

结论一 :

对于 写操作 , 还是按照三个流程:

  1. 打开文件
  1. 写文件
  1. 关闭文件

结论二:

//       打开文件
        Writer writer = new FileWriter("demo1.txt",true);

当我们打开文件时:

FileWriter 方法还设定了 一个参数 , 这个参数的如果置为 true 就代表不会清空全有数据而是在原有数据的后面进行拼接写入。

如果在参数列表 ==不添加 true 或者置为 false ==, 就会 清空内容,从一个 空文档 开始写入。

鱼式疯言

关于 文件关闭 这件事,小编有话说

在操作系统内核中,每打开一个文件,就会在操作系统中的一个特点的区域: “文件描述符表” 中多一个

这个 文件描述符表 可以看成是 一个数组 , 一旦打开文件过多没有及时关闭 ,就会在 文件描述符表中 不断堆积 , 就会导致出现 文件泄露问题

虽然进程结束,程序会 自动清空文件描述符表中的每一项 , 但是如果程序一直 不结束,就会导致 不可预估的问题 发现。

所以小编在这里建议: 加上 close() 方法来 释放文件资源

3. 字节流代码演示

<1>. 读操作

package MyIODemo;


import java.io.*;
import java.util.Scanner;




/**
 * 基本版本的读入文件
 */
public class StreamTest {
    public static void main(String[] args) {
        try(InputStream inputStream = new FileInputStream("./demo.txt")){
                while(true) {
                    byte[] buffer = new byte[1024];
                    int flg = inputStream.read(buffer);
                    if(flg == -1) {
                        break;
                    }

                    for (int i = 0; i < flg; i++) {
                        System.out.print((char) buffer[i]);
                    }

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

在这里插入图片描述
这里字节流的读操作

  1. 打开文件

小编利用了 try() catch {} 进行操作。

利用 try (打开文件) , 在这个括号打开文件 在{} 内生效,出来{} 就会自动关闭 文件流 。 这样就可以省去手动 close()关闭文件

byte[] buffer = new byte[1024];
 int flg = inputStream.read(buffer);
  1. 在读文件时,我们就需要注意声明一个 byte[] 类型 的数组, 用来 存储文件中的数据, 只需要放入 read 的参数中 即可填充 , 而 flg 的这个返回值就是作为 数组实际填充 的大小, 如果一旦 flg = -1 时, 就说明数据已经返回结束了。

其他操作和上面字符流大体一致,小编在这就不赘述啦 💖 💖

鱼式疯言

注意事项

只有这种特定的 打开文件类似的操作 才能放入 try () 的括号内, 且如果要放 多行 的话,就需要用 ; 号来隔开。 作用域就是在 { }

<2>. 写操作

package MyIODemo;


import java.io.*;
import java.util.Scanner;



/**
 * 基本版本的写入文件
 */
class StreamTest2 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("./demo.txt",true)) {
            byte[] buffer = {97,98,99};
            outputStream.write(buffer);

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

        }
    }
}

在这里插入图片描述

字节流的写操作也大同小异,小编在这里就不赘述, 小伙伴好好理解即可。

三. 文件综合运用操作

学会了文件系统和文件内容的各个基础操作,下面小编就举出两个实际的案例给小伙伴演示下两者结合的秒出哦 , 可千万别眨眼哦 💖 💖 💖 💖

1. 找到指定文件确认是否删除

<1>. 逻辑分析

  1. 首先: 先确认该文件的路径
  1. 其次: 在 路径合法 的情况下, 把每个文件目录取出进行递归查找
  1. 最后:在是合法文件的提前下, 判断是否含有 该文件名 ,一旦含有就选择 是否需要删除

<2>. 代码展示

/**
 * 查找指定文件并且删除
 *
 */

package MyIODemo;


import java.io.*;
import java.util.Scanner;


class StreamTest4 {
    public static void main(String[] args) {
        // 确定路径
        System.out.print("请输入指定路径: ");
        Scanner in = new Scanner(System.in);
        String path = in.next();

        // 转化成路径
        File  pathRoot = new File(path);

//        判断是否是合法路径
        if(!pathRoot.isDirectory()) {
            System.out.println("不是合法路径!");
            return;
        }

        // 输入指定文件
        System.out.print("请输入指定的文件的关键字: ");
        String key = in.next();

        // 进行递归
        scan(pathRoot, key);
    }

    private static void scan(File pathRoot, String key) {
        // 判断当前路径是否合法
        if(!pathRoot.isDirectory()) {
            return;
        }

        // 合法的情况下取出当前所以的路径
        File[] files = pathRoot.getAbsoluteFile().listFiles();


        // 多加一层判断
        if (files== null || files.length == 0) {
            return;
        }

        // 深度优先遍历 所以的文件路径
        for(File file : files) {
            if(file.isFile()) {
//                是文件的话就开始判断是不是指定文件
//                然后进行删除
                delete(file, key);

            } else {
                // 继续往下递归
                scan(file,key);
            }
        }

    }

    private static void  delete(File file, String key) {
        if(file.getName().contains(key)) {
            System.out.println("请确定是否删除该文件:" + file.getAbsoluteFile() + " Y/y -> 是, N/n -> 否 :  ");
            Scanner in = new Scanner(System.in);
            String  str = in.next();

            if(str.equals("y") || str.equals("Y")) {
                file.delete();
                System.out.println("删除成功!");
            } else {
                System.out.println("删除失败,正在退出...");

            }
        }
    }

}

在这里插入图片描述

在这里插入图片描述

2. 进行文件的复制

<1>. 逻辑分析

  1. 首先输入第一个字符串为 源文件, 判断是否是 合法文件
  1. 其次输入第二个字符串为 目标文件, 判断是否是 合法文件
  1. 最后在 try catch 中实例化 字节输出和输入流 ,先对源文件进行 读操作 , 然后再对目标文件进行 写操作。当源文件 读取结束 ,目标文件也就完成了 拷贝

<2>. 代码展示

/**
 *
 * 将一个文件拷贝到另外一个文件
 *
 */


import java.io.*;
import java.util.Scanner;


class StreamTest5 {

    public static void main(String[] args) {
        System.out.print("请输入源文件路径: ");
        Scanner in = new Scanner(System.in);
        String path = in.next();
        File curPath = new File(path);

        // 判断是否合法路径
        // 是否是正确的文件
        if(!curPath.isFile()) {
            System.out.println("源文件非法!");
            return;
        }


        // 判断是否合法
        System.out.print("请输入目标文件的路径: ");
         path = in.next();
         File descPath = new File(path);
         if (!curPath.getParentFile().isDirectory()) {
             System.out.println("目标文件路径非法");
            return;
         }

         // 开始进行读入 和写出
        try (InputStream inputStream = new FileInputStream(curPath) ;
        OutputStream outputStream = new FileOutputStream(descPath)) {
            byte[] buffer = new byte[1024];
            // 从源文件读入, 写出到目标文件
            while(true) {

//               读入
               int n = inputStream.read(buffer);
               if(n==-1) {
                   break;
               }

               // 写出
               outputStream.write(buffer,0,n);
            }

            System.out.println("拷贝成功! ");

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


    }
}

在这里插入图片描述

总结

  • . 文件系统操作: 利用 File 这个类对文件的 路径,目录,判断 进行各种操作。

  • . 文件内容操作: 熟悉了 文件流 的 字节流和 字符流 的 概念理解 , 以及对于 FileReader , IntputStream 的读操作, 和 FileWriterOutputStream写操作

  • . 文件综合运用操作: 综合 结合了两种不同的 文件系统操作和文件内容操作 结合学习,实际运用了具体的实际运用中。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2073440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【在Linux世界中追寻伟大的One Piece】应用层协议HTTP

目录 1 -> HTTP协议 2 -> 认识URL 2.1 -> urlencode和urldecode 3 -> HTTP协议请求与响应格式 3.1 -> HTTP请求 3.2 -> HTTP响应 4 -> HTTP的方法 4.1 -> HTTP常见方法 5 -> HTTP的状态码 6 -> HTTP常见Header 7 -> 最简单的HTTP服…

Linux系统报错“version ‘GLIBC_2.34‘ not found”解决方法

注意&#xff0c;此文章慎用&#xff0c;glibc不可随意升级&#xff0c;可能导致系统崩溃 一、查看版本 ldd --version 二、添加高版本源 sudo vi /etc/apt/sources.list.d/my.list 进入编辑页面 "i"键进入插入模式 输入源 deb http://th.archive.ubuntu.com/…

【信创】推荐一款超级好用的文件同步备份工具 _ 统信 _ 麒麟 _ 方德

往期好文&#xff1a;【信创】统信UOS打包工具介绍与使用教程 Hello&#xff0c;大家好啊&#xff01;今天给大家推荐一款在Linux系统上超级好用的文件同步和备份工具——FreeFileSync。无论是在日常工作还是数据管理中&#xff0c;文件同步和备份都是至关重要的任务。FreeFile…

【自动驾驶】控制算法(五)连续方程离散化与离散LQR原理

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

QT6 setCentralWidget 和 takeCentralWidget

qt6 中&#xff0c;初始化界面完成之后&#xff0c;可以使用setCentralWidget 设置当前的widget为中心页面 如果你存在多个widget想要多个切换 如果存在widget1 和 widget2 在初始化的时候 setCentralWidget(widget1)触发操作切换到 widget2 如果没有先takeCentralWidget 直…

13.深入解析ThreadPoolExecutor线程池

ThreadPoolExecutor线程池 线程池简介线程池的使用创建线程池ThreadPoolExecutor——推荐使用线程池的核心参数 Executors——不推荐使用 提交任务如何执行批量任务如何执行定时、延时任务如何执行周期、重复性任务 关闭线程池线程池的参数设计分析核心线程数(corePoolSize)最大…

EEMD-MPE-KPCA-BiLSTM、EEMD-MPE-BiLSTM、EEMD-PE-BiLSTM故障识别、诊断(Matlab)

EEMD-MPE-KPCA-BiLSTM(集合经验分解-多尺度排列熵-核主元分析-双向长短期网络)故障识别、诊断&#xff08;Matlab) 目录 EEMD-MPE-KPCA-BiLSTM(集合经验分解-多尺度排列熵-核主元分析-双向长短期网络)故障识别、诊断&#xff08;Matlab)效果一览基本介绍程序设计参考资料 效果一…

RK3588人工智能开发----【1】初识NPU

NPU 的诞生&#xff01; 随着人工智能和大数据时代的到来&#xff0c;传统嵌入式处理器中的CPU和GPU逐渐无法满足日益增长的深度学习需求。为了应对这一挑战&#xff0c;在一些高端处理器中&#xff0c;NPU&#xff08;神经网络处理单元&#xff09;也被集成到了处理器里。NPU的…

【GNSS射频前端】MA2769初识

MAX2769 芯片概述&#xff1a; MAX2769是一款单芯片多系统GNSS接收器&#xff0c;采用Maxim的低功耗SiGe BiCMOS工艺技术。集成了包括双输入低噪声放大器&#xff08;LNA&#xff09;、混频器、图像拒绝滤波器、可编程增益放大器&#xff08;PGA&#xff09;、压控振荡器&#…

note38:tdsql数据库迁移

数据迁移过程中遇到的具体问题&#xff1a; ①提供给系统团队的表结构与生产不一致&#xff0c;导致脚本报错。因为历史遗留问题&#xff0c;存在部分直接在生产环境更改字段长度或添加索引的情况&#xff0c;导致测试环境和生产环境的表结构不同步。 今后所有生产的变动&…

Vulkan 学习(5)---- Vulkan 内存分配

目录 Overview枚举内存信息分配内存内存映射 Overview Vulkan 将内存管理的工作交给了开发者自己负责&#xff0c;如何分配内存&#xff0c;如何指定内存策略都是由开发者自己决定的&#xff0c;当然处理问题也是由开发者自己负责的 Vulkan 将内存划分为两大类&#xff1a;主…

Android自定义简单仿QQ运动步数进展圆环

实现效果主要效果分为三个部分&#xff1a; 1.固定蓝色的大圆弧 color borderWidth 2.可以变化的小圆弧(红色) color borderWidth 3.中间的步数文字 color textSize drawArc方法 startAngle 确定角度的起始位置 sweepAngle 确定扫过的角度 useCenter 是否使用中心&#xff1a…

MyBatis XML配置文件(下)

MyBatis的开发有两种方式&#xff1a;1、注解 2、XML。使用MyBatis的注解方式&#xff0c;主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能&#xff0c;建议使用XML来配置映射语句&#xff0c;也就是将SQL语句写在XML配置文件中。 MyBatis XML开发的方式需要以…

UE5学习笔记17-让人物的视线和鼠标移动时的方向一致,并且不让人物模型旋转,只改变视线方向

一、创建标准动画帧 1.我想让人物在装备武器后根据鼠标的移动方向改变人物的视线方向&#xff0c;并且人物模型不会改变朝向 2.我的动画中存在一个四个方向瞄准的动画&#xff0c;将左下&#xff0c;坐上&#xff0c;左转&#xff0c;右上&#xff0c;右下&#xff0c;右转&…

C++ 设计模式——组合模式

C 设计模式——组合模式 C 设计模式——组合模式1. 主要组成成分2. 逐步构建透明组合模式1. 定义抽象组件&#xff08;Component&#xff09;2. 实现叶子组件&#xff08;Leaf&#xff09;3. 实现组合组件&#xff08;Composite&#xff09;4. 主函数&#xff08;Main&#xff…

Nacos踩坑

最近遇到项目部署&#xff0c;遇到Nacos中的配置读取不到&#xff0c;导致服务起不来。服务器银河麒麟x86&#xff0c;Nacos版本2.3.2, openJdk8u43 报错如下&#xff1a; java.lang.UnsatisfiedLinkError: no com_alibaba_nacos_shaded_io_grpc_netty_shaded_netty_transport…

Linux磁盘操作之du命令

使用du命令&#xff0c;您可以查看指定目录或文件的磁盘使用量总计。这对于了解特定目录或文件占用的磁盘空间大小非常有用&#xff0c;可以帮助您进行磁盘空间管理和清理。 参数说明 du是一个用于显示目录或文件的磁盘使用情况的命令&#xff0c;du是disk usage的缩写&#…

从图像到视频:Web Codecs API编码技术解析

初探Web Codecs API 三 前言 在之前的文章中,咱们简单的介绍了解码相关的东西,这一节咱们来简单聊聊编码相关的东西。 编码的目的就是为了压缩,去除空间、时间维度的冗余。 这里又不得不提起前面所说的I 帧、P 帧、B 帧和 IDR 帧。 众所周知,视频是连续的图像序列,由…

【添加核心机械臂动力学】Model and Control a Manipulator Arm with Robotics and Simscape

机械臂动力学 为了设计控制器&#xff0c;机械臂动力学必须表示给定力矩输入的关节位置。这在机械臂动力学子系统中通过一个前向动力学块实现&#xff0c;该块将关节力矩转换为给定当前状态的关节加速度&#xff0c;然后通过两次积分得到完整的关节配置。积分器初始化为q0和dq…

自闭症托管托养机构:星贝育园的优势与使命

在当今社会&#xff0c;自闭症儿童作为一群需要特别关注和照顾的群体&#xff0c;其教育与康复问题日益受到社会各界的重视。自闭症托管托养机构作为这一领域的重要力量&#xff0c;承担着为自闭症儿童提供全方位、个性化支持的重任。星贝育园&#xff0c;作为一所全日寄宿制的…