【JavaEE初阶】文件操作——IO

news2024/11/27 19:39:18

摄影分享~
在这里插入图片描述

文章目录

  • 文件
    • 文件路径(Path)
  • 文件的类型
  • Java中操作文件
    • File概述
  • 文件内容的读写——数据流
    • 字节流
    • InputStream概述
    • OutputStream 概述
    • 字符流
    • FileInputStream 概述
    • 利用 Scanner 进行字符读取
  • 实例练习

文件

文件:File这个概念,在计算机里也是一次多用:
狭义的文件:指的是硬盘上的文件和目录。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。
广义的文件:泛指计算机中的很多的软硬件资源.

同时,随着文件越来越多,对文件的系统管理也被提上了日程,如何进行文件的组织呢,一种合乎自然的想法出现了,就是按照层级结构进行组织 —— 也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。

文件路径(Path)

每个文件,在硬盘上都有一个具体的路径。
在这里插入图片描述
例如:上述照片的路径就是:E:/rocket.jpg
表示一个文件的具体位置路径,就可以使用 / 来分割不同的目录级别。

在这里插入图片描述
就可以表示为:E:\tmp\111\aaa

在Windows中/\都可以来做分隔符。但是在平常的代码中更建议使用/,因为/不存在字符转义问题。

在路径这里,有两种表示路径的风格。

  1. 绝对路径,以c: d: 盘符开头的路径
  2. 相对路径,以当前所在的目录为基准,以.或者..开头(有时可以省略),找到指定的路径

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

在这里插入图片描述
定位到111这个目录,是E:/tmp
如果工作目录不同,定位到同一个文件,相对路径写法是不同的:
例如:定位到111
如果工作目录是E:/ 相对路径写作:./tmp/111
如果工作目录是E:/tmp 相对路径写作:./111
如果工作目录是E:/tmp/222 相对路径写作:../111
如果工作目录是E:/tmp/222/bbb 相对路径写作:../../111

..表示上一级路径

文件的类型

文件的类型有很多种,比如:word,exe,图片,视频,pdf,源代码,动态库等。这些文件可以归纳到两类中:

  1. 文本文件(存的是文本,字符串)
    字符串,是由字符构成的,每个字符,都是通过一个数字来表示的。这个文本文件里存的数据,一定是合法的字符,都是指定字符编码的码表之内的数据。
  2. 二进制文件(存的是二进制,不一定是字符串)
    没有任何限制

如何判断一个文件是二进制还是文本文件?
使用记事本打开,如果乱码就是二进制文件;如果没有乱码,就是文本。
在这里插入图片描述

Java中操作文件

主要分为两类:

  1. 针对文件系统操作。(文件的创建,删除,重命名)
  2. 针对文件内容操作。(文件的读和写)

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

File概述

常见属性

修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表示
static charpathSeparator依赖于系统的路径分隔符,char 类型的表示

pathSeparator(File中的一个静态变量)就是/或者\跟着系统走。

构造方法

签名说明
File(File parent, Stringchild)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, Stringchild)根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

方法

修饰符及返回值类型方法签名说明
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 FIle 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
booleancreateNewFile()根据 File 对象,自动创建一个空文件。成功创建后返回 true
booleandelete()根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行
String[]list()返回 File 对象代表的目录下的所有文件名
File[]listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
booleanmkdir()创建 File 对象代表的目录
booleanmkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
booleanrenameTo(Filedest)进行文件改名,也可以视为我们平时的剪切、粘贴操作
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

方法演示:
在这里插入图片描述
注意:

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

中不要求E:/这里真的有test.txt
如果想要可以自己手动创建:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

throws IOException

这个异常在IO中是特别容易出现的异常。

deleteOnFile()程序退出的时候,自动删除。(打开一个word文档,就会在同级目录下生成出一个临时文件,关闭word,这个文件就没有了)
在这里插入图片描述
这个临时文件,相当于保存了当前实时编辑的内容,防止编辑了很多东西之后突然停电,导致数据丢失。这种临时数据就使用deleteOnExit的方式来删除。

