文件操作 和 IO

目录

​编辑一、认识文件

1、文件路径

2、其它知识

二、Java 中操作文件

三、文件内容的读写

1、Reader

2、InputStream

3、输出


一、认识文件

 文件是在硬盘上存储数据的一种方式,操作系统帮我们把硬盘的一些细节都封装起来了

我们只需要了解文件相关的一些接口即可

硬盘是用来存储数据,和内存相比,硬盘的存储空间更大,访问速度更慢,成本更低,可以持久化存储

操作系统通过 “文件系统” 这样的模块来管理硬盘

实际上我的电脑只有一个硬盘,操作系统可以通过文件系统把这个硬盘抽象成多个硬盘一样 NTFS 是windows 上的文件系统,背后有一定的格式来组织硬盘数据

 EXT4 是 Linux 上常见的文件系统


1、文件路径

不同的文件系统,管理文件的方式都是类似的

通过 目录 - 文件 构成了 “ N 叉树” 树形结构

通过 D盘 - tmp - cat.jpg 这个路线,就能 找到 / 确定 电脑上的唯一一个文件,这个东西就称为 “路径”

在 windows 上,使用 / 或者 \ 来分割不同的目录

以盘符开头的路径,也叫做 “绝对路径”

绝对路径相当于与是从 “此电脑” 这里出发,找文件的过程

以 . 或者 ... 开头的目镜,叫做 “绝对路径”

相对路径,需要有一个 “基准目录” / “工作目录”,表示从这个基准出发,怎么走能找到这个文件夹

如果以 D:为基准目录 ./tmp/cat.jpg  如果以 D:tmp 为基准 ./cat.jpg (. 表示当前所在目录)

如果以 D:/tmp/111 为基准, ..cat.jpg(..表示当前目录的上一级目录)

同样是一个 cat.jpg 文件,站在不同的基准目录上找到的路径是不一样的


2、其它知识

文件系统上存储的文件,又可以分成两个大类

1、文本文件

存储的是字符

例如:utf-8 就是一个大表,这个表上的数据的组合,就可以称为字符

2、二进制文件

存储的是二进制的数据

如何判断文件是文本文件还是二进制文件?

一个最简单的方式:直接使用记事本打开

记事本打开文件,就是尝试把当前的数据,在码表中查询

如果打开之后能看懂,就是文本文件,如果打开之后看不懂,就是二进制文件


二、Java 中操作文件

后续针对文件的操作,文本和二进制的操作方式是不同的

文件系统操作:创建文件,删除文件,创建目录....

java 中,不要通过 java.io.file 类来对一个文件(包括目录)进行具体的描述

IO : input 和 output,我们是站在 cpu 的视角来看待输入输出的

通过 File 对象来描述到一个具体的文件

File 对象可以对应到一个真实存在的文件,也可以对应到一个不存在的文件

构造方法:

第二个构造方法此处的字符串,就表示一个路径,可以是绝对路径,也可以是相对路径

方法: 

站在操作系统的角度来看待:目录也是文件

操作系统的文件是一个更广义的概念,具体来说有很多不同的类型

1、普通文件(通常见到的文件)

2、目录文件(通常见到的文件夹)

windows 上,目录之间的分隔符,可以使用 / 也可以使用 \ 

Linux 和 mac 上面,就只支持 /

所以即使在 windows 上,也尽量使用 / ,使用 、 在代码中需要搭配转义字符

可以通过代码,来感受一下对文件的操作: 当我们把绝对路径改成相对路径,代码运行结果又会有所不同:

 getAbsolutePath 会将工作目录拼接上当前目录,就是运行的结果

在 idea 中运行一个程序,工作目录就是项目所在的目录,在命令行中 运行一个程序,工作目录就是命令行当前所在的目录,如果程序是运行在 tomacat 中,工作目录就是 tomcat 下的 bin 目录

这个操作是可能会抛出异常的

比如,当前写入的路径是一个非法的路径

比如,当前创建的这个文件,对于所在的目录没有权限操作

有的时候,可能会用到这样的一个功能:临时文件

