文件的IO

news2024/11/16 5:47:38

一、文件的定义

狭隘的文件:指你的硬盘上的文件和目录.

广义的文件:泛指计算机中的硬件资源,操作系统中,把很多硬件设备和软件资源都抽象成了文件,按照文件的形式统一管理.比如网卡,操作系统也是把网卡抽象成了文件资源,所以说操作网卡其实和操作文件的方式是基本一样的.

而我们本章节只考虑狭义的文件.

二、路径

路径分为:绝对路径和相对路径

    • 绝对路径:C:\Program Files\Java\jdk1.8.0_192

这样的路径就叫做绝对路径.

2.相对路径:以当前目录为基准,以.或者..开头(.有时候可以省略),找到指定路径.

当前目录在程序运行中被称为工作目录.

打开控制台,默认的工作路径就是:

如这个:想要定位111这个文件夹,我们就可以使用相对路径定位法.

此时工作目录就是"d:/tmp"

则111文件夹的相对路径就是:"./111".

但如果工作目录是"d:/tmp/222"

那么相对路径就是"../111"(注意:这里的".."指的是返回上一级目录)

三、文件的类型

现在的市面上有众多的文件:word、exe、图片、视频、音频......

这些不同的文件,可以归到两类的文件里去:

    • 文本文件(存的是文本,字符串)
    • 二进制文件(存的是二进制文件,不再是字符串了)

检验方式:直接用记事本打开文件,如果乱码了就是二进制文件,如果能够正常读取,就是文本文件.(因为记事本是以文本文件的方式进行存储)

另外,文本文件和二进制文件的操作方式是不同的.

四、Java对于文件的基本操作

1.

这个就相当于路径中的"/",如果代码需要进行多语言的运行,有的语言没有"/"的识别,则需要pathSeparator进行分割.

2.构造方法

最常见的构造方法指定路径的方法是第二个:使用文件的直接路径进行调用.

3.常用方法

构造方法中的文件路径不需要真实存在,因为File中有方法可以对文件进行手动创建文件.

就是这个方法:

绝对路径:

File类的方法都是"人如其名"

另外,在文件IO这块很容易抛出异常,因为文件是存放在硬盘中的,而硬盘是电脑中最容易出问题的部分了(如坏了或者说硬盘满了).

相对路径:

注意:这里的文件路径是在Jvm包中的test.txt,也就是在

这个工作路径下的"test.txt"

这里着重说一下getAbsolutePath()与getCanonicalPath()两个方法,他们都是获取文件的绝对路径,只不过

getAbsolutePath()是获取不加修饰的文件绝对路径,而getCanonicalPath()是获取经过修饰的绝对路径.

在此时,Idea的目录下面没有创建"test.txt",所以说判断是否存在是否是文件是否是目录都是false

在手动创建完文件后,是否存在,是否是文件都是true是否是目录都是false.

我们可以创建文件当然也可以删除文件:

另外,还有一个deleteOnExit作用是:能够在程序结束的时候将这个文件删除.

(被称为临时文件)

比如我们在打开word文档时就会生成一个临时文件:

关闭目录后就会消失.

这个临时文件相当于实时保存了你文件中的内容,如果硬盘损坏或者断电了,没有保存的内容就没了.

目录的创建:

运用file.mkdirs()

mkdirs()可以创建多级目录.

文件重命名:

这样就可以把之前的"test"文件夹改名为testAAAAAAAA.

五、"流"对象

1."流"的概念

针对文件内容,使用"流对象"进行操作.

什么叫做"流对象":类比水流,就是指对文件的操作就好比水流一样,想流多少,就流多少.

就是说编译器操作文件也是一样,想读多少,就读多少.假如共有100个字节,我想读100个就读1次,我想读10个就读10次.

    • 操控"流"对象

操控"流"对象,总共分为两大类:

1)字节流:(操作二进制文件的)

主要的两个类:InputStream、OutputStream 子类:FileInputStream、FileOutputStream

注意:InputStream类是不能new的,因为InputStream类是个抽象类.

首先是开与关:

然后就是如操作了:

我们的读操作有三个版本:

无参数版本:一次读一个字节.

一个参数版本:把读到的内容存到这个数组里,(此处参数是输出型参数),返回值是读取到的字节数

三个参数版本:和2类似只不过是在一定空间里尽可能填满数组.

注意:虽然read读取的是一个字节,但它的返回值是int

原因:当read读完文件时,就会返回-1,来表示文件已经读完.