在这里插入图片描述
在这里插入图片描述

文件内容的读写——数据流

什么叫做流呢?

举个🌰:
水龙头,通过这个水龙头可以接水。
比如你要接100ml水,你可以一次接100ml,一次接完
也可以一次接50ml,分两次接
还可以一次接10ml,分10次接

这是水流~~

同理,从文件中读100个字节,就可以:
一次性读100字节,一次读完。
一次性读50字节,两次读完。
一次读10字节,十次读完。

因此就把读写文件的相关对象,称为“流对象”

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

  1. 字节流:操作二进制数据的
    InputStream
    OutoutStream
    FileInputSrteam
    FileOutputStream
  2. 字符流:操作文本数据的
    Reader
    Writer
    FileReader
    FileWriter

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

  1. 打开文件
  2. 关闭文件
  3. 读文件(read)=>针对InputStream/Reader
  4. 写文件(writer)=>针对OutputStream/Writer

注意InputStream OutoutStream Reader Writer都是抽象类,不能直接new

字节流

InputStream概述

在这里插入图片描述
可以看到read的三个版本:

方法:

修饰符及返回值类型方法签名说明
intread()一次读取一个字节,返回 -1 代表已经完全读完了
intread(byte[] b)把读到的内容填充到参数的这个字节数组中(此处的参数是“输出型参数”)返回值是实际读取的字节数
intread(byte[] b,int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
voidclose()关闭字节流

在这里插入图片描述

注意FileNotFoundExpectionIOExpection的一个子类。所以抛异常的时候只需要抛IOExpection就够了。

read();无参数版本详解:

在这里插入图片描述

在这里插入图片描述
可以看到打印出来是abcd的ascii值
如果文本中是中文“你好。”那么打印出来则为:
在这里插入图片描述
这里使用的utf8,utf8码表对应的16进制则为以上值。(utf8中一个汉字对应三个字节)

read(byte[])版本详解:
在这里插入图片描述
此版本中需要调用者提前准备好一个数组buffer(缓冲区)用来提高IO操作的效率。

int len = inputStream.read(buffer);

中传参操作,相当于是把刚才准备好的数组,交给read方法,让read方法内部针对这个数组进行填写。(此处参数相当于输出型参数)

注意read的行为和返回值。read会尽可能的把参数传进来的数组给填满。上面这里给出的数组长度时1024,read就会尽可能的读取1024个字节,填到数组中。但实际上,文件剩余长度是有限的,如果剩余长度超过1024,此时1024个字节都会被填满,返回值就是1024了。如果当前剩余的长度不足1024,此时有多少就填多少。read方法就会返回当前实际读取的长度。
读完了,一个字节都没读到,则返回-1.

在这里插入图片描述
使用了InputStream来读文件,可以使用OutStream来写文件。

OutputStream 概述

修饰符及返回值类型方法签名说明
voidwrite(int b)写入要给字节的数据
voidwrite(byte[]b)将 b 这个字符数组中的数据全部写入 os 中
intwrite(byte[]b, int off,int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
voidclose()关闭字节流
voidflush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

详解write(int b)
在这里插入图片描述
在这里插入图片描述
注意:在abcd之前记事本中的内容是“你好”。对于OutputStream来说,默认情况下,打开一个文件,会先清空文件原有的内容。
如果不想清空,流对象还提供了一个“追加写”对象。通过这个可以实现不清空文件,把新内容追加到写后面。
注意:inputoutput的方向:是以CPU为中心,来看待这个方向的。
在这里插入图片描述

以CPU为中心:
流向CPU的方向,就是输入。所以就把数据从硬盘到内存这个过程称为读(input)
流出CPU的方向,就是输出。所以就把数据从内存到硬盘这个过程称为写(output)

详解close()

outputStream.close();

这里的close操作,含义是关闭文件。
进程->在内核中,使用PCB这样的数据来表示进程。
一个线程对应一个PCB。一个进程可以对应多个PCB。
PCB中有一个重要的属性:文件描述符表(相当于一个数组,记录了该进程打开了哪些文件)
一个进程里有多个线程多个PCB,这些PCB公用同一个文件描述符表。

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

那么,如果我们忘记写这个close();会怎么办呢?

如果没写close,对应的表项,没有及时释放。虽然Java有GC(垃圾回收机制),GC操作会在回收这个outputStream对象的时候去完成这个释放操作,但是这个GC回收器不一定及时。所以,如果不手动释放,意味着文件描述符表可能很快就被占满了。如果占满了之后,后面再次打开文件,就会打开失败。文件描述符表最大长度,不同系统上不太一样,基本是(几百到几千)

我们应该如何保证这个close会被执行到呢?

在这里插入图片描述
上述写法虽然没有显式的写close,实际上是会执行的。只要try语句块执行完毕,就可以自动执行到close

这个语法在Java中称为 try with resources
当然,要使用这个语法必须实现Closeable接口的类,才可以放到try的()中被自动关闭。

close操作,会触发缓冲区的刷新。(刷新操作,就是把缓冲里的内容写到硬盘里)

字符流

用法和字节流类似。

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

public class IODemo7 {
    // 字符流的操作
    public static void main(String[] args) {
        try (Reader reader = new FileReader("e:/test.txt")) {
            while (true) {
                int ch = reader.read();
                if (ch == -1) {
                    break;
                }
                System.out.println("" + (char)ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

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

public class IODemo9 {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("e:/test.txt")) {
            writer.write("hello world");
            // 手动刷新缓冲区
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

FileInputStream 概述

构造方法:

签名说明
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

在这里插入图片描述

利用 Scanner 进行字符读取

构造方法说明
Scanner(InputStream is, String charset)使用 charset 字符集进行 is 的扫描读取
 Scanner scanner = new Scanner(System.in);

System.in就是一个输入流对象。

实例练习

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

public class IODemo11 {
    private static Scanner scanner = new Scanner(System.in);
    public static void main(String[] args) {
        //让用户输入一个指定搜索的目录
        System.out.println("请输入一个指定搜索的路径:");
        String basePath = scanner.next();

        //针对用户输入进行简单判断
        File root = new File(basePath);
        if(!root.isDirectory()){
            //路径不存在,或者只是一个普通文件,就无法进行搜索
            System.out.println("输入的目录有误!");
            return;
        }

        //再让用户输入一个要删除的文件名
        System.out.println("请输入要删除的文件名:");
        String nameToDelete = scanner.next();

        //针对指定的路径进行扫描,递归操作
        //先从跟目录出发(root)
        //先判定一下这个目录中是否包含我们需要删除的文件,如果是就删除
        //否则就跳过,下一个
        //如果当前这里包含了一些目录,再针对子目录进行递归

        scanDir(root,nameToDelete);
    }

    private static void scanDir(File root, String nameToDelete) {
        System.out.println("[scanDir]"+root.getAbsolutePath());//查看递归的查找路径
        //1.先列出root下的文件和目录
        File[] files = root.listFiles();
        if(files == null){
            //当前root目录下为空
            //结束递归
            return;
        }
        //2.遍历当前列出的结果
        for (File f: files) {
            if(f.isDirectory()){
                //如果是目录就进一步递归
                scanDir(f,nameToDelete);
            }else{
                //如果是普通文件,则判定是否要删除?
                if(f.getName().contains(nameToDelete)){
                    System.out.println("是否确认删除"+f.getAbsolutePath());
                    String choic = scanner.next();
                    if(choic.equals("yes")||choic.equals("YES")){
                        f.delete();
                        System.out.println("删除成功!");
                    }else{
                        System.out.println("删除取消!");
                    }
                }
            }
        }
    }
}

在这里插入图片描述

在这里插入图片描述

  1. 进行普通文件的复制
    把一个文件拷贝成另一个文件
import java.io.*;
import java.util.Scanner;

public class IODemo8 {
    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("您输入的源路径有误!");
            return;
        }
        File destFile = new File(destPath);
        if(destFile.isFile()){
            //如果目标存在,也不能拷贝
            System.out.println("您输入的目标路径有误!");
            return;
        }
        try(InputStream inputStream = new FileInputStream(srcFile);
            OutputStream outputStream = new FileOutputStream(destFile)){
            while(true){
                int b = inputStream.read();
                if(b == -1){
                    break;
                }
                outputStream.write(b);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

PostSQL内存管理之内存上下文

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台:Linux x86-64 Red Hat Enterprise Linux 7 版本:14 文档用途 了解pg内存分配 详细信息 1.MemoryContex机制 内存上下文是pg相关的内存控制结构,树形结构组织下的内存上下文能在频繁的…

SNMPc软件的下载和安装教程,计算机网络管理,网络工程师

⬜⬜⬜ 🐰🟧🟨🟩🟦🟪(*^▽^*)欢迎光临 🟧🟨🟩🟦🟪🐰⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu &am…

vue 改变数据后,数据变化页面不刷新

文章目录 导文文章重点方法一:使用this.$forceUpdate()强制刷新方法二:Vue.set(object, key, value)方法三:this.$nextTick方法四:$set方法 导文 在vue项目中,会遇到修改完数据,但是视图却没有更新的情况 v…

让开发者成为创新主体 | 阿里云云原生4月动态

作者:云原生内容小组 云原生月度动态 ✦ 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》,从趋势热点、产品新功能、服务客户、开源与开发者动态等方面,为企业提供数字化的路径与指南。 本栏目每月更新。 01 趋势热点 &…

vue - 实现登录后用户无操作后自动退出登录功能,当用户鼠标不动、键盘不动、无窗口滚动时自动清除登录状态(可自定义删减条件,详细示例源码一键复制开箱即用)

需求 很多教程都是无效而且有bug。。很难用索性自己搞了最健壮的解决方案。 在vue项目中,实现自动检测用户没有【移动鼠标】【操作键盘】【窗口滚动】时,自动清除登录信息强制退出登录下线,支持自定义触发时间(比如无操作10分钟就执行),自定义条件(比如只监听用户鼠标是…

匿名对象以及临时空间

目录 大纲 1.何为匿名对象 2.产生匿名对象的四种情况: 1)给初始化对象时 2)以值的方式给函数传参; 3)类型转换; 4)函数返回时; 3.编译器优化 I.在同一行代码的优化 II.在函…

电脑关机很慢怎么办?这5个方法很有用!

案例:电脑关机很慢怎么办? 【我的电脑才买来不久,现在每次关机都很慢,有时甚至一直在转圈圈无法关机,怎么处理这种情况呢?】 如果使用电脑时间长了,我们可能会发现电脑的各项性能都会有所下降…

Vue3(5)插槽Slots

目录 一、插槽内容与出口 二、渲染作用域 三、默认内容 四、具名插槽 五、作用域插槽 六、具名作用域插槽 一、插槽内容与出口 在之前的博文中,我们已经了解到组件能够接收任意类型的JS值作为props,但组件要如何接收模板内容呢?在某些…

图片堆叠、多重聚焦的几种办法

当拍摄的物品较小,景深较深时,相机的焦点只能放在较近或者较远的一处,图片的整个画面就不能保证完全清晰,多重聚焦的原理其实就是拼合,在画幅的不同处拍摄聚焦图片,将各个聚焦的内容拼合在一起,…

杂记 2023.5.11

目录 come across(as).. 与异性对话经验和理论、策略 单词记忆 机器学习 come across(as).. 这个用法在口语里超级高频,表示「给人.印象,让人觉得..」,s后面可跟名词、形容词、 being形容词。 我们再来看几个例子: ◆He comes ac…

【Leetcode -455.分发饼干 -459.重复的字符串】

Leetcode Leetcode -455.分发饼干Leetcode - 459.重复的字符串 Leetcode -455.分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩…

多语言的APP外包开发流程

很多创业的人希望把APP做成多国家使用的模式,尤其是一些小游戏开发,很多小游戏玩法全世界都是一样的,这样开发一次就可以在全球推广。在开发这种类型软件的过程中需要注意哪些呢,今天和大家分享这方面的知识。北京木奇移动技术有限…

C语言入门篇——字符串,内存函数

目录 1、字符串函数 1.1求字符串长度 1.1.1strlen函数 1.2长度不受限制的字符串函数 1.2.1strcpy函数 1.2.2strcat函数 1.2.3strcmp函数 1.3长度受限制的字符串函数介绍 1.3.1strncpy函数 1.3.2strncat函数 1.3.3strncmp函数 1.4字符串查找 1.4.1strstr函数 1.4.…

JavaScript实现输入年龄来判断年龄阶段是青年/中年/老年人的代码

以下为实现输入年龄来判断年龄阶段是青年/中年/老年人的程序代码和运行截图 目录 前言 一、实现输入年龄来判断年龄阶段是青年/中年/老年人 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择,您可以在目录里进行快速查找…

open3d 裁剪点云

目录 1. crop_point_cloud 2. crop 3. crop_mesh 1. crop_point_cloud 关键函数 chair vol.crop_point_cloud(pcd) # vol: SelectionPolygonVolume import open3d as o3dif __name__ "__main__":# 1. read pcdprint("Load a ply point cloud, crop it…

哪些蓝牙耳机戴久不疼?长时间佩戴不疼的蓝牙耳机推荐

现在的真无线耳机已经成为了人们的标配之一了,各个厂家也紧随其后,生产出了多种无线耳机,不少人的选购蓝牙耳机一般都是对音质、佩戴和连接,但通常人们佩戴蓝牙耳机都是在半天左右,小编专门整理了一期舒适度高的耳机&a…

从 0~1 创建 Vue2 项目

前言 从0开始搭建Vue2项目;介绍项目目录结构;为了项目方便需要添加的配置。创建 Vue2 项目共有两种方式: 手动选择;选择默认模式。 给孩子点点关注吧!😭 一、环境准备 1.1 安装包管理工具 1.1.1 安装 …

使用CV-CUDA提高基于计算机视觉的任务吞吐量

使用CV-CUDA提高基于计算机视觉的任务吞吐量 涉及基于 AI 的计算机视觉的实时云规模应用程序正在迅速增长。 用例包括图像理解、内容创建、内容审核、映射、推荐系统和视频会议。 然而,由于对处理复杂性的需求增加,这些工作负载的计算成本也在增长。 从…

凌恩生物文献分享|南农大胡锋教授团队揭示苯并[a]芘胁迫影响蚯蚓肠道病毒组生态适应策略机制

蚯蚓被誉为“土壤生态系统工程师”,对于土壤结构改良、有机质分解、土壤污染修复具有重要意义,同时蚯蚓也被作为评估污染物生态风险的灵敏指示者。蚯蚓肠道微生物对于蚯蚓生态功能的发挥至关重要,为了充分利用蚯蚓的生态和生物技术效益&#…

Python每日一练:蚂蚁家族(详解集合法)

文章目录 前言一、题目二、代码分析总结 前言 这题挺有意思,感觉评简单难度有点低了,如果正经用无向图来做,代码还是有点长的。首先得建立节点,估计除第一个和最后一个每个节点都是一条线连进,一条线连出的。就可以这…