文件操作 和 IO - 详解

一,认识文件

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());//falseSystem.out.println(file.isDirectory());//falseSystem.out.println(file.isFile());//falseSystem.out.println(file.createNewFile());//trueSystem.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:/aaaSystem.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.mzph.cn/news/95223.shtml

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

相关文章

Maven(项目构建管理工具)

为什么要使用Maven&#xff1f; 传统项目管理状态分析&#xff1a; ①jar包不统一&#xff0c;jar包不兼容&#xff1b; ②工程升级维护过程操作繁琐&#xff1b; ........... Maven(JAVA书写)&#xff1a;管理jar包以及jar之间的依赖关系&#xff0c;完成项目编译&#xff0c;…

【Java 进阶篇】JDBC数据库连接池Druid详解

在Java应用程序中&#xff0c;与数据库进行交互是一个常见的任务。为了更有效地管理数据库连接并提高性能&#xff0c;数据库连接池是一种常见的解决方案。Druid是一个流行的JDBC数据库连接池&#xff0c;它具有丰富的功能和高性能。本博客将详细介绍Druid连接池&#xff0c;包…

6.Tensors For Beginners-What are Convector

Covectors &#xff08;协向量&#xff09; What‘s a covector Covectors are “basically” Row Vectors 在一定程度上&#xff0c;可认为 协向量 基本上就像 行向量。 但不能简单地认为 这就是列向量进行转置&#xff01; 行向量 和 列向量 是根本不同类型的对象。 …

【iptables 实战】9 docker网络原理分析

在开始本章阅读之前&#xff0c;需要提前了解以下的知识 阅读本节需要一些docker的基础知识&#xff0c;最好是在linux上安装好docker环境。提前掌握iptables的基础知识&#xff0c;前文参考【iptables 实战】 一、docker网络模型 docker网络模型如下图所示 说明&#xff1…

僵尸进程的产生与处理

僵尸进程是指在进程结束后&#xff0c;其父进程没有及时处理该进程的终止状态信息&#xff0c;导致该进程的进程描述符仍然存在于系统进程表中&#xff0c;但是已经没有实际的执行代码。这样的进程被称为僵尸进程。 僵尸进程的产生是由于父进程没有及时调用wait()或waitpid()等…

RabbitMQ-死信队列

接上文 RabbitMQ-java使用消息队列 1 死信队列简介 死信队列模式实际上本质是一个死信交换机绑定的死信队列&#xff0c;当正常队列的消息被判定为死信时&#xff0c;会被发送到对应的死信交换机&#xff0c;然后再通过交换机发送到死信队列中&#xff0c;死信队列也有对应的消…

基于Matlab求解高教社杯数学建模竞赛(cumcm2010A题)-储油罐的变位识别与罐容表标定(附上源码+数据+题目)

文章目录 题目解题源码数据下载 题目 通常加油站都有若干个储存燃油的地下储油罐&#xff0c;并且一般都有与之配套的“油位计量管理系统”&#xff0c;采用流量计和油位计来测量进/出油量与罐内油位高度等数据&#xff0c;通过预先标定的罐容表&#xff08;即罐内油位高度与储…

【Ubuntu】基于C++实现人脸识别

人脸识别考勤机 文章目录 人脸识别考勤机概述第一章 搭建Ubuntu环境1.1 什么是物联网1.2 物联网应该怎么学1.3 Linux开发环境搭建1.4 Linux基本使用1.5 Ubuntu网络配置 第二章 “hello,world!”程序2.1 什么是程序2.2 “hello,world!”程序2.3 C语法扩展2.4 常见错误调试 第三章…

ELK 处理 Spring Boot 日志

ELK 处理 Spring Boot 日志&#xff0c;妙啊&#xff01; 来源&#xff1a;ibm.com/developerworks/cn/java /build-elk-and-use-it-for-springboot -and-nginx/index.html ELK 简介 Logstash Elasticsearch Kibana ELK 实现方案 ELK 平台搭建 安装 Logstash 安装 Elas…

国庆day5

客户端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);socket new QTcpSocket(this);//此时&#xff0c;已经向服务器发送连接请求了&#xff0c;如果成功连…

图的深度遍历-邻接矩阵实现

description 本题要求实现邻接矩阵存储图的深度优先遍历。 函数接口定义&#xff1a; void DFS(MGraph G,Vertex v); 其中MGraph是邻接矩阵存储的图&#xff0c;定义如下&#xff1a; #define MaxVertexNum 10 /定义最大顶点数/ typedef int Vertex;/* 用顶点下标表示顶点,…

【重拾C语言】五、模块化程序设计——函数(定义、调用、参数传递、结果返回、函数原型;典例:打印字符图形、验证哥德巴赫猜想)

目录 前言 五、模块化程序设计——函数 5.1 计算三角形的重心 5.2 函数 5.2.1 函数定义 5.2.2 函数调用 a. 函数调用的形式和过程 b. 参数传递 值传递 指针传递 c. 函数结果返回 5.2.3 函数原型&#xff08;先调用后定义&#xff09; 5.3 程序设计实例 5.3.1 打印…

C/S架构学习之TCP的三次握手和四次挥手

TCP的三次握手&#xff1a;一定由客户端主动发起的&#xff0c;发生在建立连接的过程中。此过程发生在客户端的connect()函数和服务器的accept()函数之间。第一次握手&#xff1a;客户端向服务器发送一个带有SYN标志的数据包&#xff0c;表示客户端请求建立连接。并且客户端会选…

3D孪生场景搭建:模型区域摆放

前面介绍完了NSDT场景编辑器的线性绘制和阵列绘制&#xff0c;本章将讲述下编辑器的另一种绘制方式&#xff1a;区域绘制。 1、区域绘制功能简介 在场景中绘制资产时&#xff0c;除使用上述两个的方式外&#xff0c;NSDT 编辑器还支持使用区域绘制的方式进行绘制。先选取需要…

python修改unittestreport中的用例条数

背景: 自动化框架中使用yaml文件作为数据配置&#xff0c;使用ddt作为数据驱动来运行测试用例&#xff0c;由于测试用例都是基于场景去编写&#xff0c;目前都是一个测试类算是一条测试用例&#xff0c;但基于测试报告里面一个类运行的测试方法有多个&#xff0c;因此统计的测试…

计算机毕业设计 基于SpringBoot的图书馆管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

香蕉叶病害数据集

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

【Java 进阶篇】JDBC 数据库连接池 C3P0 详解

数据库连接池是数据库编程中常用的一种技术&#xff0c;它可以有效地管理数据库连接&#xff0c;提高数据库访问的性能和效率。在 Java 编程中&#xff0c;有多种数据库连接池可供选择&#xff0c;其中之一就是 C3P0。本文将详细介绍 C3P0 数据库连接池的使用&#xff0c;包括原…

Linux CentOS7 vim重复行

在用vim编辑处理文件时&#xff0c;会有重复行。有的是情境需要&#xff0c;有的可能是误操作而形成。对于正常形成的重复行&#xff0c;我们不作讨论&#xff0c;我们仅讨论什么情况下会出现重复行&#xff0c;如何避免&#xff0c;如何处理。 在文件中的单行或多个连续空白行…

【Unity】3D贪吃蛇游戏制作/WebGL本地测试及项目部署

本文是Unity3D贪吃蛇游戏从制作到部署的相关细节 项目开源代码&#xff1a;https://github.com/zstar1003/3D_Snake 试玩链接&#xff1a;http://xdxsb.top/Snake_Game_3D 效果预览&#xff1a; 试玩链接中的内容会和该效果图略有不同&#xff0c;后面会详细说明。 游戏规则 …