Java输入输出流(IO)
概论
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输成为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。输入流和输出的读取和写入流程如图所示。

分类
1.字符流和字节流
字符流:以字符为最小数据单位的流,是基于字节流 + 编码表(UTF-8/GBK)封装的流。
字节流:以字节(8 位二进制)为最小数据单位进行数据读写的流,是 Java IO 中**最基础、最通用的流。
2.输入流和输出流
输入流:数据从「外部设备」流向「Java 程序(内存)」**的流,核心作用是**读取数据。
输出流:数据从「Java 程序(内存)」流向「外部设备」**的流,核心作用是**写入数据。
3.节点流和处理流
节点流:直接连接数据源 / 数据目的地的流,是真正负责底层数据读写的基础流(无任何包装)。
处理流:包装节点流,不直接连接数据源,仅对已有流进行功能增强的流(基于装饰者模式实现)。
IO 流的体系结构

Java.io 包中的最重要的部分是由6个类和1个接口组成。6个类是指 File、RandomAccessFile、InputStream、OutputStream、Writer、Reader,1个接口指的是 Serializable。掌握了这些 I/O 的核心操作,那么对于Java 中的 I/O 体系也就有了一个初步的认识了。
总体上看,Java I/O 主要包括如下3个部分:
流式部分:I/O 的主体部分。
非流式部分:主要包含一些辅助流式部分的类,如 File 类、RandomAccessFile 类和 FileDescriptor 类等。
其他类:主要是文件读取部分的与安全相关的类(如 SerializablePermission 类),以及与本地操作系统相关的文件系统的类,如(FileSystem 类、Win32FileSystem 类和 WinNTFileSystem 类)。
这里,将 Java I/O 中主要的类简单介绍如下:
File类:文件和目录操作,用于表示文件或目录,并提供文件操作,如创建、删除、重命名等。
InputStream类:抽象类 (输入流),基于字节输入操作的抽象类,是所有字节输入流的父类,定义了所有输入流都具有的共同特征。
OutputStream类:抽象类 (输出流),基于字节输出操作的抽象类,是所有字节输出流的父类,定义了所有输出流都具有的共同特征。
Reader类:抽象类 (输入流),所有字符输入流的超类,处理字符的输入操作。
Writer类:抽象类 (输出流),所有字符输出流的超类,处理字符的输出操作。
RandomAccessFile类:随机访问文件,支持文件的随机访问,可以从文件的任意位置读写数据。
缓冲流和缓冲区(是处理流里的分支)
流和缓冲区都是用来描述数据的。计算机中,数据往往会被抽象成流,然后传输。
比如读取一个文件,数据会被抽象成文件流;播放一个视频,视频被抽象成视频流。
在传输层协议当中,应用往往先把数据放入缓冲区,然后再将缓冲区提供给发送数据的程序。发送数据的程序,从缓冲区读取出数据,然后进行发送。
中心思想:减少对硬盘的读写次数,提高读写效率。
通俗解释:送快递,如果到了一个快递,我就给人送去,然后又到了一个快递,又给别人送去,这样效率就非常低下。于是我把快递囤了一定数量,然后再用快递车一起去送,那么效率将高得多。
问题:
那么缓冲流有什么好处么?为什么有了InputStream还需要BufferedInputStream呢?
BufferedInputStream、BufferedOutputStream是FilterInputStream、FilterOutputStream的子类,作为装饰器类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。
我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
代码实现
File类(文件创建,获取,删除)
在文件夹中创建1.txt文件和b目录

