文件操作 和 IO - 详解

news2024/11/20 3:21:16

一,认识文件

1.1 树形结构组织和目录

文件是对于"硬盘"数据的一种抽象,在一台计算机上,有非常多的文件,这些文件是通过 "文件系统" 来进行组织的,本质上就是通过 "目录"(文件夹) 这样的树形结构来组织文件的,画个图理解一下:

有了目录,我们就可以使用目录的层次结构来描述文件所在的位置,即 "路径"。如:D:\Program Files (x86)\编程3\Common\VSPerfCollectionTools\vs2022\1033,在这里还有两个概念:

  • 绝对路径:以 C:D:盘符开头的,这种路径就是 "绝对路径"。
  • 相对路径:需要指定一个目录作为基准目录,从基准目录出发,到达指定的文件,这里的路径就是 "相对路径"。这些路径往往是以  . (代表当前目录) 或者  .. (代表当前目录的上一级目录) 开头的。

1.2 文件类型

文件主要分为两大类:

1)文本文件:文件中保存的数据都是字符串,保存的内容都是合法字符(计算机存储的数据都是二进制的,能通过字符编码将二进制数据转换成字符的就是合法字符)

2)二进制文件:文件中保存的数据是二进制数据,即不是合法的字符

区分文本文件和二进制文件:将文件直接使用记事本打开,如果是乱码,就是二进制文件,如果不是,就是文本文件。

二,文件操作 - FILE

2.1 属性

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

E:\01\MSDN 中的 \ 就是 pathSeparator,如果当前的系统是 Windows,\ 或者 / 都可以作为分隔符,如果系统是 Linux 或 Mac ,只能使用 / 作为分隔符,一般建议使用 / 作为分隔符,因为 \ 一般还需要搭配转义字符来使用。

2.2 构造方法

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

2.3 方法

返回值类型方法名说明
StringgetParent()
返回 File 对象的父目录文件路径
StringgetName()
返回 FIle 对象的纯文件名称
StringgetPath()
返回 File 对象的文件路径
StringgetAbsolutePath()
返回 File 对象的绝对路径
StringgetCanonicalPath()
返回 File 对象的修饰过的绝对路径
booleanexits()
判断 File 对象描述的文件是否真实存在
booleanisDirectory()
判断 File 对象代表的文件是否是一个目录
booleanisFile()
判断 File 对象代表的文件是否是一个普通文件
booleancreateNewFile()
根据 File 对象,自动创建一个空文件。成功创建后返
true
booleandelete()
根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()
根据 File 对象,标注文件将被删除,删除动作会到
JVM 运行结束时才会进行
String[]
list()
返回 File 对象代表的目录下的所有文件名
File[]
listFiles()
返回 File 对象代表的目录下的所有文件,以 File 对象表示
boolean
mkdir()
创建 File 对象代表的目录
boolean
mkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
boolean
renameTo(File dest)
进行文件改名,也可以视为我们平时的剪切、粘贴操
boolean
canRead()
判断用户是否对文件有可读权限
boolean
canWirte()
判断用户是否对文件有可写权限
public class Demo {
    public static void main(String[] args) throws IOException {
        File file = new File("./text.txt");//不要求该文件一定存在
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("d:/text.txt");
        System.out.println(file.exists());//false
        System.out.println(file.isDirectory());//false
        System.out.println(file.isFile());//false
        System.out.println(file.createNewFile());//true
        System.out.println(file.delete());//true
        //file.deleteOnExit();在程序全部执行完之后删除文件

        File file1 = new File("d:/");
        String[] ret = file1.list();
        System.out.println(Arrays.toString(ret));

        File file2 = new File("d:/aaa/bbb/ccc");
        boolean ans = file2.mkdirs();//能创建多级目录
        //file2.mkdir();只能创建一级目录,如 d:/aaa
        System.out.println(ans);
    }
}

三,文件内容读写 - 数据流

数据流根据文件类型也分成了两种:

1)字节流:对应二进制文件,每次读写的最小单位是 "字节"

2)字符流:对应文本文件,每次读写的最小单位是 "字符",英文的字符都是一个字节,一个汉字在不同的字符编码中是不同点大小,在 utf8 是 3 个字节,在 unicode 是 2 个字节。(字符流本质上是针对字节流进行的一层封装)