结果返回的是字符,返回的数字可以用ASCII进行转换成对应的字符.

另外,还可以利用字节流读取的另外一种方式:(使用在read中填写字符数组的形式读取)

我们发现和上面的结果是一样的.

这里的传参操作,相当于把刚才准备好的数组将给read方法,让read方法内部针对这个方法进行填写.

此处的参数相当于"输出型参数".

在Java中通常是把输入的信息作为参数,输出的信息作为返回值.但也有少数情况,是使用参数来返回内容的(输出型参数),但这是在C++中很常见.

inputStream.read()的本质是的读取字节,如果在读取的过程中发现读不到内容后才返回-1.上述代码设置了数组的最大阅读长度:1024.

如果读取的内容长度大于1024,程序则会覆盖之前读的内容继续读取,直到返回-1.

所以说文件操作一般都是读一部分处理一部分,不会等文件全部多玩再进行处理.


这里回忆一下抽象类和接口有什么区别:

抽象类和普通类:几乎没有区别,只不过抽象类不能够new而且带了抽象方法

接口比抽象类更加抽象,抽象:指信息的描述更加少.

抽象类还可以有普通成员,普通方法,抽象成员,抽象方法,但是接口就只能有抽象方法和抽象成员.


我们可以用intputStream读文件,也可以用outputStream写文件:

这里采用控制台循环输入的方式如果输入-1就停止.

注意:对于我们的OutputStream来说,默认情况下,会清空文件原有的内容.(这样的话之前的内容就没了)

如果我们不想清空之前的内容,流对象还提供了一个"追加写"对象,通过这个就可以实现不清空文件,把新的内容写到后面.

这里再说一下close()操作:

在我们多线程的PCB运行过程的同时,会运行一个文件描述符表(就是一个可以存放表的数组),这个表会记录每个线程打开的文件(这也是多线程进行信息交互的方式之一)打开文件操作会申请一个位置用来存放这个表,每次关闭文件,也就会把表从这个文件描述符表中释放掉.

如果我们不释放,会发生什么呢?

注意:文件描述符表这个数组是不会扩容的,虽然有自动释放功能,但可能不够即使及时,一但文件描述符表满了文件打开操作就会发生错误,导致程序崩溃.

但是,因为close()常见操作(就是如果出现if+break)之类的问题所以我们的常见操作是:

这是我们推荐的操作,在Java中被称为try with resources,在这个代码虽然没有显式的close,但是当try的部分执行完毕后,就可以自动执行到close的!!!

点入OutputStream中去,发现该类实现了Closeable接口,这个方法就是提供了close().

try with resources是文件IO中最方便的表述形式,所以我们后面讲全部采用这种形式.

2)字符流:(操作文本文件的)

主要的两个类:Reader、Writer 子类:FileReader、FileWriter

这些类的操控都是相对固定的,主要分为四个操作:1.打开文件(构造对象)2.关闭文件(close)3.读文件(read)针对InputStream、Reader4.写文件(write)针对OutputStream、Writer

跟上面一样的代码形式,作用是读取字符

因为汉字也是用字符表示的,所以也可以读取汉字.

写入方法也是一样:

这个我们来说一下Scanner:

如果我们点入System可以发现其实System也是一个流对象

所以说,按道理来讲我们将inputStream对象填入括号中也是可以的.

Scanner控制台就读取控制台内容,Scanner文件就读取文件内容,Scanner能读取所有的流对象.

六、案例

1.扫描目录,并找到名称中包含的指定字符所有普通文件(不包含目录),并且询问用户是否要删除该文件.

就相当于:

首先,做好准备工作,将代码的输入路径和指定删除文件部分完成:

接下来,完成目录的扫描能力部分:

我们首先要弄清目录是以书的形式存储的,对应的我们在遍历目录的时候可以使用递归的形式.如果是要删除文件,就删除,如果不是就下一个

这个代码要注意几点:

  1. 将输入的根目录一下的不管是目录还是文件都放入File[ ]数组,便于之后遍历数组.

  1. 判断是不是目录,如果是就继续递归,如果不是就将文件名和要删除文件进行比对,如果比对成功就删除.

  1. 在比对的过程中需要对用户进行询问,如果用户同意再删除,如果不同意就取消删除.

package IODemo6;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86139
 * Date: 2023-01-29
 * Time: 17:53
 */