程序运行的时候,搞一个临时文件,程序结束了,临时文件中自动删掉

像 office 等很多这样的生产力软件 都有产生临时文件功能,这个临时文件就自动保存了你当前的编辑的中间状态

有的人使用 word 不喜欢保存,用了一段时间之后,电脑突然断电关机了,没保存的数据难道就没了吗?

重启电脑,由于刚才是非正常关闭,临时文件是来不及删除,仍然存在的moffice 启动就能知道上次是异常关闭了,就会提示你是否要从之前的临时文件恢复未保存的数据 

 创建目录代码:

import java.io.File;
import java.io.FileReader;public class Demo4 {public static void main(String[] args) {File file = new File("./test-dir");//mk -> make dir->directory//mkdir 一次只能创建一层目录,mkdirs 可以一次创建多层目录file.mkdir();//file.mkdirs();}
}

 文件重命名也可以起到文件移动的效果

import java.io.File;//文件重命名
public class Demo5 {public static void main(String[] args) {File file = new File("./test.txt");File file2 = new File("./src/test2.txt");file.renameTo(file2);}
}

以上文件系统的操作,都是基于 File 类来完成的

另外还需要文件内容的操作


三、文件内容的读写

1、Reader

文件这里的内容本质是来自于硬盘,硬盘又是操作系统管理的,使用某个编程语言操作文件,本质上都是需要调用系统的 api 

虽然不同的编程语言操作文件的 api 有所差别,但是基本步骤都是一样的

文件内容操作的核心步骤有四个:

1、打开文件

2、关闭文件

3、读文件

4、写文件

Java IO流 是一个比较庞大的体系,涉及到非常多的类,这些不同的类,都有各自不同的特性,但是总的来说,使用的方法都是类似的

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

(2)close 方法,关闭文件

(3)如果衍生自 InputStream 或者 Read ,就可以使用 read 方法来读数据

(4)如果衍生自 OutputStream 或者 Writer ,就可以使用 write 方法来写数据

 读文件操作:

 这个操作非常重要,释放必要的资源

让一个进程打开一个文件,是要从系统这里申请一定的资源的(占用进程的 pcb 的文件描述符表中的一个表项)

如果不释放,就会出现 “文件资源泄露” ,是一个很严重的问题

文件描述符表 可以理解成一个顺序表,长度有限,不会自动扩容,一旦一直打开文件,而不去关闭不用的文件,文件描述符表就会被占满,后续就没法打开新的文件了

我们可以使用 try with rewsourses 来避免出现上述问题

此时只要 try 代码执行完毕了,就会自动调用到 close 方法

文件流中的任意对象,都可以按照上述讨论来进行 close

一次读一个 char 类型的数组

 会把读到的内容,填充到参数的这个 cbuf 数组中,此处的参数,相当于是一个输出形参数

通过 read ,就会把本来是空的一个数组,填充上内容

n 表示实际读到的字符的个数

相当于给了 1024 这么大空间,如果文件足够大,超过 1024,就能填满这个空间

如果文件比较小,不足1024,就会把文件所有内容都填到数组中(剩下会空余)

返回值 n 就表示实际读到的字符的个数

有时候,可能会涉及到有多个小文件,都需要读取并且拼接到一起,就可以使用这个方法

假设现在有三个文件,每个文件的大小是 100 字节

 最终代码如下:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;//Reader 的使用
public class Demo6 {public static void main(String[] args) throws IOException {
/*        //FileReder 的构造方法,可以填写一个路径(绝对路径和相对路径都可以),也可以写一个构造好了的 file 对象Reader reader = new FileReader("d:/test.txt");try {//中间的代码无论出现什么情况,close 都可以执行到}finally {//如果抛出异常或者 return ,close就都执行不到了reader.close();}*///上述使用 finally 的方式能解决问题,但是不优雅//使用 try with resourses 是更好的解决方法try(Reader reader = new FileReader("d:/test.txt")){while(true){char buf[] = new char[1024];int n = reader.read(buf);if(n == -1){//读到文件末尾了break;}for(int i = 0;i < n;i++){System.out.print(buf[i] + " ");}}}}
}

2、InputStream

InputStream 是字节流,用法和 Reader 相似

文本文件,也可以使用字节流打开,只不过此时你读到的每个字节,就不是完整的字符了

 一次读一个字节

 一次读若干个字节,尝试填满这个 byte[]

一次读若干个字节,填满数组的一部分

Java 虽然有 char ,但是很少会用,更多的是使用 String 

此处,我们可以借助一些额外的工具类,就可以完成 字节 / 字符 --> 字符串 的转化

虽然也可以直接使用 String 的构造方法完成 char[] 或者 byte[] 到字符串的转化,但是比较麻烦

这个工具类就是 Scanner !!!

操作系统中,所谓的文件,是一个广义的概念,System.in 是一个特殊的文件,对应到 “标准输入”,普通的硬盘上的文件,也是文件

后来网络编程中的网卡(socket),也是文件

Scanner 都是一视同仁的,只是把当前读到的字节数据进行转换,但并不关心这个数据是来自于哪里

但是,要注意,Scanner 只是用来读取文本文件的,不是适合读取二进制文件

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo8 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("d:/test.txt")){Scanner scanner = new Scanner(inputStream);//此时就是从 test.txt 这个文件中读取数据了String s = scanner.next();System.out.println(s);}}
}

3、输出

输出的使用方法和输入非常相似,关键操作是 write 

write 之前要打开文件,write 之后也需要关闭文件

输出流对象(无论是字节流还是字符流),会在打开文件之后,清空文件内容!!!

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo8 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("d:/test.txt")){Scanner scanner = new Scanner(inputStream);//此时就是从 test.txt 这个文件中读取数据了String s = scanner.next();System.out.println(s);}}
}

