Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input 和输出output ,即流向内存是输入流,流出内存的输出流。
Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行,可以看做是一种数据的流动。
I/O流中的I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
按数据的流向不同分为:输入流和输出流。
按操作数据单位的不同分为:字节流(8bit)和字符流(16bit)。
根据IO流的角色不同分为:节点流和处理流。
小结:图解
Java的IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的。
(抽象基类) | 输入流 | 输出流 |
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
常用的节点流:
文件流: FileInputStream、FileOutputStrean、FileReader、FileWriter
字节/字符数组流: ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter
????????对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
常用处理流:
缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
????????作用:增加缓冲功能,避免频繁读写硬盘,进而提升读写效率。
转换流:InputStreamReader、OutputStreamReader
????????作用:实现字节流和字符流之间的转换。
对象流:ObjectInputStream、ObjectOutputStream
????????作用:提供直接读写Java对象功能
Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。不能操作图片,视频等非文本文件。
常见的文本文件有如下的格式:.txt、.java、.c、.cpp、.py等
注意:.doc、.xls、.ppt这些都不是文本文件。
java.io.Reader
抽象类是表示用于读取字符流的所有类的父类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
注意:当完成流的操作时,必须调用close()方法,释放系统资源,否则会造成内存泄漏。
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
注意:当完成流的操作时,必须调用close()方法,释放系统资源,否则会造成内存泄漏。
java.io.FileReader
类用于读取字符文件,构造时使用系统默认的字符编码和默认字节缓冲区。
举例:读取hello.txt文件中的字符数据,并显示在控制台上
package com.suyv.test01;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-19 20:13
*@Description: 读取hello.txt文件中的字符数据,并显示在控制台上
*/
public class FileReader01 {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
//2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中
//3. 通过相关流的方法,读取文件中的数据
//4. 关闭相关的流资源,避免出现内存泄漏
@Test
public void Test01() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file = new File("file\\hello.txt");
//2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中
FileReader fr = new FileReader(file);
//3. 通过相关流的方法,读取文件中的数据
// int data = fr.read(); //每调用一次读取一个字符
// while (data != -1) {
// System.out.print((char) data);
// data = fr.read();
// }
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
//4. 关闭相关的流资源,避免出现内存泄漏
fr.close();
}
/*
* 需求:读取hello.txt中的内容,显示在控制台上。
* 使用try-catch-finally的方式处理异常。确保流一定可以关闭,避免内存泄漏
* */
@Test
public void Test02() {
FileReader fr = null;
try {
//1.创建File类的对象,对应着hello.txt文件
File file = new File("file\\hello.txt");
//2.创建输入型的字符流,用于读取数据
fr = new FileReader(file);
//3.读取数据,并显示在控制台上
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 流资源的关闭操作(必须要关闭,否则会内存泄漏)
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void test3() throws IOException {
//1.创建File类的对象,对应着hello.txt文件
File file = new File("file\\hello.txt");
//2.创建输入型的字符流,用于读取数据
FileReader fr = new FileReader(file);
//3.读取数据,并显示在控制台上
char[] cbuffer = new char[5];
int len;
while ((len = fr.read(cbuffer)) != -1) {
//遍历数组
for (int i = 0; i < len; i++) {
System.out.print(cbuffer[i]);
}
}
//4. 流资源的关闭操作(必须要关闭,否则会内存泄漏)
fr.close();
}
}
java.io.FileWriter
类用于写出字符到文件,构造时使用系统默认的字符编码和默认字节缓冲区。
举例:将内存中的数据写出到指定的文件中
package com.suyv.test01;
import org.junit.Test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 13:54
* @Description: FileWriter的使用--需求:将内存中的数据写出到指定的文件中
*/
public class FileWriter01 {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
//2. 创建FileWriter流对象,将File类的对象作为参数传递到FileWriter的构造器中
//3. 通过相关流的方法,读取文件中的数据
//4. 关闭相关的流资源,避免出现内存泄漏
@Test
public void Test01() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file = new File("file\\info.txt");
//2. 创建FileWriter流对象,将File类的对象作为参数传递到FileWriter的构造器中
FileWriter fw = new FileWriter(file);
//3. 通过相关流的方法,读取文件中的数据
fw.write("HelloWorld\n");
fw.write("中国");
System.out.println("写入成功");
//4. 关闭相关的流资源,避免出现内存泄漏
fw.close();
}
}
package com.suyv.test01;
import org.junit.Test;
import java.io.*;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 14:23
* @Description: 复制一份hello.txt文件,命名为hello_copy.txt
*/
public class FileReaderWriter {
@Test
public void Test01() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file1 = new File("file\\hello.txt");
File file2 = new File("file\\hello_copy.txt");
//2. 创建FileWriter流和FileReader流对象,将File类的对象作为参数传递到FileWriter的构造器中
FileReader fr = new FileReader(file1);
FileWriter fw = new FileWriter(file2);
//3. 通过相关流的方法,读取文件中的数据
int len; // 记录每次读入到cbuffer中的字符的个数
char[] cbuffer = new char[5];
while ((len = fr.read(cbuffer)) != -1){
fw.write(cbuffer,0,len);
}
//4. 关闭相关的流资源,避免出现内存泄漏
fw.close();
fr.close();
}
}
① 因为出现流资源的调用,为了避免内存泄漏,需要使用try-catch-finally处理异常
② 对于输入流来说,File类的对象必须在物理磁盘上存在,否则执行就会报FileNotFoundException。如果传入的是一个目录,则会报IOException异常。
对于输出流来说,File类的对象是可以不存在的。
如果File类的对象不存在,则可以在输出的过程中,自动创建File类的对象
如果File类的对象存在,
????????如果调用FileWriter(File file)或FileWriter(File file,false),输出时会新建File文件覆盖已有的文件
????????如果调用FileWriter(File file,true)构造器,则在现有的文件末尾追加写出内容。
因为内置缓冲区的原因,如果FileWriter不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush() 方法了。
注意:即便是flush()方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
举例:
package com.suyv.test01;
import org.junit.Test;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 14:36
* @Description: flush的使用
*/
public class FileReaderFlush {
@Test
public void Test01() throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("file\\fw.txt");
// 写出数据,通过flush
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('关'); // 写出第1个字符
fw.close();
fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
fw.close();
}
}
如果我们读取或写出的数据是非文本文件,则Reader、Writer就无能为力了,必须使用字节流。
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
说明:close()方法,当完成流的操作时,必须调用此方法,释放系统资源。
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
说明:close()方法,当完成流的操作时,必须调用此方法,释放系统资源。
java.io.FileInputStream
类是文件输入流,从文件中读取字节。
读取操作:
package com.suyv.test02;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 15:51
* @Description: FileInputStream--字节输入流的使用
*/
public class FileInputStream01 {
// 单个接收--无汉字
@Test
public void Test01() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file = new File("file\\hello.txt");
//2. 创建FileInputStream流对象
FileInputStream fis = new FileInputStream(file);
//3. 通过相关流的方法,读取文件中的数据
int i;
while ((i = fis.read()) != -1){
System.out.print((char) i); // helloworld111
}
//4. 关闭相关的流资源,避免出现内存泄漏
fis.close();
}
// 单个接收--有汉字utf8
@Test
public void Test02() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file = new File("file\\hello1.txt");
//2. 创建FileInputStream流对象
FileInputStream fis = new FileInputStream(file);
//3. 通过相关流的方法,读取文件中的数据
int i;
while ((i = fis.read()) != -1){
// 出现乱码,汉字在gbk中占2个字节,在utf8中占三个字节
System.out.print((char) i); // helloworld111??-??
}
//4. 关闭相关的流资源,避免出现内存泄漏
fis.close();
}
// 使用byte数组接收
@Test
public void Test03() throws IOException {
// 1. 2. 创建fileInputStream对象
FileInputStream fis = new FileInputStream("file\\hello.txt");
// 3. 读取数据
byte[] buffer = new byte[5];
int len;
while ((len = fis.read(buffer)) != -1){
String str = new String(buffer,0,len);
System.out.print(str + "\t"); // hello world 111
// 错误写法
// String str = new String(buffer);
// System.out.print(str + "\t"); // hello world 111ld
}
// 4. 关闭资源
fis.close();
}
// skip(long n) 跳过几个字节
@Test
public void Test04() throws IOException {
// 1. 2. 创建fileInputStream对象
FileInputStream fis = new FileInputStream("file\\hello.txt");
// 3. 读取数据
fis.skip(4);
System.out.println((char) fis.read()); // o
// 4. 关闭资源
fis.close();
}
}
java.io.FileOutputStream
类是文件输出流,用于将数据写出到文件。
举例:
package com.suyv.test02;
import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 16:14
* @Description: FileOutputStream
*/
public class FileOutputStream01 {
@Test
public void Test01() throws IOException {
// 1. 2. 创建FileOutputStream流对象
FileOutputStream fos = new FileOutputStream("file\\fos.txt");
// 3. 执行操作
fos.write(97);
fos.write(98);
fos.write(99);
System.out.println("写入成功");
/*当前fos.txt内容为:abc*/
// 4. 关闭资源
fos.close();
}
@Test
public void Test02() throws IOException {
// 1. 2. 创建FileOutputStream流对象
// 默认为不追加
FileOutputStream fos = new FileOutputStream("file\\fos.txt");
// 3. 执行操作
// 字符串转换为字节数组
byte[] b = "abcde".getBytes();
// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
fos.write(b,2,2);
/*当前fos.txt内容为:cd*/
// 4. 关闭资源
fos.close();
}
@Test
public void Test03() throws IOException {
// 1. 2. 创建FileOutputStream流对象
// 添加第二个参数为true时,为文件追加内容
FileOutputStream fos = new FileOutputStream("file\\fos.txt",true);
// 3. 执行操作
// 字符串转换为字节数组
byte[] b = "abcde".getBytes();
fos.write(b);
/*当前fos.txt内容为:cdabcde*/
// 4. 关闭资源
fos.close();
}
// 接收控制台输入的内容
@Test
public void Test04() throws IOException {
Scanner scan = new Scanner(System.in);
// 创建流对象
FileOutputStream fos = new FileOutputStream("file\\content.txt");
// 操作流
String str = scan.nextLine();
fos.write(str.getBytes());
/*文件内容为:中国*/
// 关闭资源
fos.close();
}
// 接收控制台输入的内容
@Test
public void Test05() throws IOException {
Scanner scan = new Scanner(System.in);
// 创建流对象
FileOutputStream fos = new FileOutputStream("file\\content.txt");
while (true) {
// 操作流
String str = scan.nextLine();
// 循环退出条件
if (str.equals("-1")){
break;
}
fos.write(str.getBytes());
fos.write('\n');
}
// 关闭资源
fos.close();
}
}
package com.suyv.test02;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 14:45
* @Description: 复制图片
*/
public class FileInputOutputStream {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
//2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中
//3. 通过相关流的方法,读取文件中的数据
//4. 关闭相关的流资源,避免出现内存泄漏
// 复制一份03.png文件,命名为03_copy.png
@Test
public void Test01() throws IOException {
//1. 创建File类的对象,对应着物理磁盘上的某个文件
File file1 = new File("file\\03.png");
File file2 = new File("file\\03_copy.png");
//2. 创建FileInputStream和FileOutputStream流对象
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//3. 通过相关流的方法,读取文件中的数据
byte[] buffer = new byte[1024]; //1kb
int len;//记录每次读入到buffer中字节的个数
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("复制成功");
//4. 关闭相关的流资源,避免出现内存泄漏
fos.close();
fis.close();
}
}
package com.suyv.test02;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-20 16:50
* @Description: 图片的加密与加密
*/
public class FileInputOutputStream02 {
// 图片的加密操作
@Test
public void Test01() throws IOException {
//1. 创建File类的对象
File file1 = new File("file\\girl.jpeg");
File file2 = new File("file\\girl_secret.jpeg");
//2. 创建FileInputStream流对象和FileOutputStream流对象
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//3. 通过相关流的方法,读取文件中的数据
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5);
}
fos.write(buffer,0, len);
}
System.out.println("加密成功");
//4. 关闭相关的流资源,避免出现内存泄漏
fos.close();
fis.close();
}
// 图片的解密操作
@Test
public void Test02() throws IOException {
//1. 创建File类的对象
File file1 = new File("file\\girl_secret.jpeg");
File file2 = new File("file\\girl_unsecret.jpeg");
//2. 创建FileInputStream流对象和FileOutputStream流对象
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//3. 通过相关流的方法,读取文件中的数据
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5);
}
fos.write(buffer,0, len);
}
System.out.println("解密成功");
//4. 关闭相关的流资源,避免出现内存泄漏
fos.close();
fis.close();
}
}