文件操作 和 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.rhkb.cn/news/151665.html

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

相关文章

WebGoat 靶场 JWT tokens 四 五 七关通关教程

文章目录 webGoat靶场第 四 关 修改投票数第五关第七关 你购买书&#xff0c;让Tom用户付钱 webGoat靶场 越权漏洞 将webgoat-server-8.1.0.jar复制到kali虚拟机中 sudo java -jar webgoat-server-8.1.0.jar --server.port8888解释&#xff1a; java&#xff1a;这是用于执行…

MySQL命令行中文乱码问题

MySQL命令行中文乱码问题&#xff1a; 命令行界面默认字符集是gbk&#xff0c;若字符集不匹配会中文乱码或无法插入中文。 解决办法&#xff1a;执行set names gbk; 验证&#xff1a; 执行命令show variables like ‘char%’;查看默认字符集。 创建数据库设置字符集utf8&…

2023旅游产业内容营销洞察报告:如何升级经营模式,适配社媒新链路

2023年我国旅游业强劲复苏&#xff0c;上半年旅游消费增长显著&#xff0c;政府出台一系列文旅扶持政策后&#xff0c;旅游业也在积极寻求数字化转型的升级方式。 上半年以旅游消费为代表的服务业对经济的增长贡献率超过60%&#xff0c;旅游企业普遍实现经营好转&#xff0c;企…

【FPGA零基础学习之旅#14】串口发送字符串

&#x1f389;欢迎来到FPGA专栏~串口发送字符串 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家能指正…

电脑散热——液金散热

目录 1.简介 2.传统硅脂与液金导热区别 3.特点 4.优点 5.为什么液金技术名声不太好 6.使用方法 1.简介 凡是对于电脑基础硬件有所了解的人&#xff0c;都知道硅脂是如今高性能电脑设备中必不可少的东西。芯片表面和散热器接触面&#xff0c;虽然肉眼看上去是非常光滑的金属…

C (1094) : DS双向链表—前驱后继

Description 在双向链表中&#xff0c;A有一个指针指向了后继节点B&#xff0c;同时&#xff0c;B又有一个指向前驱节点A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点&#xff0c;也能从链表尾节点开始遍历所有节点。 对于给定的一列数据&#xff0c;按照给定的…

C#封装、继承和多态的用法详解

大家好&#xff0c;今天我们将来详细探讨一下C#中封装、继承和多态的用法。作为C#的三大面向对象的特性&#xff0c;这些概念对于程序员来说非常重要&#xff0c;因此我们将对每个特性进行详细的说明&#xff0c;并提供相应的示例代码。 目录 1. 封装&#xff08;Encapsulati…

ElementUI结合Vue完成主页的CUD(增删改)表单验证

目录 一、CUD ( 1 ) CU讲述 ( 2 ) 编写 1. CU 2. 删除 二、验证 前端整合代码 : 一、CUD 以下的代码基于我博客中的代码进行续写 : 使用ElementUI结合Vue导航菜单和后台数据分页查询 ( 1 ) CU讲述 在CRUD操作中&#xff0c;CU代表创建&#xff08;Create&#xff09…

我做了一个简易P图(参数图)分析软件

P图(即参数图&#xff0c;Parameter Diagram)&#xff0c;是一个结构化的工具&#xff0c;帮助大家对产品更好地进行分析。 典型P图格式 P图最好是和FMEA软件联动起来&#xff0c;如国可工软的FMEA软件有P图分析这个功能。 单纯的P图分析软件很少&#xff0c;为了方便做P图分…

Elasticsearch:多语言语义搜索

在此示例中&#xff0c;我们将使用多语言嵌入模型 multilingual-e5-base 对混合语言文档的 toy 数据集执行搜索。 使用这个模型&#xff0c;我们可以通过两种方式进行搜索&#xff1a; 跨语言&#xff0c;例如使用德语查询来查找英语文档在非英语语言中&#xff0c;例如使用德…

【C++】多线程的学习笔记(2)——白话文版(bushi

目录 前一篇 本章内容提要 使用mutex锁的原因 mutex锁的概念 mutex的使用教程 锁的声明以及命名 mutex的加锁以及解锁 例子 结果 注意 mutex的其他方式的锁介绍 lock_guard 介绍 例子 运行结果 adopt_lock参数 unique_lock 介绍 try_to_lock defer_lock re…

iOS开发 通过分析UMeng的错误详情解决crash问题

iOS开发 通过分析UMeng的错误详情解决crash问题 在项目中获取崩溃信息很重要。在iOS开发调试以及上线之后&#xff0c;程序经常会出现Crash问题。比较常见的第三方crash分析工具是使用友盟、百度、crashlytics等。第三方crash分析工具&#xff0c;甚至还带了符号化crash日志的…

设计模式 - 七大软件设计原则

目录 一、设计模式 1.1、软件设计原则 1.1.1、开闭原则 1.2.2、单一职责原则 1.2.3、里氏替换原则 1.2.4、迪米特原则 1.2.5、接口隔离原则 1.2.6、依赖倒转原则 1.2.7、合成/聚合复用原则 一、设计模式 1.1、软件设计原则 1.1.1、开闭原则 开闭原则&#xff1a;对扩…

Docker 日志管理 - ELK

Author&#xff1a;rab 目录 前言一、Docker 日志驱动二、ELK 套件部署三、Docker 容器日志采集3.1 部署 Filebeat3.2 配置 Filebeat3.3 验证采集数据3.4 Kibana 数据展示3.4.1 创建索引模式3.4.2 Kibana 查看日志 总结 前言 如何查看/管理 Docker 运行容器的日志&#xff1f;…

1.Linux入门基本指令

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 01.ls指令 02.pwd指令 03.cd指令 04.touch指令 05.mkdir指令(重要) 06.rmdir&&rm指令(重要) 07.man指令(重要) 08.cp指令(重要) 09.mv指令(重要) 10.cat指令 nano指令 echo指令 输出重定向 追加重…

当 FineReport 遇见 CnosDB

随着大数据和物联网应用的快速发展&#xff0c;时序数据库成为了一种关键的数据存储和分析工具。而 FineReport 作为一款流行的商业智能工具&#xff0c;与时序数据库 CnosDB 的集成可以为企业提供更强大的数据分析和可视化功能。本博客将介绍如何将 FineReport 与 CnosDB 集成…

架构师-软件工程习题选择题

架构师-软件工程习题选择题

SpringBoot-黑马程序员-学习笔记(一)

8.pom文件中的parent 我们使用普通maven项目导入依赖时&#xff0c;通常需要在导入依赖的时候指定版本号&#xff0c;而springboot项目不需要指定版本号&#xff0c;会根据当前springboot的版本来下载对应的最稳定的依赖版本。 点开pom文件会看到这个&#xff1a; 继承了一个…

【Redis】基础数据结构-简单动态字符串SDS

C语言字符串 char *str "redis"; // 可以不显式的添加\0&#xff0c;由编译器添加 char *str "redis\0"; // 也可以添加\0代表字符串结束C语言中使用char*字符数组表示字符串&#xff0c;‘\0’来标记一个字符串的结束&#xff0c;不过在使用的过程中我…

自动驾驶传感器技术

自动驾驶传感器技术是自动驾驶系统的关键组成部分&#xff0c;它使车辆能够感知并理解周围环境。本文将深入探讨自动驾驶传感器技术&#xff0c;包括常见类型、工作原理以及它们在自动驾驶中的作用。 1. 摄像头 摄像头的工作原理 摄像头是基于光学原理的传感器&#xff0c;其…