还可以按照追加写的方式打开,此时就不会清空内容了 

读操作和写操作,也都能支持随机访问,可以移动光标到指定位置进行读写,此处就不进行介绍了

OutputStream 方式使用方法完全一样

只不过 write 方法,不能支持 字符串 参数,只能按照 字节 或者 字节数组来写入


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

import java.io.File;
import java.util.Scanner;public class Demo10 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);//1、用户输入一个目录,后续的查找都是针对这个目录进行的System.out.println("请输入要搜索的目录");File rootPath = new File(scanner.next());//2、再让用户输入要搜索和删除的关键粗System.out.println("请输入要删除的关键字");String word = scanner.next();//3、判断当前目录是否有效if (!rootPath.isDirectory()){System.out.println("此时输入的路径不是合法目录");return;}//4、遍历目录,从根目录出发,按照深度优先(递归) 的方式进行scanDir(rootPath,word);}public static void scanDir(File currentDir,String word){//1、先列出当前目录中包含哪些内容File[] files = currentDir.listFiles();if (files == null || files.length == 0){//空的目录或者非法的目录return;}//2、遍历列出的文件,分两个情况进行讨论for(File f : files){if (f.isFile()){//如果当前文件是普通文件,看看文件名是否包含了 word ,来决定是否要删除dealFile(f,word);}else {//如果当前文件是目录文件,就递归执行 scanDirscanDir(f,word);}}}public static void dealFile(File f,String word){Scanner scanner = new Scanner(System.in);//1、先判断当前文件是否包含 wordif (!f.getName().contains(word)){//此时文件不包含 word,return;}//2、包含 word,询问用户是否删除该文件System.out.println("该文件是: " + f.getAbsolutePath() + ",是否确认删除(Y / N )");String choice = scanner.next();if (choice.equals("Y") || choice.equals("y")){f.delete();}}
}

示例:进行普通的文件复制

