Java文件I/O简单介绍
一、File类
java.io.File
类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
1.1 构造方法
public File(String pathname); // 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String parent, String child); // 从父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child); // 从父抽象路径名和子路径名字符串创建新的 File实例。
1.2 常用方法
/// API
// 获取功能
public String getAbsolutePath(); // 返回此File的绝对路径名字符串。
public String getPath(); // 将此File转换为路径名字符串。
public String getName(); // 返回由此File表示的文件或目录的名称。
public long length(); // 返回由此File表示的文件的长度。若File对象表示目录,则返回值未指定。
// 判断功能
public boolean exists(); // 此File表示的文件或目录是否实际存在。
public boolean isDirectory(); // 此File表示的是否为目录。
public boolean isFile(); // 此File表示的是否为文件。
// 创建删除功能
public boolean createNewFile(); // 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete(); // 删除由此File表示的文件或目录。
public boolean mkdir(); // 创建由此File表示的目录。
public boolean mkdirs(); // 创建由此File表示的目录,包括任何必需但不存在的父目录
// 目录的遍历
public String[] list(); // 返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles(); // 返回一个File数组,表示该File目录中的所有的子文件或目录。
1.3 例子
- 递归打印多级目录
public static void printDir(File dir) {
// 获取子文件和目录
File[] files = dir.listFiles();
// 循环打印
for (File file : files) {
// 判断
if (file.isFile()) {
// 是文件,输出文件绝对路径
// if (file.getName().endsWith(".java")) // 筛选后缀是 .java 的文件
System.out.println("文件名:" + file.getAbsolutePath());
} else {
// 是目录,输出目录绝对路径
System.out.println("目录:" + file.getAbsolutePath());
// 继续遍历,调用printDir,形成递归
printDir(file);
}
}
}
- 使用文件过滤器
java.io.FileFilter
接口来筛选文件:
public static void printDir2(File dir) {
// Lambda表达式优化
// File[] files = dir.listFiles(f -> f.getName().endsWith(".java") || f.isDirectory());
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java") || pathname.isDirectory();
}
});
// 循环打印
for (File file : files) {
// 判断
if (file.isFile()) {
System.out.println("文件名:" + file.getAbsolutePath());
} else {
printDir2(file);
}
}
}
java 7 引入了一些新的文件处理类用来代替 File 类的文件 I/O 操作方式:Java NIO系列教程
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
二、基础I/O:字节流、字符流
输入流 | 输出流 | |
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
2.1 字节流
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节。所以字节流可以传输任意文件数据。
2.1.1 字节输出流 OutputStream
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close();
public void flush();
public void write(byte[] b);
public void write(byte[] b, int off, int len);
public abstract void write(int b);
2.1.2 FileOutputStream类
java.io.FileOutputStream
类是文件输出流,用于将数据写出到文件。
public FileOutputStream(File file);
public FileOutputStream(String name);
- 写出字节:write 方法;
- 每次程序运行,创建输出流对象,都会清空目标文件中的数据。构造方法还可以传入一个
boolean append
参数,表示追加写。 - 写出换行:
fos.write("\r\n".getBytes());
2.1.3 字节输入流 InputStream
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close();
public abstract int read();
public int read(byte[] b);
2.1.4 FileInputStream类
java.io.FileInputStream
类是文件输入流,从文件中读取字节。
FileInputStream(File file);
FileInputStream(String name);
- 读取字节:read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回 -1;
- 使用字节数组读取:read(byte[] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1。
2.2 字符流
一些字符如中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
2.2.1 字符输出流 Writer
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类。
void write(int c);
void write(char[] cbuf);
abstract void write(char[] cbuf, int off, int len);
void write(String str);
void write(String str, int off, int len);
void flush();
void close();
2.2.2 FileWriter类
java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileWriter(File file);
FileWriter(String fileName);
- 写出字符:write 方法;
- flush :刷新缓冲区;
- close :先刷新缓冲区,然后通知系统释放资源。
字符流,只能操作文本文件,不能操作图片,视频等非文本文件。当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
2.2.3 字符输入流 Reader
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类。
public void close();
public int read();
public int read(char[] cbuf);
2.2.4 FileReader类
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileReader(File file);
FileReader(String fileName);
- 读取字符: read() 方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回 -1;
- 使用字符数组读取: read(char[] cbuf) ,每次读取b的长度个字符到数组中,返回读取到的有效字符个数,
读取到末尾时,返回 -1。
当创建一个文件输入流对象时,若没有该文件,会抛出
FileNotFoundException
;创建文件输出流对象时,若没有该文件,会自动创建。
try-with-resource
三、缓冲流、转换流、序列化流、打印流
3.1 缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类。
- 字节缓冲流:
BufferedInputStream
,BufferedOutputStream
- 字符缓冲流:
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
3.1.1 字节缓冲流
构造方法:
public BufferedInputStream(InputStream in); // 创建一个新的缓冲输入流。
public BufferedOutputStream(OutputStream out); // 创建一个新的缓冲输出流。
字节缓冲流读写方法与基本的流是一致的。
3.1.2 字符缓冲流
构造方法
public BufferedReader(Reader in); // 创建一个新的缓冲输入流。
public BufferedWriter(Writer out); // 创建一个新的缓冲输出流。
字符缓冲流的基本方法与普通字符流调用方式一致。特有方法:
/// BufferedReader:
public String readLine(); // 读一行文字
/// BufferedWriter:
public void newLine(); // 写一行行分隔符,由系统属性定义符号
3.2 转换流
3.2.1 InputStreamReader类
转换流java.io.InputStreamReader
,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
InputStreamReader(InputStream in); // 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName); // 创建一个指定字符集的字符流
3.2.1 OutputStreamWriter类
转换流java.io.OutputStreamWriter
,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
OutputStreamWriter(OutputStream in); // 创建一个使用默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName); // 创建一个指定字符集的字符流。
3.3 序列化
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据
、对象的类型
和对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据
、对象的类型
和对象中存储的属性
信息,都可以用来在内存中创建对象。
3.3.1 ObjectOutputStream类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法:
public ObjectOutputStream(OutputStream out); // 创建一个指定OutputStream的ObjectOutputStream
/// 示例:
FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
- 一个对象要想序列化,必须满足两个条件
- 该类必须实现
java.io.Serializable
接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
。 - 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用
transient
关键字修饰
- 写出对象方法
public final void writeObject (Object obj); // 将指定的对象写出
3.3.2 ObjectInputStream类
java.io.ObjectInputStream
反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法:
public ObjectInputStream(InputStream in); // 创建一个指定InputStream的ObjectInputStream。
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法:
public final Object readObject (); // 读取一个对象
对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个ClassNotFoundException
异常。
另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException
异常。 发生这个异常的原因如下:
- 该类的序列版本号与从流中读取的类描述符的版本号不匹配
- 该类包含未知数据类型
- 该类没有可访问的无参数构造方法
Serializable
接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID
该版本号的目的在于验证序列化的对象和对应类是否版本匹配。示例:
public class Employee implements java.io.Serializable {
// 加入序列版本号
private static final long serialVersionUID = 1L;
public String name;
public String address;
// 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值
public int eid;
public void addressCheck() {
System.out.println("Address check : " + name + " ‐‐ " + address);
}
}
3.4 打印流
平时我们在控制台打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于java.io.PrintStream
类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
3.4.1 PrintStream类
构造方法:
public PrintStream(String fileName);
public PrintStream(File file);
public PrintStream(OutputStream out);
- System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上。
我们可以改变它的流向:
public class PrintDemo {
public static void main(String[] args) throws IOException {
// 调用系统的打印流,控制台直接输出97
System.out.println(97);
// 创建打印流,指定文件的名称
PrintStream ps = new PrintStream("ps.txt");
// 设置系统的打印流流向,输出到ps.txt
System.setOut(ps);
// 调用系统的打印流, ps.txt中输出97
System.out.println(97);
}
}
另,三篇讲得较全面的博客:
CSDN:Java8 I/O源码-整体结构
Java文件I/O简单介绍的更多相关文章
- java中io对文件操作的简单介绍
11.3 I/O类使用 由于在IO操作中,需要使用的数据源有很多,作为一个IO技术的初学者,从读写文件开始学习IO技术是一个比较好的选择.因为文件是一种常见的数据源,而且读写文件也是程序员进行IO编程 ...
- PHP 关于文件操作的简单介绍
文件操作一直是Web程序员头疼的地方,而文件操作在CMS这样的系统中又是必须的.如今,PHP文件操作的函数内容已经非常强大,文件这部分也是学习PHP非常重要的一部分,希望大家不要忽略.这篇文章会简单介 ...
- java反射机制的简单介绍
参考博客: https://blog.csdn.net/mlc1218559742/article/details/52754310 先给出反射机制中常用的几个方法: Class.forName (& ...
- Java泛型使用的简单介绍
目录 一. 泛型是什么 二. 使用泛型有什么好处 三. 泛型类 四. 泛型接口 五. 泛型方法 六. 限定类型变量 七. 泛型通配符 7.1 上界通配符 7.2 下界通配符 7.3 无限定通配符 八. ...
- Java Linked集合的简单介绍和常用方法的使用
LinkedList的简单介绍 java.util.LinkedList 集合数据存储的结构是链表结构.LinkedList是一个双向链表在实际开发中,对一个集合元素的添加和删除,经常涉及到首尾操作, ...
- Java中NIO的简单介绍
NIO基本介绍 Java NIO(New IO) 也有人称之为Java non-blocking IO 是从Java1.4版本开始引入的一个新的IO API,可以代替标准的IO API.NIO与原来的 ...
- java中数据流的简单介绍
java中的I/O操作主要是基于数据流进行操作的,数据流表示了字符或者字节的流动序列. java.io是数据流操作的主要软件包 java.nio是对块传输进行的支持 数据流基本概念 “流是磁盘或其它外 ...
- java文件断点续传的简单实现
一.概述 所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载.在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了.一般断点下载时才用到Range和Content- ...
- php之文件上传简单介绍
要声明的form表单格式 <form action="act.php" method="post" enctype="multipart/for ...
随机推荐
- 【linux】驱动-13-阻塞与非阻塞
目录 前言 13. 阻塞与非阻塞 13.1 阻塞与非阻塞 13.2 休眠与唤醒 13.2.1 内核休眠函数 13.2.2 内核唤醒函数 13.3 等待队列(阻塞) 13.3.1 定义等待队列头部 13 ...
- React-Antd4的Form表单校验
之前很少用react做项目,最近入职新公司,用的react,在自己的摸索过程中,慢慢会记录一些使用方法.今天简单记录一下使用antd 4.0版本的Form表单校验,直接代码. 需要购买阿里云产品和服务 ...
- C#WebApi的创建与发布
VS中新建项目-Web-ASP.NET Web应用程序 然后确定,选择空模版就可以了,勾上Webapi(也可以选择webapi模板,这样生成的文件比较多) 添加好之后Controllers和Model ...
- 一个排序引发的BUG
你好呀,我是why. 前两天在 Git 上闲逛的时候又不知不觉逛到 Dubbo 那里去了. 看了一下最近一个月的数据,社区活跃度还是很高的: 然后看了一下最新的 issue,大家提问都很积极. 其中看 ...
- WEB安全新玩法 [5] 防范水平越权之查看他人订单信息
水平越权是指系统中的用户在未经授权的情况下,查看到另一个同级别用户所拥有的资源.水平越权会导致信息泄露,其产生原因是软件业务设计或编码上的缺陷.iFlow 业务安全加固平台可以缓解部分场景下的水平越权 ...
- JavaScript(1)高阶函数filter、map、reduce
前言 需求:有这样一个数组[10, 20, 110, 200, 60, 30, 40] 1.筛选出数组中小于100的元素 2.将筛选出的每个元素的值x2 3.完成第2步之后,将数组中的所有元素加起来 ...
- 手把手教你实现一个支持插件化的 uTools 工具箱(一)
前言 对于前端同学来说,我们会经常用到各种小工具,比如:图床.颜色拾取.二维码生成器.url 管理.文本比对.json 格式化.当然我们可以 chrome 收藏夹来管理各种在线的小工具,但作为一个有追 ...
- 探索颜色渐变绘制算法(基于Processing语言) 第一部分
突然间意识到连续变化的颜色在程序中是如何实现的这一问题.没错,就想有事找事,我会分好几部分慢慢探寻,其实笔者也不会,咱一起研究.ok,我们开始! 第一部分 初始部分就从官方案例来入手学习.官方给了三个 ...
- 39、升级linux的内核
39.1.什么是linux系统内核: 操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件.一个计算机 系统是一个硬件和软件的共生体,它们互相依赖,不可分割.计算机的硬件,含有外 ...
- HDU 4438 Hunters 区域赛水题
本文转载于 http://blog.csdn.net/major_zhang/article/details/52197538 2012天津区域赛最水之题: 题意容易读懂,然后就是分情况求出A得分的数 ...