文件操作和IO

文章目录

  • 一、文件系统
  • 二、文件类型
  • 三、文件系统操作
    • 3.1File类的属性
    • 3.2File类的构造方法
    • 3.3File类的方法
  • 四、文件内容操作
    • 4.1Reader类里的函数
    • 4.2Writer类里的函数
    • 4.3InputStream类里的函数
    • 4.4OutputStream类里的函数
    • 4.5字节流转换为字符流

一、文件系统

1、操作系统会把很多硬件设备和软件资源都抽象成“文件”进行统一管理。但大部分情况下我们说的文件指的是硬盘中数据的一种抽象。
2、计算机上通过“文件系统”(操作系统提供的模块)来组织文件,“文件系统”使用“目录”这样的结构(树形结构)来组织文件。
此电脑是目录树的根节点,路径即使用目录来描述文件所在的位置。
绝对路径:以C:、D:盘符开头的路径就是“绝对路径”,Windows上盘符不区分大小写。
相对路径:先指定一个目录作为基准目录,从基准目录出发,考虑沿着什么样的路线能找到指定的文件,此时涉及到的路径就是“相对路径”,“相对路径”往往以.(当前目录)或者…(当前目录的上一级目录)开头,.这种情况可以省略。
①假定当前的基准目录是D:\JAVACODE
则“相对路径”为.\the-second
②假设当前的基准目录是D:\JAVACODE\101
则“相对路径”为…\the-second

二、文件类型

在编程上文件类型主要有两大类:
①文本文件,文件中保存的数据是字符串,保存的内容都是合法的字符。
②二进制文件,文件中保存的数据是二进制数据,保存的内容不需要都是合法的字符。
记事本会尝试按照字符的方式来展示文件内容,用记事本打开文件如果打开之后是乱码就是二进制文件否则为文本文件。

三、文件系统操作

3.1File类的属性

static String pathSeparator和static char pathSeparator表示分割目录的符号。Windows上\和/都可以作为分割符,Linux和Mac上/作为分割符,一般我们用/。

3.2File类的构造方法

File(File parent, String child)

File(String pathname)//参数传入文件的绝对/相对路径

File(String parent, String child)

3.3File类的方法

getParent()、getName())、getPath())、getAbsolutePath())、getCanonicalPath()):

class test1 {public static void main(String[] args) throws IOException {File f = new File("./test.txt");System.out.println(f.getParent());//输出.System.out.println(f.getName());//输出test.txtSystem.out.println(f.getPath());//输出.\test.txtSystem.out.println(f.getAbsolutePath());//输出D:\project\io\.\test.txt,即把当前的相对路径拼接到基准目录上System.out.println(f.getCanonicalPath());//输出D:\project\io\test.txt,即针对getAbsolutePath()获得的绝对路径进行简化}
}

exists()、isDirectory()、isFile())、createNewFile():