JAVA针对读写两种操作,分别为字节流提供了 InputStream(输入) 和 OutputStream(输出) 类,为字符流提供了 Reader(输入) 和 Writer(输出) 类。这里有一个注意点,如何区分输入和输出,画个图:

 3.1 字符流 - Reader

返回值类型方法名说明
intread()从文件中读取一个字符,返回unicode编码
intread(char[] cbuf)从文件中读取若干字符,将cbuf数组填满,返回实际读取的字符数
intread(chae[] cbuf, int off, int len)从文件中读取作干字符,从off下标开始,长度为len的cbuf数组填满,返回实际读取的字符数
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Demo3 {
    public static void main(String[] args) throws IOException {
        //一次读一个字符
        Reader reader = new FileReader("d:/text.txt");//打开文件
        while(true){
            int n = reader.read();//读取一个字符
            if(n == -1){//返回-1表示文件读取完毕
                break;
            }
            char ch = (char) n;
            System.out.println(n);
        }
        reader.close();
    }
}

但是这么写还是可能会出现文件资源泄露,如果在while循环中抛出异常,下面的close()方法就执行不到了,所以我们可以使用 try...finally..来实现:

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

public class Demo3 {
    public static void main(String[] args) throws IOException {
        //一次读多个字符
        Reader reader = new FileReader("d:/text.txt");//打开文件
        try{
            while(true){
                char[] ret = new char[10];
                int n = reader.read(ret);
                if(n == -1) break;
                for (int i = 0; i < n; i++) {
                    System.out.println(ret[i]);
                }
            }
        }finally {
            reader.close();//关闭操作
        }
    }
}

这么写虽然解决了问题,但是不够方便,在这里还有一种写法:

public class Demo3 {
    public static void main(String[] args) throws IOException { 
        //只有实现closeable接口才可以这样写(流对象都可以)
        try(Reader reader = new FileReader("d:/text.txt")){
            while(true){
                char[] ret = new char[10];
                int n = reader.read(ret);
                if(n == -1) break;
                for (int i = 0; i < n; i++) {
                    System.out.println(ret[i]);
                }
            }
        }
    }
}

3.2 字符流 - Writer

方法名说明
write(int c)一次写一个字符
write(String str)一次写多个字符
write(char[] cbuf)一次写多个字符,使用字符数组
write(String str, int off, int len)从下标off开始往文件中写入,长度为len
write(char[] cbuf, int off, int len)从下标off开始往文件中写入,长度为len

注:默认情况下,写入文件会将文件中的原有内容清空。

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

public class Demo4 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("d:/text.txt")) {
            writer.write("原神,启动!");//写入,先清空再写入
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    /*  在构造方法参数中加一个 true , 就可以直接在文件后面填写,不需要清空
        try(Writer writer1 = new FileWriter("d:/text.txt",true)) {
            writer1.write("原神,启动!");//写入
        } catch (IOException e) {
            throw new RuntimeException(e);
        }*/
    }
}

3.3 字节流 - InputStream

返回值类型方法名说明
intread()
读取一个字节的数据,返回 -1 代表已经完全读完了
intread(byte[] b)
最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表以及读完了
int
read(byte[] b, int off, int len)
最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
void
close()
关闭字节流
import java.io.*;