import java.io.*;
import java.util.Scanner;public class Demo11 {public static void main(String[] args) throws IOException {System.out.println("请输入要复制的文件路径");Scanner scanner = new Scanner(System.in);String src = scanner.next();File srcfile= new File(src);if (!srcfile.isFile()){System.out.println("您输入的源文件路径是非法的");return;}System.out.println("请输入要复制到的目标路径");String dest = scanner.next();File destfile= new File(dest);//不要求目标文件存在,但是得保证目标文件所在的目录是存在的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);if (n == -1){System.out.println("读取到 eof,循环结束");break;}outputStream.write(buffer,0,n);}}}
}

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

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

相关文章

【前端 | CSS】滚动到底部加载,滚动监听、懒加载

背景 在日常开发过程中&#xff0c;我们会遇到图片懒加载的功能&#xff0c;基本原理是&#xff0c;滚动条滚动到底部后再次获取数据进行渲染。 那怎么判断滚动条是否滚动到底部呢&#xff1f;滚动条滚动到底部触发时间的时机和方法又该怎样定义&#xff1f; 针对以上问题我…

数据集成革新:去中心化微服务集群的无限潜能

在当今数据密集型的业务环境下&#xff0c;传统的集中式架构已经难以满足高可用性和高并发性的要求。而去中心化微服务集群则通过分散式的架构&#xff0c;将系统划分为多个小型的、独立部署的微服务单元&#xff0c;每个微服务负责特定的业务功能&#xff0c;实现了系统的高度…

docker搭建opengrok环境

引言&#xff1a; 由于这几天开始 http://aospxref.com/ 网站没法用了。用习惯了opengrok的方式看AOSP的源码&#xff0c;其他的在线查看源码的网站用起来都不是很理想。所以考虑搭建一个环境。 首先网上看了下opengrok的环境搭建的方式&#xff0c;最终还是采用docker的方…

基于C#的无边框窗体阴影绘制方案 - 开源研究系列文章

今天介绍无边框窗体阴影绘制的内容。 上次有介绍使用双窗体的方法来显示阴影&#xff0c;这次介绍使用API函数来进行绘制。这里使用的是Windows API函数&#xff0c;操作系统的窗体也是用的这个来进行的绘制。 1、 项目目录&#xff1b; 下面是项目目录&#xff1b; 2、 函数介…

日常BUG——SpringBoot模糊映射

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 SpringBoot在启动时报出如下错误&#xff1a; Caused by: java.lang.IllegalStateExceptio…

ARM处理器

1、RISC处理器&#xff1a; RISC (Reduced Instruction Set Computer) 微处理器是一种计算机微处理器架构&#xff0c;其设计原则是通过简化指令集来提高执行速度。 (1)、RISC处理器的设计理念&#xff1a; 简化指令集&#xff1a;RISC 微处理器的指令集非常精简&#xff0c…

文件批量重命名001到100

文件批量重命名001到100如何搞定&#xff1f;这是一个许多朋友都在热议的话题&#xff0c;今天我将向大家介绍这方面的内容&#xff0c;希望你会喜欢。总的来说&#xff0c;文件重命名快捷键CtrlF2在日常工作中非常实用。它可以轻松快速地完成文件和文件夹的重命名操作&#xf…

储能pcb的布局注意事项与制造难点

随着新能源需求的不断增长和能源结构的转型&#xff0c;储能技术的市场规模不断扩大。储能PCB作为储能系统中电池模块的重要组成部分&#xff0c;对整个系统的安全性和性能起到关键作用。今天我们就来聊聊&#xff0c;储能pcb有什么特征。 什么是储能&#xff1a;储能是指能量…

用友Java后端笔试2023-8-5

计算被直线划分区域 在笛卡尔坐标系&#xff0c;存在区域[A,B],被不同线划分成多块小的区域&#xff0c;简单起见&#xff0c;假设这些不同线都直线并且不存在三条直线相交于一点的情况。 img 那么&#xff0c;如何快速计算某个时刻&#xff0c;在 X 坐标轴上[ A&#xff0c;…

Verdi_traceX and autotrace

Verdi_traceX and autotrace Trace X From nWave/nTrace of from the Teporal Flow View. Show Paths on Flow ViewShow Paths on nWave 若Waveform中有X态&#xff0c;鼠标右键会有Trace X的选项&#xff1b; 会自动打开Temporal Flow View窗口&#xff0c;展示对应路径&am…

RocketMQ、Dashboard部署以及安全设置

RocketMQ、dashboard部署以及安全设置 一、启动RocketMQ1.1 下载RocketMQ1.2 修改配置文件1.2.1 修改nameServer Jvm内存配置1.2.2 修改broker参数 1.3 启动1.3.1 启动NameServer1.3.2 启动Broker1.3.3 测试是否启动成功1.3.3.1 测试消息发送1.3.3.2 测试消息接收1.3.3.3 Java程…

数据结构——配对堆

引入 配对堆是一个支持插入&#xff0c;查询/删除最小值&#xff0c;合并&#xff0c;修改元素等操作的数据结构&#xff0c;是一种可并堆。有速度快和结构简单的优势&#xff0c;但由于其为基于势能分析的均摊复杂度&#xff0c;无法可持久化。 定义 配对堆是一棵满足堆性质…

C语言暑假刷题冲刺篇——day1

目录 一、选择题 二、编程题 &#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;C语言每日一练 ✨其他专栏&#xff1a;代码小游戏C语言初阶&#x1f91d;希望作者的文章能对你…

问道管理:网上如何打新股?

随着资本市场的不断敞开&#xff0c;越来越多的人开始重视股票市场&#xff0c;并想经过网上打新股来取得更大的出资收益。但是&#xff0c;网上打新股的办法并不简略&#xff0c;怎样才能成功地打新股呢&#xff1f;本文将从多个角度剖析&#xff0c;协助广阔出资者处理这一问…

海信聚好看将携新品DBdoctor,亮相中国数据库技术大会(DTCC2023)

海信聚好看将携新品DBdoctor&#xff0c;亮相中国数据库技术大会 8月16日—18日&#xff0c;第14届中国数据库技术大会&#xff08;DTCC-2023&#xff09;将在北京国际会议中心隆重召开。作为国内数据库领域规模最大的技术交流盛会&#xff0c;吸引了众多业内知名企业和数百名…

[谦实思纪 01]整理自2023雷军年度演讲——《成长》(上篇)武大回忆(梦想与成长)

文章目录 [谦实思纪]整理自2023雷军年度演讲 ——《成长》&#xff08;上篇&#xff09;武大回忆&#xff08;梦想与成长&#xff09;0. 写在前面1. 梦开始的地方1.1 要有梦想&#xff0c;要用目标量化梦想 2. 在两年内修完所有的学分。2.1 别老自己琢磨&#xff0c;找个懂的人…

Python爬虫IP代理池的建立和使用

写在前面 建立Python爬虫IP代理池可以提高爬虫的稳定性和效率&#xff0c;可以有效避免IP被封锁或限制访问等问题。 下面是建立Python爬虫IP代理池的详细步骤和代码实现&#xff1a; 1. 获取代理IP 我们可以从一些代理IP网站上获取免费或付费的代理IP&#xff0c;或者自己租…

开启想象翅膀:轻松实现文本生成模型的创作应用,支持LLaMA、ChatGLM、UDA、GPT2、Seq2Seq、BART、T5、SongNet等模型,开箱即用

开启想象翅膀&#xff1a;轻松实现文本生成模型的创作应用&#xff0c;支持LLaMA、ChatGLM、UDA、GPT2、Seq2Seq、BART、T5、SongNet等模型&#xff0c;开箱即用 TextGen: Implementation of Text Generation models 1.介绍 TextGen实现了多种文本生成模型&#xff0c;包括&a…

【kubernetes】在k8s集群环境上,部署kubesphere

部署kubesphere 学习于尚硅谷kubesphere课程 前置环境配置-部署默认存储类型 这里使用nfs #所有节点安装 yum install -y nfs-utils# 在master节点执行以下命令 echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports # 执行以下命令&#xff…

计算机组成部分

计算机的五大部件是什么&#xff1f;答案&#xff1a;计算机的五大部件是运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备和输出设备。 其中运算器和控制器合称中央处理器&#xff0c;是计算机的核心部件&#xff1b; 存储器是用来存储程序指令和数据用的&am…