【JavaEE初阶】文件IO(下)

news2024/12/23 19:07:11

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



目录

 文件内容操作

打开 关闭文件

文件描述符表

字节流

读文件

写文件

字符流

读文件

写文件

Scanner 

示例一:通过scanner读取文件中的数字

示例二:扫描指定⽬录

示例三:实现文件复制


 文件内容操作

 文件内容操作:读文件 和 写文件,操作系统都提供了API,Java也进行了封装

Java实现IO流类 有很多,分为 字节流(二进制)和字符流(文本) 两大类

上面这四个类都是抽象类,Java中还提供了许多类 来实现这四个抽象类

  • 但凡类的名字以Reader Writer结尾的,就是实现了Reader和Writer的字符流对象
  • 但凡类的名字以InputStream OutputStream结尾的,就是实现了InputStream和OutputStream的字节流对象

在这里谈到的输入输出,都是以cpu视角来说的:

  • 数据远离cpu =>输出
  • 数据靠近cpu =>输入

打开 关闭文件

示例1

这种写法,虽然能够确保严谨,但是比较麻烦

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

public class Demo9_IO {
    public static void main(String[] args)  {
        InputStream inputStream=null;
        try {
            inputStream = new FileInputStream("./test.txt");//隐含了打开文件
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally{
            try {
                inputStream.close();//关闭文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

如果不使用close关不上,会发生什么?

打开文件 其实是在该进程的 文件描述符表 中,创建了一个新的表项

文件描述符表

文件描述符表 描述了该进程都需要哪些文件,可以认为是一个数组,数组的每个元素就是一个struct file 对象(Linux内核),每个结构体就描述了对应操作的文件信息,数组下标 就称为"文件描述符"

示例2:这种写法更简单可靠

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

public class Demo10 {
    public static <inputStream> void main(String[] args) {
        try(InputStream inputStream=new FileInputStream("./test.txt")) {

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

这里代码中,不用写close关闭,因为close之后,紧接着就是进程的结束(意味着pcb就整个销毁,pcb上的文件描述符表,整个就释放了)

字节流

读文件

读文件 :数据从硬盘上读取到 内存里

示例1:读取test.txt文件的内容,以16进制方式输出

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

public class Demo10 {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    // 读取完毕了
                    break;
                }
                // 表示字节, 更习惯使用 十六进制 打印显示.
                System.out.printf("0x%x\n", b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

示例1代码 要频繁读取多次硬盘,当前硬盘的IO是消耗比较大

示例2:使用buffer(缓冲区,暂时存储某些数据),;将硬盘上的数据先填充到buffer内存的字节数组中,尽可能填满  ,虽然一次读的内容多了,但是仍然比一次读一个字节,分多次读效率要高不少

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

public class Demo11 {
    public static void main(String[] args) {
        try(InputStream inputStream = new FileInputStream("./test.txt")){
            while(true){
                byte[] buffer =new byte[1024];
                //n返回值表示read操作,实际读取到多少个字节
                int n=inputStream.read(buffer);
                if(n==-1){
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("0x%x\n",buffer[i]);
                }
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

写文件

写文件和读文件非常类似

一个一个字节写入

        try(OutputStream outputStream=new FileOutputStream("./test.txt")){
            outputStream.write(0x61);
            outputStream.write(0x62);
            outputStream.write(0x62);
            outputStream.write(0x62);
        }catch (IOException e){
            e.printStackTrace();
        }

这里的写操作,会默认把之前的内容清空(只要使用outputStream打开文件,内容就没了),再进行写操作,可以使用"追加写"操作,保持原内容不变,在末尾继续写入内容

InputStream/OutputStream读写数据就是按照字节来操作的,如果要读写字符(中文)的话,就需要程序员手动来区分出哪几个字节是一个字符,在确保把这几个字符作为整体来写入

字符流

为了方便处理字符,引入了字符流

读文件

使用字符流读取数据的过程,Java标准库内部就自动对数据的编码进行了转码

示例1:一个一个字符读入

        try(Reader reader= new FileReader("./test.txt")){
            while(true){
                int c=reader.read();
                if(c==-1){
                    break;
                }
                char ch=(char)c;
                System.out.println(ch);
            }
        }catch(IOException e){
            e.printStackTrace();
        }

示例2:读取一串字符

try (Reader reader = new FileReader("./test.txt")) {
            char[] buffer = new char[1024];
            int n = reader.read(buffer);
            System.out.println(n);
            for (int i = 0; i < n; i++) {
                System.out.println(buffer[i]);
            }
        } catch (IOException e) {

        }

写文件

        try(Writer writer=new FileWriter("./test.txt",true)){
            writer.write("你好世界");
        }catch(IOException e){
            e.printStackTrace();
        }

Scanner 

读取文件还有一个好用的工具类:Scanner

示例一:通过scanner读取文件中的数字

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

public class Demo16_scanner {
    public static void main(String[] args) {
        try(InputStream inputStream=new FileInputStream("./test.txt")){
            Scanner scanner=new Scanner(inputStream);
            while(scanner.hasNextInt()){
                System.out.println(scanner.nextInt());
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

示例二:扫描指定⽬录

并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)

import java.io.File;
import java.util.Scanner;

public class Demo17 {
    private static void scan(File currentFile, String key) {
        if (!currentFile.isDirectory()) {
            return;
        }
        File[] files = currentFile.listFiles();
        if (files == null || files.length == 0) {
            return;
        }

        for (File f : files) {
            if (f.isFile()) {
                // 针对普通文件进行处理.
                // 判定文件名是否符合要求并提示用户删除
                doDelete(f, key);
            } else {
                // 针对目录进行处理
                // 继续递归
                scan(f, key);
            }
        }
    }

    private static void doDelete(File f, String key) {
        if (!f.getName().contains(key)) {
            // 文件名中不包含指定的关键字.
            return;
        }
        // 提示用户, 是否确认要删除
        Scanner scanner = new Scanner(System.in);
        System.out.println(f.getAbsolutePath() + " 是否确认要删除 Y/n");
        String choice = scanner.next();
        if (choice.equals("Y") || choice.equals("y")) {
            f.delete();
        }
    }

    public static void main(String[] args) {
        System.out.println("请输入要搜索的路径: ");
        Scanner scanner = new Scanner(System.in);
        String rootPath = scanner.next();
        File rootFile = new File(rootPath);
        if (!rootFile.isDirectory()) {
            System.out.println("输入的路径不存在");
            return;
        }
        System.out.println("请输入要删除的文件名字的关键字");
        String key = scanner.next();

        // 进行递归查找
        scan(rootFile, key);
    }
}

示例三:实现文件复制

将一个文件里的每个字节都读出来,写入到另一个文件里

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

public class Demo18 {
    public static void main(String[] args) {
        //1.输入路径,并做校验
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入源文件的路径: ");
        String srcPath=scanner.next();
        File srcFile= new File(srcPath);
        if(!srcFile.isFile()){
            System.out.println("源文件路径有误");
            return;
        }
        System.out.println("请输入目标文件的路径: ");
        String destPath = scanner.next();
        File destFile =new File(destPath);
        if(!destFile.getParentFile().isDirectory()){
            System.out.println("目标文件路径有误");
            return;
        }

        //2.执行复制操作
        try(InputStream inputStream = new FileInputStream(srcFile);
        OutputStream outputStream = new FileOutputStream(destFile)){
            while(true){
                byte[] buffer =new byte[1024];
                int n=inputStream.read(buffer);
                System.out.println("n="+n);
                if(n == -1){
                    break;
                }
                //需要把buffer写入到outputStream中
                outputStream.write(buffer,0,n);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

示例四

实现递归遍历目录"查找文件",按照文件的内容查询

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

public class Demo19 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要搜索的路径: ");
        String rootPath = scanner.next();
        File rootFile = new File(rootPath);
        if (!rootFile.isDirectory()) {
            System.out.println("要搜索的路径有误!");
            return;
        }
        System.out.println("请输入要搜索的查询词: ");
        String key = scanner.next();

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

    private static void scan(File rootFile, String key) {
        if (!rootFile.isDirectory()) {
            return;
        }
        File[] files = rootFile.listFiles();
        if (files == null || files.length == 0) {
            return;
        }
        for (File f : files) {
            if (f.isFile()) {
                // 进行后续的查询操作
                doSearch(f, key);
            } else {
                // 进行递归
                scan(f, key);
            }
        }
    }

    private static void doSearch(File f, String key) {
        // 打开文件, 读取文件内容, 判定文件内容是否包含 key
        StringBuilder stringBuilder = new StringBuilder();

        try (Reader reader = new FileReader(f)) {
            char[] buffer = new char[1024];
            while (true) {
                int n = reader.read(buffer);
                if (n == -1) {
                    break;
                }
                String s = new String(buffer, 0, n);
                stringBuilder.append(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (stringBuilder.indexOf(key) == -1) {
            // 未找到
            return;
        }
        // 找到了
        System.out.println("找到匹配的文件: " + f.getAbsolutePath());
    }
}

此处这里的代码逻辑 效率是非常低的,每次查询都会涉及大量的硬盘IO操作,尤其是硬盘上可能有一些大的文件

这种思路,不能适应频繁查询场景,也不能适应目录中文件数目特别多,特别大的场景(实现搜索引擎)

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

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

相关文章

JUC第23讲:Java线程池最佳实践

JUC第23讲&#xff1a;Java线程池最佳实践 本文是JUC第23讲&#xff0c;先介绍为什么使用线程池&#xff1b;然后结合实际业务&#xff0c;讲解如何使用线程池&#xff0c;以及使用过程中踩过的坑。 1、Java线程池概述 1.1、什么是线程池&#xff1f; 线程池是一种用于管理和…

彩虹易支付最新版源码及安装教程(修复BUG+新增加订单投诉功能)

该系统也没版本号&#xff0c;此版本目前是比较新的版本&#xff0c;增加了订单投诉功能&#xff0c;和一个好看的二次元模板。 此版本是全开源版&#xff0c;无一处加密文件,系统默认是安装后是打不开的&#xff0c; 本站特别修复了BUG文件&#xff0c;在PHP7.4环境下也没问…

数据结构和算法之树形结构(4)

文章出处&#xff1a;数据结构和算法之树形结构(4) 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01;&#xff01; 六、红黑树(接前篇) 红黑树是为了弥补AVL树在大规模频繁增删节点场景下性能不理想而设计出来的一种平衡二叉查找树。红黑树不是一种严…

cuda程序编译流程

cuda程序编译流程 本文以cuda example的matrixMul矩阵乘法为例说明cuda程序的编译流程。 1. 源代码 .cu 文件 在matrixMul示例中&#xff0c;源代码文件 matrixMul.cu 是典型的CUDA程序&#xff0c;包含以下部分&#xff1a; 流程图 主机代码&#xff08;Host Code&#xf…

Vivado - JTAG to AXI Master (GPIO、IIC、HLS_IP)

目录 1. 简介 2. JTAG to AXI Master 2.1 添加 IP Core 2.2 基本TCL命令 2.2.1 复位 JTAG-to-AXI Master 2.2.2 创建并运行写入传输事务 2.2.3 创建并运行读取传输事务 2.2.4 命令列表 2.3 帮助信息 2.4 创建TCL读写程序 2.4.1 Read proc 2.4.2 Write proc 2.4.3 …

嵌入式学习--LinuxDay03

嵌入式学习--LinuxDay03 shell脚本 1.1功能性语句 1.1.1说明性语句 1.1.2功能性语句 1&#xff09;read 2&#xff09;expr 3) test a)字符串 b)整数的测试 c)文件属性的测试 1.2结构性语句 1.2.1if语句 1.2.2case语句 1.2.3for循环 1.2.4while循环 1.2.5循环控制语句 shell脚本…

心觉:运用吸引力法则和开发潜意识的核心中的核心是什么?

吸引力法则的核心在于 思想的力量 和 频率的匹配。你所思考和感受的会吸引与你频率相匹配的事物和经历到你的生活中。具体来说&#xff1a; 明确意图和目标&#xff1a;清晰地知道你想要什么&#xff0c;并且用详细的方式描述它。这可以是通过写下目标、制作愿景板&#xff08;…

rocky9.2实现lvs(DR模式)+keepalived实现高可用的案例详解(双机热备、lvs负载均衡、对后端服务器健康检查)

文章目录 [TOC] 前言lvs(DR模式)的工作原理环境实现过程一、lvs1配置二、lvs2配置web1配置web2配置结果验证 总结 前言 想必能搜到这个也不是来看知识点的&#xff0c;这里就简单描述一下lvs的dr模式的工作原理&#xff0c;其他的就不过多阐述了,直接看操作步骤就好&#xff0…

rabbitMQ 简单使用

安装 rabbitMQ 下载地址&#xff1a;rabbitmq-3.12.0 安装 windows rabbitMQ 需要的命令 进入 rabbitMQ 的 sbin 目录后 cmd &#xff08;需要管理员权限&#xff09; rabbitmq-plugins.bat enable rabbitmq_management随后重启 rabbitMQ #关闭服务 net stop rabbitmq #开…

【机器学习(八)】分类和回归任务-因子分解机(Factorization Machines,FM)算法-Sentosa_DSML社区版

文章目录 一、算法概念二、算法原理&#xff08;一&#xff09; FM表达式&#xff08;二&#xff09;时间复杂度&#xff08;三&#xff09;回归和分类 三、算法优缺点&#xff08;一&#xff09;优点&#xff08;二&#xff09;缺点 四、FM分类任务实现对比&#xff08;一&…

YOLOV8在清微智能芯片的部署与实现(一)

现在以YOLOV8 为例&#xff0c;进行演示 文章目录 1. YOLOV8浮点模型训练1.1 准备数据集1.1.1 下载业务数据集1.1.2 下载开源数据集1.1.3 自定义数据集1.1.4 将数据转换为yolo训练数据格式 1.2 yolov8项目准备1.3 训练模型 2. YOLOV8浮点模型推理2.1 模型推理2.2 模型val.py评…

纯CSS实现有趣emoji切换开关

这是一个纯CSS创建的动画切换开关&#xff0c;它不仅能够在视觉上吸引用户&#xff0c;还能通过交互提供即时反馈。本文将解析源码的核心实现逻辑&#xff0c;这个项目的核心是使用CSS变量、3D变换和过渡效果来实现一个动态的、响应式的用户界面元素。 关键技术点 CSS变量&am…

[Python学习日记-31] Python 中的函数

[Python学习日记-31] Python 中的函数 简介 语法定义 函数的参数 简介 引子&#xff1a; 你是某公司的一个高级程序员&#xff0c;现在老板让你写一个监控程序&#xff0c;需要24小时全年无休的监控公司网站服务器的系统状况&#xff0c;当 CPU、Memory、Disk 等指标的使用…

基于SpringBoot+Vue+MySQL的体育商城系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着互联网的飞速发展&#xff0c;电子商务已成为人们日常生活中不可或缺的一部分。体育用品市场作为其中的一个重要分支&#xff0c;也逐渐向线上转移。基于SpringBootVueMySQL的体育商城系统应运而生&#xff0c;旨在通过构建…

如何使用ssm实现基于Java的高校物业工程报修系统

TOC ssm736基于Java的高校物业工程报修系统jsp 绪论 1.1研究背景与意义 信息化管理模式是将行业中的工作流程由人工服务&#xff0c;逐渐转换为使用计算机技术的信息化管理服务。这种管理模式发展迅速&#xff0c;使用起来非常简单容易&#xff0c;用户甚至不用掌握相关的专…

一行命令将Cmder添加到系统右键菜单中----配置环境

第一步&#xff0c;去官网下载一个简版的文件 ** 第二步&#xff0c;将下载的文件解压后如图&#xff0c;找到Cmder.exe右键以管理员身份运行 第三步&#xff0c;在窗口输入cmder /register all然后回车 第四步&#xff0c;OK!不管在哪里都可以使用了&#xff0c;直接右键即可

vscode环境迁移

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间 vscode环境迁移 Setting 即可打开settings.json {"python.pythonPath": "/Users/apple/opt/anaconda3/bin/python","cmake.cmakePath": "/usr/local/bin/cmake",&qu…

[c++高阶]模版进阶

1.前言 在我们学习c的时候&#xff0c;常常会遇见要使用函数重载的情况。而当使用函数重载时&#xff0c;通常会使得我们编写很多重复的代码&#xff0c;这样就显得非常臃肿&#xff0c;并且效率非常的低下。 重载的函数仅仅只是类型不同&#xff0c;代码的复用率比较低&#x…

浮点数的这些特性你了解吗

问题1:下面的代码&#xff0c;输出结果是什么&#xff1a; public class CaclTest{public void test1(){float f 1.0F / 0.0F;System.out.println("f:" f)}public static void main(String[] args){CaclTest ct new CaclTest();ct.test1();}} A. 运行抛出异常:j…

7.数据结构与算法-循环链表

如果经常对首位元素进行操作&#xff0c;用尾元素更方便更快捷 两个循环链表合并