public class Demo5 {
    public static void main(String[] args) {
        try(InputStream inputStream = new FileInputStream("d:/text.txt")) {
            byte[] buffer = new byte[10];
            while (true){
                int n = inputStream.read(buffer);
                if(n == -1) break;
                for (int i = 0; i < n; i++) {
                    System.out.printf("%x\n",buffer[i]);
                }
            }
        }catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

3.4 字节流 - OutputStream

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

public class Demo5 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt",true)){
            String s = "哈哈哈哈";
            outputStream.write(s.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

3.5 字节流转字符流

当别人传给你的是一个字节流文件,但是你知道实际数据内容是文本数据时,我们可以通过以下方法来实现转换:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Demo6 {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("d:/text.txt")){
            Scanner scanner = new Scanner(inputStream);
            String s = scanner.next();
            System.out.println(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 

import java.io.*;

public class Demo7 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt")){
            PrintWriter writer = new PrintWriter(outputStream);
            writer.println("fsaf");  
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 因为 PrintWriter 这个类,在进行写入操作的时候,不一定时直接写入硬盘,而是先把数据写入一个内存中的空间,叫做 "缓冲区"。为什么会出现缓冲区?因为把数据写入内存,是非常快的,而把数据写入硬盘,是非常慢的(比内存慢几千倍甚至更多),为了提高效率,我们选择降低写硬盘的次数。这样就会出现问题,我们将数据写入 "缓冲区" 后,还没有将缓冲区的数据写入硬盘,进程就结束了,此时数据就丢失了,也就会出现上述图片中的问题

为了解决该问题,确保数据能完整的写入硬盘,我们需要手动的用 flush() 方法刷新缓冲区:

import java.io.*;

public class Demo7 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt")){
            PrintWriter writer = new PrintWriter(outputStream);
            writer.println("fsaf");
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

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

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

相关文章

PyTorch实例:简单线性回归的训练和反向传播解析

文章目录 &#x1f966;引言&#x1f966;什么是反向传播&#xff1f;&#x1f966;反向传播的实现&#xff08;代码&#xff09;&#x1f966;反向传播在深度学习中的应用&#x1f966;链式求导法则&#x1f966;总结 &#x1f966;引言 在神经网络中&#xff0c;反向传播算法…

第八章 排序 四、冒泡排序

目录 一、算法思想 二、例子 三、代码实现 四、验证 五、算法性能分析 注意&#xff1a;要分清楚交换次数和移动次数 六、总结 一、算法思想 从后往前&#xff0c;两两比较相邻元素的值&#xff0c;若为逆序&#xff0c;则交换它们的值&#xff0c;直到全部比较完。 二…

typescript: Builder Pattern

/*** file: CarBuilderts.ts* TypeScript 实体类 Model* Builder Pattern* 生成器是一种创建型设计模式&#xff0c; 使你能够分步骤创建复杂对象。* https://stackoverflow.com/questions/12827266/get-and-set-in-typescript* https://github.com/Microsoft/TypeScript/wiki/…

制作 3 档可调灯程序编写

PWM 0~255 可以将数据映射到0 75 150 225 尽可能均匀电压间隔

Python的NumPy库(一)基础用法

NumPy库并不是Python的标准库&#xff0c;但其在机器学习、大数据等很多领域有非常广泛的应用&#xff0c;NumPy本身就有比较多的内容&#xff0c;全部的学习可能涉及许多的内容&#xff0c;但我们在这里仅学习常见的使用&#xff0c;这些内容对于我们日常使用NumPy是足够的。 …

【Python】datetime 库

# timedelta(days, seconds, microseconds,milliseconds, minutes, hours, weeks) 默认按顺序传递参数 # 主要介绍 datetime.datetime 类 # 引入 from datetime import datetime today datetime.now() # 获取当前时间 2023-10-05 15:58:03.218651 today1 datetime.utcnow() #…

经典算法-----汉诺塔问题

前言 今天我们学习一个老经典的问题-----汉诺塔问题&#xff0c;可能在学习编程之前我们就听说过这个问题&#xff0c;那这里我们如何去通过编程的方式去解决这么一个问题呢&#xff1f;下面接着看。 汉诺塔问题 问题描述 这里是引用汉诺塔问题源自印度一个古老的传说&#x…

Ubuntu 22.04 安装Nvidia显卡驱动、CUDA、cudnn

GPU做深度学习比CPU要快很多倍&#xff0c;用Ubuntu跑也有一定的优势&#xff0c;但是安装Nvidia驱动有很多坑 Ubuntu版本&#xff1a;22.04.3 LTS 分区&#xff1a; /boot分配 1G &#xff0c;剩下都分给根目录/ 显卡&#xff1a;GTX 1050 Ti 坑1&#xff1a;用Ubuntu自带的 …

ESP32上电到app_main()的过程梳理

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘校园大使&#xff0c;湖南区域的日常实习&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &am…

【单片机】16-LCD1602和12864和LCD9648显示器

1.LCD显示器相关背景 1.LCD简介 &#xff08;1&#xff09;显示器&#xff0c;常见显示器&#xff1a;电视&#xff0c;电脑 &#xff08;2&#xff09;LCD&#xff08;Liquid Crystal Display&#xff09;&#xff0c;液晶显示器&#xff0c;原理介绍 &#xff08;3&#xff…

哈希表的总结

今天刷了力扣的第一题&#xff08;1. 两数之和 - 力扣&#xff08;LeetCode&#xff09;&#xff09;&#xff0c;是一道用暴力解法就可以完成的题目&#xff08;两个for循环&#xff09;,但是官方解答给出了用哈希表的解法&#xff0c;用空间换时间&#xff0c;时间复杂度从O(…

Jmeter排查正则表达式提取器未生效问题

今天在使用Jmeter的时候遇到一个很简单的问题&#xff0c;使用正则表达式提取token一直未生效&#xff0c;原因是正则表达式中多了一个空格。虽然问题很简单&#xff0c;但是觉得排查问题的方法很普适&#xff0c;所以记录下&#xff0c;也希望能够给遇到问题的大家一个参考。 …

蓝桥杯每日一题2023.10.5

3420. 括号序列 - AcWing题库 题目描述 题目分析 对于这一我们需要有前缀知识完全背包 完全背包的朴素写法&#xff1a; #include<bits/stdc.h> using namespace std; const int N 1010; int n, m, v[N], w[N], f[N][N]; int main() {cin >> n >> m;fo…

MySQL数据库入门到精通——进阶篇(3)

黑马程序员 MySQL数据库入门到精通——进阶篇&#xff08;3&#xff09; 1. 锁1.1 锁-介绍1.2 锁-全局锁1.3 锁-表级锁1.3.1 表级锁-表锁1.3.2 表级锁元数据锁( meta data lock&#xff0c;MDL)1.3.3 表级锁-意向锁1.3.4 表级锁意向锁测试 1.4 锁-行级锁1.4.1 行级锁-行锁1.4.2…

计算机网络 (中科大郑烇老师)笔记(一)概论

目录 0 引言1 什么是Internet&#xff1f;1.1 网络、计算机网络、互联网1.2 什么是Internet&#xff1f;&#xff1a;从服务角度看 2 什么是协议&#xff1f;3 网络的结构&#xff08;子系统&#xff09;3.1 网络边缘3.2 网络核心&#xff1a;分组交换、线路交换3.3 接入网、物…

【13】c++设计模式——>工厂模式

简单工厂模式的弊端 简单工厂模式虽然简单&#xff0c;但是违反了设计模式中的开放封闭原则&#xff0c;即工厂类在数据增加时需要被修改&#xff0c;而我们在设计时对于已经设计好的类需要避免修改的操作&#xff0c;而选用扩展的方式。 工厂模式设计 简单工厂模式只有一个…

天地无用 - 修改朋友圈的定位: 高德地图 + 爱思助手

1&#xff0c;电脑上打开高德地图网页版 高德地图 (amap.com) 2&#xff0c;网页最下一栏&#xff0c;点击“开放平台” 高德开放平台 | 高德地图API (amap.com) 3&#xff0c;在新网页中&#xff0c;需要登录高德账户才能操作。 可以使用手机号和验证码登录。 4&#xff0c…

探秘前后端开发世界:猫头虎带你穿梭编程的繁忙街区,解锁全栈之路

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

香蕉叶病害数据集

1.数据集 第一个文件夹为数据增强&#xff08;旋转平移裁剪等操作&#xff09;后的数据集 第二个文件夹为原始数据集 2.原始数据集 Cordana文件夹&#xff08;162张照片&#xff09; healthy文件夹&#xff08;129张&#xff09; Pestalotiopsis文件夹&#xff08;173张照片&…

用Python实现一个电影订票系统!

一、整体结构图 二、代码分解 2.1 infos.py 一部电影的详细信息适合用 字典 结构来存储&#xff0c;我们可以给字典里添加多个键值对来保存电影的名称、座位表和宣传时用的字符画&#xff0c;比如电影《泰坦尼克号》的详细信息就可以按下面的形式保存到字典 titanic 中&#…