public class IODemo8 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入要查找的路径:");
        String path=scanner.next();
        File root=new File(path);
        if(!root.isDirectory()){
            System.out.println("您输入的路径有误!!!");
            return;
        }
        System.out.println("请输入您要删除的文件名:");
        String filename=scanner.next();
        scanDir(root,filename);
    }

    private static void scanDir(File root, String filename) {
        File[] files=root.listFiles();
        if(files==null){
            return ;
        }
        for (File f:files) {
            if(f.isDirectory()){
                scanDir(f,filename);
            }else{
                if(f.getName().contains(filename)){
                    System.out.println("是否删除"+f.getAbsolutePath()+"文件");
                    Scanner scanner=new Scanner(System.in);
                    String choice=scanner.next();
                    if(choice.equals("y")||choice.equals("Y")){
                        f.delete();
                        System.out.println("删除成功!!!");
                    }else{
                        System.out.println("删除取消!!!");
                    }
                }
            }
        }
    }
}

2.进行普通文件的复制(就是把一个文件拷贝成另一个文件,把第一个文件按照字节的方式进行读取,然后拷贝到第二个文件里)

首先,进行文件的读取与判断:

接下来,打开源文件的输入流对象和目标文件的输出流对象:

然后我们采取读一个字节,写一个字节的形式进行拷贝:

这样代码就完成了.

我们发现拷贝成功了!!!

package IODemo6;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86139
 * Date: 2023-01-29
 * Time: 18:35
 */