书写类DemoA
import java.io.File;
// 描述文件类
public class DemoA {
// 1. 获取到文件或者目录
private static void a() {
// 代表的是一个文件,1.txt 存在
File file1 = new File("/D:/java代码/workspace/io/1.txt"); //刚才创建文件的地方
// 代表的是一个文件,2.txt 不存在
File file2 = new File("/D:/java代码/workspace/io/2.txt");
// 代表的是一个目录(文件夹),a目录
File file3 = new File("/D:/java代码/workspace/io/a");
// 代表的是一个目录(文件夹),b目录,存在
File file4 = new File("/D:/java代码/workspace/io/b");
System.out.println(file1);
System.out.println(file2);
System.out.println(file3);
System.out.println(file4);
}
public static void main(String[] args) {
a();
}
}
文件和目录的常见方法1️⃣
// 文件和目录的常见方法1️⃣
private static void b() {
File file = new File("/D:/java代码/workspace/io/1.txt");
// 1.获取到名称
String name = file.getName();
// 2.获取到绝对路径
String absolutePath = file.getAbsolutePath();
// 3.判断是否是目录、是否是文件
boolean isFile = file.isFile();
boolean isDirectory = file.isDirectory();
// 4.判断是否存在
boolean exists = file.exists();
// 5.获取到父目录
String parentPath = file.getParent();
System.out.println(name);
System.out.println(absolutePath);
System.out.println(isFile);
System.out.println(isDirectory);
System.out.println(exists);
System.out.println(parentPath);
}
文件和目录的常见方法2️⃣
// 文件和目录的常见方法2️⃣
private static void c() {
File file = new File("/D:/java代码/workspace");
if (file.isDirectory()) {
// 获取到子内容
File[] childFiles = file.listFiles();
for (File childFile : childFiles) {
System.out.println(childFile.getName());
}
}
}
文件和目录的常见方法3️⃣
// 文件和目录的常见方法3️⃣
@SneakyThrows
private static void d() {
File file1 = new File("/D:/java代码/workspace/io/2.txt");
if (!file1.exists()) {
// 创建文件
boolean isSuccess = file1.createNewFile();
System.out.println(isSuccess);
}
File file2 = new File("/D:/java代码/workspace/io/c/a");
if (!file2.exists()) {
// 创建目录
// boolean isSuccess = file2.mkdir();//不带s不能创建子目录的不存在的父目录
boolean isSuccess = file2.mkdirs();//带s的即使没有c,也能帮你把a的父目录c创建出来
System.out.println(isSuccess);
}
// 删除文件
file1.deleteOnExit();
// 删除目录
file2.deleteOnExit();
}
遍历某个盘符
// 遍历某个盘符
private static void e(File file, int index) {
for (int i = 0; i < index; i++) {
System.out.print(" ");
}
System.out.println(file.getName());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File childFile : files) {
int m = index + 1;
e(childFile, m);
}
}
}
public static void main(String[] args) {
File file = new File("/D:/java代码/workspace");
int index = 0;
e(file, index);
}
效果