class Test2 {public static void main(String[] args) throws IOException {File file = new File("d:/test.txt");System.out.println(file.exists());//输出falseSystem.out.println(file.isDirectory());//输出falseSystem.out.println(file.isFile());//输出false// 创建文件boolean ret = file.createNewFile();System.out.println("ret = " + ret);System.out.println(file.exists());//输出trueSystem.out.println(file.isDirectory());//输出falseSystem.out.println(file.isFile());//输出true}
}

delete()、deleteOnExit():

class Test3 {public static void main(String[] args) throws InterruptedException {File f = new File("d:/test.txt");//boolean ret = f.delete();//System.out.println("ret = " + ret);        f.deleteOnExit();//进程结束之后才会删除文件      Thread.sleep(5000);System.out.println("进程结束!");}
}

list()、listFiles()(返回File对象目录下的所有内容,包括系统自带的在此电脑里看不见的特殊目录):

class Test4 {public static void main(String[] args) {File f = new File("d:/");//用list()时File构造方法的参数中不能传入具体的文件名,不然list()会返回nullString[] files = f.list();//返回值为String[];listFiles()的返回值为File[]System.out.println(Arrays.toString(files));}
}

mkdir()、mkdirs()(创建目录):

class Test5 {public static void main(String[] args) {File f = new File("d:/project/a/b/c");// boolean ret = f.mkdir();//如果File构造方法的参数中传入d:/project,则可以用mkdir();如果传入的是d:/project/a/b/c这样多个层次的目录,则要用mkdirs()boolean ret = f.mkdirs();System.out.println("ret = " + ret);}
}

renameTo(File dest)(文件重命名):

class Test6 {public static void main(String[] args) {File srcFile = new File("d:/test.txt");File destFile = new File("d:/test2.txt");boolean ret = srcFile.renameTo(destFile);//将srcFile重命名为destFileSystem.out.println("ret = " + ret);}
}

四、文件内容操作

文件内容操作即读写文件,写代码时要close()对应的文件资源。
关于流对象Java标准库中提供了很多类,这些类可以归结到两个大类中。
1、字节流:每次读/写的最小单位为字节,对应着二进制文件。字节流延伸出的父类有InputStream、OutputStream,这两个父类延伸出很多子类。
2、字符流:每次读/写的最小单位为字符,一个字符可能对应多个字节,看当前的字符集是哪种,GBK一个中文字符对应两个字节,UTF-8一个中文字符对应三个字节。字符流延伸出的父类有Reader、Writer,这两个父类延伸出很多子类。
把数据保存到硬盘中,我们以cpu为视角,这个过程叫输出,相反从硬盘中读取数据到内存这个过程叫输入。

4.1Reader类里的函数

①read()一次读取一个字符。
②read(char[] cbuf)一次读取多个字符,会把参数指定的cbuf数组给填充满(即输出型参数),read(char[] cbuf)会尽可能把cbuf这个数组给填充满。
③read(char[] cbuf, int off, int len)一次读取多个字符,会把参数指定的cbuf数组从off这个位置往后数len这么长的位置给填充满。
read()的返回值是int,代表读到的字符,这样做的目的是当文件读完时要返回-1,而char无法返回-1。如果读到了字符int会返回的范围是0~65535(即一个char能表示的范围,即两个字节)。

read()读取到的字符如果是中文字符每个字符对应的是两个字节是unicode编码,但如果是utf-8编码每个中文字符应该对应的是三个字节,这不就混乱了吗?
实际上并不会,Java标准库对字符编码进行了一系列的处理。如果使用char,使用的字符集就是unicode;如果是使用String,使用的字符集就是utf-8。
char[] arr里面的每个字符都是以unicode编码,
但一旦使用这个字符数组构造成String,比如String s=new String(arr) 就会把字符数组里的每个字符转换为utf-8编码,
s.charAt(i)又会把utf-8编码的字符转换为unicode编码。
字符是unicode编码,而String大概率是utf8编码(用了大概率这个词是因为是否是utf8编码是可以配置的)。
read()涉及到的是字符所以用的是unicode编码,每个中文字符只是两个字节。

read(char[] cbuf)、read(char[] cbuf, int off, int len)的返回值为int表示实际读取到的字符的个数,如果读到文件末尾返回-1。

使用close()来关闭对应的文件资源的主要目的是为了释放文件描述符表里的元素。
文件描述符表是一个顺序表,一个进程每打开一个文件就需要在这个表里分配一个元素,而这个表的长度是有上限的,如果代码一直是打开文件而不去关闭文件,就会使这个表里的元素越来越多直到把表占满,后续再尝试打开文件就会报错,这个问题叫“文件资源泄露”。

class Test7 {public static void main(String[] args) throws IOException {
/*        Reader reader = new FileReader("d:/test.txt");//reader是抽象类不能通过new关键字创建对象,只能通过Reader子类用new关键字来创建子类对象赋值给Reader引用。创建对象的过程就是打开d:/test.txt文件的过程,如果文件不存在则打开失败抛出FileNotFoundException异常//1.用无参数的read()while (true) {int c = reader.read();if (c == -1) {break;}char ch = (char)c;System.out.println(ch);}//2.用有参数的read(cbuf)try {while (true) {//加while循环是因为,如果文件内容特别长,超出了cbuf数组的范围,这时就可以循环多次,保证最终能把文件读完。char[] cbuf = new char[3];int n = reader.read(cbuf);//n表示当前读到的字符的个数if (n == -1) {break;}System.out.println("n = " + n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}} finally {//文件使用完了,要记得close()reader.close();//close()要写在finally里保证try里的代码无论是正常执行完毕还是抛出异常执行完毕close()都一定会被执行到。如果close()不写在finally里,如果上面的read(cbuf)抛出异常方法会立刻结束此时后面的close()就执行不到了。}        *///3.对2的写法进行优化,写成try with resources的形式try (Reader reader1 = new FileReader("d:/test.txt")) {//推荐写法,这个语法叫try with resources,在try的()中定义的变量会在try代码块结束的时候(无论是正常结束还是抛出异常结束)自动调用其中的close()方法。在try的()中的对象必须实现Closeable接口,流对象都可以写入try的()中。while (true) {char[] cbuf = new char[3];int n = reader1.read(cbuf);if (n == -1) {break;}System.out.println("n = " + n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}}}
}

new FileReader(“d:/test.txt”)会抛出FileNotFoundException,read()会抛出IOException,IOException是FileNotFoundException的父类。

4.2Writer类里的函数

①write(int c)一次写一个字符。
②write(String str)一次写一个字符串。
③write(char[] cbuf)一次写多个字符(字符数组)。
④write(String str, int off, int len)
⑤write(char[] cbuf, int off, int len)
write()的一系列方法写入文件时在默认情况下会把原有文件的内容清空掉再写入。
如果不想把把原有文件的内容清空,则要在FileWriter的构造方法中多传入第二个参数true(第二个参数代表是否append追加),此时就不会清空原来文件的内容而是写入到原来文件内容的末尾。

class Test7 {public static void main(String[] args) {try (Writer writer = new FileWriter("d:/test.txt", true)) {writer.write("我正在学习");} catch (IOException e) {throw new RuntimeException(e);}}
}

4.3InputStream类里的函数

①read(byte[] b, int off, int len)
②read(byte[] b)
③read()
read()的返回值是int,如果读到了字节int会返回的范围是0~255(即一个无符号byte能表示的范围,即一个字节),如果文件读完时则返回-1。

class Test9 { public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("d:/test.txt")) {byte[] buffer = new byte[1024];int n = inputStream.read(buffer);System.out.println("n = " + n);for (int i = 0; i < n; i++) {System.out.printf("%x\n", buffer[i]);//%x是打印16进制,4个比特位(4个二进制位)对应一个16进制位}} catch (IOException e) {e.printStackTrace();}} 
}

4.4OutputStream类里的函数

①write(byte[] b, int off, int len)
②write(int b)
③write(byte[] b)

class Test10 {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("d:/test.txt", true)) {//不想清空文件里的原有内容则FileOutputStream的构造方法中要传入一个trueString s = "你好世界";outputStream.write(s.getBytes());//将字符串里面的内容转成字节数组  } catch (IOException e) {e.printStackTrace();}}
}

4.5字节流转换为字符流

如果别人给我们提供的是字节流对象,但是我们知道实际的数据内容是文本数据,这时我们可以把字节流转换成字符流(有很多种转换的办法)。
读时字节流转换为字符流:

class Test11 {public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("d:/test.txt")) {//此时 scanner从文件中读取内容try (Scanner scanner = new Scanner(inputStream)) {//inputStream即System.in,在实际开发中Scanner这一行要写入try后面的()中String s = scanner.next();System.out.println(s);}} catch (IOException e) {e.printStackTrace();}}
}

写时字节流转换为字符流:

class Test12 {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("d:/test.txt")) {//这相当于把字节流转成字符流try(PrintWriter writer = new PrintWriter(outputStream)) {writer.println("hello");writer.flush();//这里的flush()一定要加}} catch (IOException e) {e.printStackTrace();}}
}

writer.flush()一定要加,因为PrintWriter这样的类在进行写入的时候,不一定是直接把数据写入硬盘,而是先把数据写入到一个内存构成的“缓冲区”(buffer)中。引入“缓冲区”的概念是为了提高程序执行效率。比如把数据写入内存非常快,而把数据写入硬盘非常慢,为了提升效率先把数据写入到内存中等数据积攒到一定程度时再把数据写入硬盘,这样减少了写入硬盘的次数提升了效率。但这样有一个问题,当数据写入到缓冲区之后,如果缓冲区的数据还没来得及写入硬盘进程就结束了,此时缓冲区的数据也随之丢失。为了避免这个问题,应该在合适的时机使用flush()手动刷新缓冲区。

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

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

相关文章

【刷题-牛客】链表内指定区间反转

链表定区间翻转链表 题目链接题目描述核心思想详细图解代码实现复杂度分析 题目链接 链表内指定区间反转_牛客题霸_牛客网 (nowcoder.com) 题目描述 核心思想 遍历链表的过程中在进行原地翻转 [m,n]翻转区间记作子链表,找到子链表的 起始节点 left 和 终止节点 right记录在…

爬虫,初学者指南

第一篇&#xff1a;入门测速request模块的基本使用以www.douban.com为例 import requests url "http://www.douban.com" heards {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0…

组队竞赛(int溢出问题)

目录 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 &#xff08;二&#xff09;正确代码 1. long long sum0 2. #define int long long 3. 使用现成的sort函数 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 #include <iostream&g…

自动化测试的定位及一些思考

大家对自动化的理解&#xff0c;首先是想到Web UI自动化&#xff0c;这就为什么我一说自动化&#xff0c;公司一般就会有很多人反对&#xff0c;因为自动化的成本实在太高了&#xff0c;其实自动化是分为三个层面的&#xff08;UI层自动化、接口自动化、单元测试&#xff09;&a…

Sourcetree 无法打开/闪退问题

Sourcetree在某次开机以后无法打开或者是闪退。 Sourcetree是一款Git的可视化图形管理界面,提供了Windows和Mac的免费Git客户端,很方便的管理项目的代码版本 出现问题的环境 win11&#xff0c;sourcTree版本&#xff1a;3.4.12.0 在开始菜单搜索sourcetree&#xff0c;打开…

线上论坛之单元测试

对线上论坛进行单元测试的测试报告 源码地址&#xff1a;https://gitee.com/coisini-thirty-three/forum 一、用户部分&#xff08;UserServiceImplTest&#xff09; 1.创建普通用户 测试名称 createNormalUser() 测试源码 Test void createNormalUser() { // 构造用户 User …

为您的SSH提提速

SSH是运维和开发人员接触比较多的工具&#xff0c;一般用SSH来连接远程服务器&#xff0c;这个是我的一些免费客户和企业客户经常使用的场景&#xff0c;当然SSH除了远程连接之外&#xff0c;还有很多额外的用途&#xff0c;比如SSH本身是具备代理功能的&#xff0c;我们也有一…

【2023年研究生数学建模】E题解题思路

问题1 针对问题1.1&#xff0c;要求判断患者sub001至sub100发病后48小时内是否发生血肿扩张事件。对于此&#xff0c;先构建新表&#xff0c;记录每次检查的时间及血肿体积。采取遍历的方式识别48小时内是否出现血肿扩张事件&#xff0c;若发生血肿扩张&#xff0c;则记录入表…

如何写一份出色的毕业设计任务书

title: 如何写一份出色的毕业设计任务书 date: 2023-09-20 毕业设计任务书是每个毕业生必须面对的关键文档。它不仅是你完成毕业设计的路线图&#xff0c;还是导师评估你工作的依据。因此&#xff0c;撰写一份清晰、详细且具体的任务书至关重要。本文将向你介绍如何编写一份出色…

【Seata】seata的部署和集成

一、部署Seata的tc-server 1.下载 首先我们要下载seata-server包&#xff0c;地址在http://seata.io/zh-cn/blog/download.html 当然&#xff0c;课前资料也准备好了&#xff1a; 2.解压 在非中文目录解压缩这个zip包&#xff0c;其目录结构如下&#xff1a; 3.修改配置 修…

【MySQL】索引

索引 索引是帮助 MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上实现高级…

pyspark常用算子总结

欢迎关注微信公众号&#xff0c;更多优质内容会在微信公众号首发 1. pyspark中时间格式的数据转换为字符串格式的时间&#xff0c;示例代码 from datetime import datetimedate_obj datetime(2023, 7, 2) formatted_date date_obj.strftime("%Y-%m-%d %H:%M:%S")p…

go 线程限制数量 --chatGPT

问&#xff1a;runTask(names, limit), 遍历启动以names的子名称的工作线程 name测试打印&#xff0c;上限数量是limit, 要求打印所有names gpt: 你可以使用 Go 协程来实现 runTask 函数&#xff0c;该函数会遍历启动以 names 子名称的工作线程&#xff0c;并在达到上限数量 …

【MySQL数据库事务操作、主从复制及Redis数据库读写分离、主从同步的实现机制】

文章目录 MySQL数据库事务操作、主从复制及Redis数据库读写分离、主从同步的实现机制ACID及如何实现事务隔离级别&#xff1a;MVCC 多版本并发控制MySQL数据库主从复制主从同步延迟怎么处理Redis 读写分离1.什么是主从复制2.读写分离的优点 Redis为什么快呢&#xff1f; MySQL数…

Docker初识

什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署&#xff0c;环境不一定一致&#xff0c;会遇到…

Matlab图像处理-模式识别

模式识别 模式识别就是用计算的方法根据样本的特征将样本划分到一定的类别中去。模式识别就是通过计算机用数学技术方法来研究模式的自动处理和判读&#xff0c;把环境与客体统称为“模式”。模式识别以图像处理与计算机视觉、语音语言信息处理、脑网络组、类脑智能等为主要研…

题目 1063: 二级C语言-统计字符

输入一行字符&#xff0c;分别统计出其中英文字母、空格、数字和其它字符的个数。 样例输入a 1, 样例输出 1 1 1 1 鉴于直接用cin会导致空格无法录入&#xff0c;于是用string的getline函数。 再在对应区间的计数器1就好 #include<iostream> #include<string> …

【每日一题】436. 寻找右区间

436. 寻找右区间 - 力扣&#xff08;LeetCode&#xff09; 给你一个区间数组 intervals &#xff0c;其中 intervals[i] [starti, endi] &#xff0c;且每个 starti 都 不同 。 区间 i 的 右侧区间 可以记作区间 j &#xff0c;并满足 startj > endi &#xff0c;且 startj…

【每日随笔】驾驭人性 ③ ( 胡萝卜 - 用利益让员工离不开你 | 大棒 - 用规则让员工害怕你 | 如何建立制度规则 )

文章目录 一、胡萝卜 - 用利益让员工离不开你二、大棒 - 用规则让员工害怕你三、如何建立制度规则 一、胡萝卜 - 用利益让员工离不开你 上一篇博客 【每日随笔】驾驭人性 ② ( 员工立场问题 | 立场转变 | 吴越同舟 | 老板如何与员工结成利益共同体 ) 中 提到了 , 用利益让员工离…

十几张高清世界地图

十几张高清世界地图 仅供学习&#xff01;