public class IODemo9 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入要拷贝文件的源目录:");
        String srcPath=scanner.next();
        System.out.println("请输入要拷贝文件的目标目录:");
        String destPath=scanner.next();
        File srcFile=new File(srcPath);
        if(!srcFile.isFile()) {
            System.out.println("您输入的源文件有误!!!");
        }
        File destFile=new File(destPath);
        try(InputStream srcInputStream=new FileInputStream(srcFile);
        OutputStream destOutputStream=new FileOutputStream(destFile)) {
            while(true){
                int b=srcInputStream.read();
                if(b==-1){
                    break;
                }
                destOutputStream.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:这里的outputStream能够无中生有,不需要目标文件存在.

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

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

相关文章

初识流计算框架Spark

Spark简介 Spark最初由美国加州伯克利大学(UCBerkeley)的AMP(Algorithms, Machines and People)实验室于2009年开发,是基于内存计算的大数据并行计算框架,可用于构建大型的、低延迟的数据分析应用程序。Sp…

一刷代码随想录——链表

1.理论基础链表节点的定义:struct ListNode {int val;ListNode* next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* next) : val(x), next(next) {} };根据卡哥提示,由于力扣中已经给出如…

C++中拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符(三/五法则)

1、介绍 三五法则是针对C中类的成员和类对象的操作函数。 三法则是指:拷贝构造函数、拷贝赋值运算符、析构函数。 五法则是在三法则的基础上增加了:移动构造函数、移动赋值运算符。 2、拷贝构造函数 定义:如果构造函数的第一个参数是自身…

Postman前置脚本

位置:作用:调用脚本之前需要执行的代码片段一、产生随机数字生成0-1之间的随机数,包括0,不包括1;var random Math.random();console.log("随机数",random);获取最小值到最大值之前的整数随机数function Get…

2019-ICML-Graph U-Nets

2019-ICML-Graph U-Nets Paper: https://arxiv.org/abs/1905.05178 Code: https://github.com/HongyangGao/Graph-U-Nets 图U-Nets 作者将CNN上的U-Net运用到了图分类上,因为我们主题是图分类,就不对U-Net进行论述了,只对其中的gPool&#…

eureka 读写锁的一点思考

读写锁 读写锁一般实现 读读不互斥 读写互斥 写写互斥 读写锁的好处是,面对读多写多的场景会拥有比较好的表现 一般我们会在读操作加上读锁,写操作加上写锁。但是最近我发现eureka 在使用读写锁的时候是相反的, 也就是说在读操作加上了读锁&…

2023最值得入手的运动耳机是哪款、口碑最好的运动蓝牙耳机推荐

不知道有没有和我一样的小伙伴,在运动时特别喜欢听音乐,每次听到一首合适的音乐,感觉运动起来都更有激情和活力了。所以这时候就需要挑选一款舒适的耳机了。别看市面上各种各样的运动耳机很多,但实际上能真正适合运动的少之又少&a…

oss服务端签名后直传分析与代码实现

文章目录1.简介1.1 普通上传方式1.2 服务端签名后直传3.服务端签名后直传文档3.1 用户向应用服务器请求上传Policy和回调。3.2 应用服务器返回上传Policy和签名给用户。3.3 用户使用Post方法向OSS发送文件上传请求。4.实战开发-后端4.1 pom.xml核心配置4.2 application.yml核心…

Java两大工具库:Commons和Guava(2)

您好,我是湘王,这是我的CSDN博客。值此新春佳节,我给您拜年啦~祝您在新的一年中所求皆所愿,所行皆坦途,展宏“兔”,有钱“兔”,多喜乐,常安宁!开发中有一类应…

如何在es中查询null值

文章目录1、背景2、需求3、准备数据3.1 创建mapping3.2 插入数据4、查询 name字段为null的数据5、查询address不存在或值直接为null的数据6、参考链接1、背景 在我们向es中写入数据时,有些时候数据写入到es中的是null,或者没有写入这个字段,…

离散数学与组合数学-08谓词逻辑

文章目录离散数学与组合数学-08谓词逻辑8.1 谓词的引入8.1.1 引入谓词逻辑8.1.2 个体词与谓词8.2 量词的引入8.2.1 量词引入8.2.2 个体域符号化8.2.3 量词真值确定8.3 谓词符号化举例8.3.1 示例一8.3.2 示例二8.3.3 示例三8.3.4 示例四8.4 谓词合式公式8.4.1 四类符号8.4.2 项8…

MySQL运维(一)MySQL中的日志、Mysql主从复制

MySQL运维(一)MySQL中的日志、Mysql主从复制 1、MySQL日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#…

Elasticsearch 需要了解的都在这

ES选主过程?其实ES的选主过程其实没有很高深的算法加持,启动过程中对接点的ID进行排序,取ID最大节点作为Master节点,那么如果选出来的主节点中存储的元信息不是最新的怎么办?其实他是分了2个步骤做这件事,先…

react 项目 中使用 Dllplugin 打包优化技巧

目录 0.React和DLLPlugin 前言 使用步骤 结果截图 主要说明 0.React和DLLPlugin React 是一个用于构建用户界面的 JavaScript 库。它由 Facebook 开发,现在由 Facebook 和一个由个人开发者和公司组成的社区维护。React 允许开发人员构建可重用的 UI 组件并有…

“回文子串、最长回文子序列”总结,动态规划再显神通(Java实现)

目录 一、回文子串 1.1、dp定义 1.2、递推公式 1.3、初始化 1.4、遍历顺序 1.5、解题代码 二、最长回文子序列 2.1、dp定义 2.2、递推公式 2.3、初始化 2.4、遍历顺序 2.5、解题代码 一、回文子串 题目描述: 题目来源:647. 回文子串 1.1、dp定…

解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题

模型训练过程中常需边训练边做validation或在训练完的模型需要做测试,通常的做法当然是先创建model实例然后掉用load_state_dict()装载训练出来的权重到model里再调用model.eval()把模型转为测试模式,这样写对于训练完专门做测试时当然是比较合适的&…

ssm学生心理健康测评网的规划与设计

摘 要 1 Abstract 1 1 绪论 1 1.1 课题背景 1 1.2 课题研究现状 1 1.3 初步设计方法与实施方案 2 1.4 本文研究内容 2 2 系统开发环境 4 2.1 JSP技术介绍 4 2.2 B/S模式 4 2.3 MySQL环境配置 5 3 系统分析 6 3.1 系统可行性分析 6 3.1.…

【模糊神经网络】基于模糊神经网络的倒立摆轨迹跟踪控制

临近春节没啥事做,突然想起前两年未完成的模糊神经网络,当时是学了一段时间,但是到最后矩阵求偏导那块始终不对,最后也不了了之了,趁最近有空,想重新回顾回顾,看看会不会产生新的想法。经过不断…

elasticsearch基本操作

elasticsearch基本操作基础两种模式:ik分词器词库拓展索引库操作mapping映射属性typeindexanalyzerproperties索引库的CRUD创建修改查询删除文档操作创建查询修改删除基础 本教程使用es8.6.0与kibana作为测试环境 打开开发工具 ## 1.查看节点信息 GET /_cat/nodes?v ## 2.查…

【JUC并发编程】深入浅出Java并发基石——AQS

【JUC并发编程】深入浅出Java并发基石——AQS 参考资料: RedSpider社区——第十一章 AQS 深入剖析并发之AQS独占锁 1.5w字,30图带你彻底掌握 AQS! 深入浅出AbstractQueuedSynchronizer 我画了35张图就是为了让你深入 AQS 动画演示AQS的核心原…