OutputStream类(写)
文件写入(覆盖)
import lombok.SneakyThrows;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Scanner;
// 文件的写入(字节流形式)
public class DemoB {
@SneakyThrows
private static void a() {
// 1.产生一个文件
File file = new File("/D:/java代码/workspace/io/1.txt");
boolean exists = file.exists();
if (!exists) {
System.out.println("该文件不存在");
return;
}
// 2.写入到这个文件中(覆盖)
// 2.1 产生写入的对象(字节流对象)
OutputStream out = new FileOutputStream(file);
// 2.2 写入一个字
String s = "张三来了呀";
byte[] bytes = s.getBytes();
out.write(bytes);
// 2.3 关闭流通道
//out.close();
}
public static void main(String[] args) {
a();
}
}
文件写入(追加)
@SneakyThrows
private static void b() {
// 1.产生一个文件
File file = new File("/D:/java代码/workspace/io/1.txt");
boolean exists = file.exists();
if (!exists) {
System.out.println("该文件不存在");
return;
}
// 2.写入到这个文件中(追加)
// 2.1 产生写入的对象(字节流对象) 追加操作
OutputStream out = new FileOutputStream(file, true);
// 2.2 写入一个字
String s = "张三来了呀";
byte[] bytes = s.getBytes();
out.write(bytes);
// 2.3 关闭流通道
out.close();
}
控制台键盘写入
@SneakyThrows
private static void c() {
File file = new File("/D:/java代码/workspace/io/2.txt");
boolean exists = file.exists();
if (!exists) {
System.out.println("该文件不存在");
file.createNewFile();
}
OutputStream out = new FileOutputStream(file);
Scanner scan = new Scanner(System.in);
String line;
do {
System.out.print("请输入:");
line = scan.nextLine();
if ("bye".equals(line)) {
break;
}
byte[] bytes = (line + "\n").getBytes();
out.write(bytes);
} while (true);
out.close();
}
InputStream类
一次性读取一个字节
import java.io.*;
import java.util.Arrays;
// 文件的读取(字节流形式)
public class DemoC {
// 一次读取一个字节
@SneakyThrows
private static void a() {
File file = new File("/D:/java代码/workspace/io/2.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (file.isDirectory()) {
System.out.println("读取的必须是文件");
return;
}
InputStream in = new FileInputStream(file);
// 读取了一个字
int read = in.read();
System.out.println(read);
in.close();
}
public static void main(String[] args) {
a();
}
}
根据循环将内容读取完毕
@SneakyThrows
private static void b() {
File file = new File("/D:/java代码/workspace/io/2.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (file.isDirectory()) {
System.out.println("读取的必须是文件");
return;
}
InputStream in = new FileInputStream(file);
while (true) {
// 读取了一个字
int read = in.read();
if (read == -1) {
break;
}
System.out.print((char) read);
}
in.close();
}
一次读取多个字节
@SneakyThrows
private static void c() {
File file = new File("/D:/java代码/workspace/io/2.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (file.isDirectory()) {
System.out.println("读取的必须是文件");
return;
}
InputStream in = new FileInputStream(file);
// 一次读取了十个字节
byte[] buffer = new byte[19];
// len:实际读取的长度
int len = in.read(buffer);
if (len == -1) {
System.out.println("没有内容");
}
System.out.println(Arrays.toString(buffer));
String str = new String(buffer);
System.out.println(str);
in.close();
}
循环的方式
@SneakyThrows
private static void d() {
File file = new File("/D:/java代码/workspace/io/2.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (file.isDirectory()) {
System.out.println("读取的必须是文件");
return;
}
InputStream in = new FileInputStream(file);
// 一次读取了十个字节
byte[] buffer = new byte[10];
// len:实际读取的长度
while (true) {
int len = in.read(buffer);
if (len == -1) {
System.out.println("没有内容");
break;
}
String str = new String(buffer);
System.out.print(str);
}
in.close();
}
将5.png复制到另一个目录中
@SneakyThrows
private static void e() {
File srcFile = new File("/D:/java代码/workspace/io/a/5.png");
File destFile = new File("/D:/java代码/workspace/io/b/5.png");
// 读取文件
InputStream in = new FileInputStream(srcFile);
// 写入文件
OutputStream out = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
while (true) {
int len = in.read(buffer);
if (len == -1) {
break;
}
out.write(buffer, 0, len);
}
in.close();
out.close();
}
Reader类
读取一个字符
@SneakyThrows
private static void a() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (!file.isFile()) {
System.out.println("不是一个文件");
return;
}
// 产生一个字符读取流
Reader reader = new FileReader(file);
// 读取一个字符
int i = reader.read();
if (i == -1) {
System.out.println("文件读取完毕");
return;
}
char ch = (char) i;
System.out.println(ch);
reader.close();
}
循环方式
@SneakyThrows
private static void b() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (!file.isFile()) {
System.out.println("不是一个文件");
return;
}
// 产生一个字符读取流
Reader reader = new FileReader(file);
while (true) {
// 读取一个字符
int i = reader.read();
if (i == -1) {
System.out.println("文件读取完毕");
break;
}
char ch = (char) i;
System.out.print(ch);
}
reader.close();
}
读取多个字符
@SneakyThrows
private static void c() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (!file.isFile()) {
System.out.println("不是一个文件");
return;
}
Reader reader = new FileReader(file);
char[] chars = new char[5];
int len = reader.read(chars);
System.out.println(chars);
reader.close();
}
循环方式
@SneakyThrows
private static void d() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
if (!file.isFile()) {
System.out.println("不是一个文件");
return;
}
Reader reader = new FileReader(file);
char[] chars = new char[5];
while (true) {
int len = reader.read(chars);
if(len == -1) {
break;
}
String str = new String(chars, 0, len);
System.out.print(str);
}
reader.close();
}
Writer类
写入到了字符缓冲区
@SneakyThrows
private static void a() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (file.isDirectory()) {
System.out.println("不是一个文件");
return;
}
Writer writer = new FileWriter(file);
// 写入是写入到了字符缓冲区(临时的内存区域)
writer.write("你好");
// 将字符缓冲区中的数据写入到硬盘中
writer.flush();
writer.close();
}
批量换行写入
@SneakyThrows
private static void b() {
File file = new File("/D:/java代码/workspace/io/1.txt");
if (file.isDirectory()) {
System.out.println("不是一个文件");
return;
}
Writer writer = new FileWriter(file);
Scanner scan = new Scanner(System.in);
while (true) {
System.out.print("Input:");
String input = scan.next();
if ("再见".equals(input)) {
break;
}
writer.write(input + "\n");
}
writer.close();
}
RandomAccessFile类
Java 提供的 RandomAccessFile 类,允许从文件的任何位置进行数据的读写。它不属于流,是 Object 类的子类,但它融合了 InputStream 类和 OutStream 类的功能,既能提供 read()方法和 write()方法,还能提供更高级的直接读写各种基本数据类型数据的读写方法,如 readInt()方法和 writeInt()方法等。
public class RandomAccessFileTest{
public static void main(String[] args) throws Exception {
File file = new File("D://guanwei//guanwei.txt");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
// 从2号位置开始定位
raf.seek(2);
// 插入7个字母‘abcdefg’ 会覆盖其后的7个内容
raf.write("abcdefg".getBytes());
// 获取当前指针的位置
long pointer = raf.getFilePointer();
System.out.println("当前指针位置是:" + pointer);
// 读取,设置从0开始读取
raf.seek(0);
byte[] bs = new byte[100];
int len;
while ((len = raf.read(bs)) != -1) {
System.out.println(new String(bs, 0, len));
}
}
}
缓冲流
字节流的写入缓冲
@SneakyThrows
private static void a() {
File file = new File("/D:/java代码/workspace/io/1.txt");
// 创建了一个字节写入流
OutputStream in = new FileOutputStream(file);
// 创建缓冲流
BufferedOutputStream bis = new BufferedOutputStream(in);
bis.write("hello".getBytes());
bis.flush();
bis.close();
}
字节流的读取缓冲
@SneakyThrows
private static void b1() {
File file = new File("/D:/java代码/workspace/io/2025.07.24.17.23.mp4");
InputStream in = new FileInputStream(file);
long start = System.currentTimeMillis();
byte[] buffer = new byte[1024];
while (true) {
int len = in.read(buffer);
if (len == -1) {
break;
}
}
long end = System.currentTimeMillis();
System.out.println("总共花费了:" + (end - start) + "毫秒");
in.close();
}
字符流的写入缓冲
@SneakyThrows
private static void c() {
File file = new File("/D:/java代码/workspace/io/1.txt");
Writer writer = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(writer);
bw.write("你好,我是张三,我是使用缓冲流写入的数据");
bw.flush();
}
字符流的读取缓冲
@SneakyThrows
private static void d1() {
File file = new File("/D:/java代码/workspace/io/2.txt");
Reader reader = new FileReader(file);
char[] buffer = new char[10];
long start = System.currentTimeMillis();
while (true) {
int len = reader.read(buffer);
if (len == -1) {
break;
}
System.out.print(new String(buffer, 0, len));
}
System.out.println();
long end = System.currentTimeMillis();
System.out.println("总共花费了:" + (end - start) + "毫秒");
reader.close();
}
字节流转字符流
import lombok.SneakyThrows;
import java.io.*;
public class DemoG {
@SneakyThrows
public static void main(String[] args) {
File file = new File("/D:/java代码/workspace/io/1.txt");
InputStream in = new FileInputStream(file);
// 通过InputStreamReader将字节流---->字符流
Reader reader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = bufferedReader.readLine();
System.out.println(line);
bufferedReader.close();
reader.close();
in.close();
OutputStream out = new FileOutputStream(file);
// 通过OutputStreamWriter将字节流---->字符流
Writer writer = new OutputStreamWriter(out);
writer.write("asjkdhkdsjhiwheswegqwiud你啊后啊我😋3 的说法 ");
writer.flush();
}
}
&spm=1001.2101.3001.5002&articleId=159795556&d=1&t=3&u=1a5cbb855ed74cdb8d0793e78257c573)
958

被折叠的 条评论
为什么被折叠?



