欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 【JavaEE】【IO】文件操作

【JavaEE】【IO】文件操作

2024/10/23 2:14:54 来源:https://blog.csdn.net/yj20040627/article/details/142587081  浏览:    关键词:【JavaEE】【IO】文件操作

目录

  • 一、文件
    • 1.1 文件的概念
    • 1.2 文件的操作
    • 1.3 路径
    • 1.4 文件分类
  • 二、Java中的文件元信息、路径操作
    • 2.1 属性
    • 2.2 构造方法
    • 2.3 方法
      • 2.3.1 文件路径
      • 2.3.2 文件判断
      • 2.3.3 文件创建删除
      • 2.3.4 其他操作
  • 三、文件读写操作
    • 3.1 流(Stream)
      • 3.1.1 字节流
        • 3.1.1.1 InputStream
        • 3.1.1.2 OutputStream
      • 3.1.2 字符流
        • 3.1.2.1 Reader
        • 3.1.2.2 Writer
    • 3.2 字节流字符流转换
  • 四、自定义快读类
    • 4.1 自定义快速读入
    • 4.2 自定义快速输出

一、文件

1.1 文件的概念

在操作系统中会将“硬盘设备”和“软件资源”都抽象成文件。

在生活中提到的文件大多指硬盘的文件(像c盘里面的文件),就是硬盘上的数据抽象而成的。

1.2 文件的操作

在计算机上文件是由操作系统提供的“文件系统”来组织管理的,操作系统使用“目录”(也就是常说的文件夹)来管理文件的。目录是一种树形结构

1.3 路径

  • 绝对路径:就是以C盘D盘(C: D:)这种盘符开头的路径。如"E:\植物大战僵尸"。
  • 相对路径:此时需要先指定一个基准目录,然后看通过什么样的路径来到指定文件,这个路径就是相对路径,用点开头。此时用一个点表示当前目录,两个点表示当前目录上一级目录。

举例:
假如我们要找“E:\植物大战僵尸\pvzHE"目录下的"fonts"文件。

  1. 如果我们当前在“E:\植物大战僵尸\pvzHE"目录下,直接使用“.\fonts”
  2. 如果我们在“E:\植物大战僵尸”目录下,使用“.\pvzHE\fonts”
  3. 如果我们在"E:\植物大战僵尸\pvzHE\新建文件夹"目录下,使用“…\fonts”

不同场景下的基准目录:

  1. 在命令行操作,当前目录就是基准目录。
  2. 在idea操作项目目录就是基准目录。
  3. 在图形化工具上就要看实际情况了。

1.4 文件分类

在编程角度上将文件分为两类:

  1. 文本文件:文件中保存的都是字符串,保存的都是合法的字符(合法的字符就是符合当前字符集编码的字符)。
  2. 二进制文件:文件中保存的仅仅是二进制数据。

二、Java中的文件元信息、路径操作

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。

2.1 属性

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

2.2 构造方法

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

2.3 方法

2.3.1 文件路径

修饰符及返回值类型方法签名说明
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 FIle 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径

2.3.2 文件判断

修饰符及返回值类型方法签名说明
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

2.3.3 文件创建删除

修饰符及返回值类型方法签名说明
booleancreateNewFile()根据 File 对象,自动创建一个空文件。成功创建后返回 true
booleandelete()根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行

2.3.4 其他操作

修饰符及返回值类型方法签名说明
String[ ]list()返回 File 对象代表的目录下的所有文件名
File[ ]listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
booleanmkdir()创建 File 对象代表的目录
booleanmkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
booleanrenameTo(Filedest)进行文件改名,也可以视为我们平时的剪切、粘贴操作

三、文件读写操作

在Java中对文件的读写操作使用流对象(stream)

3.1 流(Stream)

在标准库中提供的文件读写操作的类有很多,但可以分为两类。

3.1.1 字节流

字节流对应着二进制文件,每次读写的最小单位都是字节(Byte)。

字节流提供了两个父类(InputStream)(OutputStream)来供继承。

3.1.1.1 InputStream

InputStream在源码中是一个抽象类,不能直接new对象。提供了一个子类FileInputStream。

类需要传文件路径,如果文件没找到还会抛出FileNotFoundException异常。

方法简介

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

默认打开一个文件会先清空,要继续写不清空在创建对象时传入true作为第二个参数。

OutputStream在源码中是一个抽象类,不能直接new对象。提供了一个子类FileOutputStream。

类需要传文件路径,如果文件没找到还会抛出FileNotFoundException异常。

方法

返回值方法签名说明
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(刷新)操作,将数据刷到设备中。

3.1.2 字符流

字符流对应着文本文件,每次读写的最小单位是字符(根据当前字符集来,一个中文字符在utf8就是3字节,GBK就是两字节)。
字符流就相当于对字节流进行了一个封装,自动帮我们把字节流中相邻几个字节转换成字符。

字符流提供了两个父类(Reader)(Writer)来供继承。

3.1.2.1 Reader

Reader在源码中是一个抽象类,不能直接new对象。提供了一个子类FileReader。

FileReader类需要传文件路径,如果文件没找到还会抛出FileNotFoundException异常。

Reader中读取字符常用是read方法,都会抛出IOException异常,介绍常用3种。

返回值分法签名说明
intread()读取一个字符,读取到返回ASCII值或者字符集编码值,没读取到返回-1
intread(char[ ] cbuf)读取多个字符,尽量将cbuf数组填满,返回读取到的字符个数,如果读完文件返回-1
intread(char[ ] cbuf, int off, int len)l最多读len-off个,从数组off下标开始储存,返回读到的个数,如果读完文件返回-1

返回值说明:
int作为返回值时,返回的是一个2字节表示的,这时因为在Java中char类型是Unicode编码,而String是由utf8编码(String的编码集可改)。

创建了一个Reader对象要释放:对象名.close();
主要释放的是文件描述符表(在进程介绍PCB的主要属性),文件描述符表里面主要用顺序表(数组)来储存,如果一直不释放,里面数组被占满就会发生内存泄露。

但是如果直接就这么写,那如果上面代码抛出异常,就执行不到close,改进方法:

  • try-finally处理:
Reader reader = new FileReader("d:/test.txt");
try {int n = reader.read();
} finally {reader.close();}
  • try with resource
    在定义对象时放入,出了try语句就会自动调用类实现的close方法(必须是实现了closeable接口的)。
try( Reader reader = new FileReader("d:/test.txt") ) {int n = reader.read();
}
3.1.2.2 Writer

默认打开一个文件会先清空,要继续写不清空在创建对象时传入true作为第二个参数。

InputStream在源码中是一个抽象类,不能直接new对象。提供了一个子类FileInputStream。

类需要传文件路径,如果文件没找到还会抛出IOException异常。

方法

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

3.2 字节流字符流转换

使用Scanner工具类去读取文件中的字符。

try(InputStream inputStream = new FileInputStream("D:/test.txt")) {Scanner scanner = new Scanner(inputStream);String s = scanner.next();}

使用PrintWriter工具类去写入文件中的字符。

try(OutputStream outputStream = new FileOutputStream("D:/test.txt",true)) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println();}

四、自定义快读类

自定义快读类来解决我们做算法题的时候由于数据量过大的时候引起的超时问题。

4.1 自定义快速读入

我们使用Scanner去读IO设备文件,,而我们现在使用BufferedReader来开辟一个内存缓冲区,在内存中拿数据比IO设备要快得多。

步骤:

  1. 字节流转变为字符流,在存入内存缓冲区中。
BufferedReader bf = new BufferedReader(new InputStreamReader(system.in));
  1. 字符串裁剪对象,拿到内存缓冲区的字符串的必要对象。
StringTokenizer st = new StringTokenizer("");
  1. 详解next方法:相当于在内存缓冲区中拿一行数据,使用while循环来处理多行输入。
String next() throws IOException {while(!st.hasMoreTokens()) {st = new StringTokenizer(bf.readLine());}return st.nextToken();
}
  1. 其他直接返回对应的parse转换就行。

类代码:

import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class Read {StringTokenizer st = new StringTokenizer("");BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));String next() throws IOException {while(!st.hasMoreTokens()) {st = new StringTokenizer(bf.readLine());}return st.nextToken();}String nextLine() throws IOException {return bf.readLine();}int nextInt() throws IOException {return Integer.parseInt(next());}long nextLong() throws IOException {return Long.parseLong(next());}double nextDouble() throws IOException {return Double.parseDouble(next());}float nextFloat() throws IOException {return Float.parsefloat(next());}
}

4.2 自定义快速输出

跟自定义一样的优化方式。

public static PrintWriter out = new PrintWriter(new BufferedWriter(new OutPutStreamWriter(System.out)))

使用之后就直接 out.输出方法,输出方法与System.out一样。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com