文章目录
1.概述
输入流:读操作
输入流(InputStream及其子类)用于从外部源(如文件、网络等)读取数据到程序中,即数据流向是“进”的,被称为读操作。
输出流:写操作
输出流(OutputStream及其子类)的主要目的是将数据(如文本、字节等)从内存(或程序内部)传输到外部设备或存储介质上。这个过程本质上是将数据写出到某个目标位置,即数据流向是“出”的,被称为写操作。
2.File类
package com.stream;
import java.io.File;
public class Test {
public static void main(String[] args) {
//第一种创建file对象
//File file = new File("d:\\java\\stream\\test.txt");
//第二种创建file对象
//File file = new File("d:\\java","stream\\test.txt");
//第三种创建file对象
File file0 = new File("d:\\java");
File file = new File(file0,"stream\\test.txt");
//判断是否是文件
System.out.println(file.isFile());
//判断是否是目录
System.out.println(file.isDirectory());
System.out.println("---------------------------");
//创建目录
File file2 = new File("d:\\java","set");
//如果不存在set目录
if(!file2.exists()){
//则创建set目录
file2.mkdir();
}
//创建多级目录
File file3 = new File("d:\\java\\one\\two");
if(!file3.exists()){
//mkdirs方法创建多级目录
file3.mkdirs();
}
//创建文件
File file4 = new File("d:\\java\\one\\two\\test.txt");
if(!file4.exists()){
try {
file4.createNewFile();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.绝对路径和相对路径
- 绝对路径:是从盘符开始的路径
- 相对路径:是从当前路径开始的路径
package com.stream;
import java.io.File;
import java.io.IOException;
public class Test2 {
public static void main(String[] args) {
File file = new File("set\\test.txt");
if (!file.exists()) {
try {
file.createNewFile();
}catch (IOException e) {
e.printStackTrace();
}
}
//判断是否是绝对路径
System.out.println(file.isAbsolute());
//获取相对路径
System.out.println(file.getPath());
//获取绝对路径
System.out.println(file.getAbsolutePath());
//获取文件名
System.out.println(file.getName());
}
}
4.字节流
- 字节输入流InputStream
- 字节输出流OutputStream
- 适合二进制数据相关的操作,不太适合处理中文相关文本数据。
字节输入流:
字节输出流:
5.FileInputStream(字节文件输入流)
- 从文件系统中的某个文件中获得输入字节(读取文件中的内容到内存或程序中)
- 用于读取诸如图像数据之类的原始字节流
FileInputStream方法
例1:
package com.imooc.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
try {
//创建一个FileInputStream对象(文件输入流)
FileInputStream fis = new FileInputStream("set\\test.txt");
int i = fis.read();
while (i != -1) { //没有到达文件内容末尾
System.out.print((char) i);
i = fis.read();//再接着读取
}
fis.close();//关闭输入流
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
}
例2:
package com.imooc.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo2 {
public static void main(String[] args) {
try {
//创建一个FileInputStream对象(文件输入流)
FileInputStream fis = new FileInputStream("set\\test.txt");
byte[] b = new byte[50];//生成一个长度50的字节数组
fis.read(b);//把数据读到byte类型的数组中
System.out.println(new String(b));
fis.close();//关闭输入流
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
}
6.FileOutputStream(字节文件输出流)
例:
package com.imooc.stream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
try {
//创建一个字节文件输出流对象
FileOutputStream fos = new FileOutputStream("set\\test.txt",true);//true:表示往之前的内容后面追加,否则就覆盖
fos.write(50);
fos.write('a');
fos.write('b');
fos.close();//关闭输出流
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
7.字符流
- 字符输入流Reader
- 字符输出流Writer
- 适合操作中文相关的文本数据
Reader:
Writer:
8.字节字符转换流
- InputStreamReader :将字节输入流转换为字符输入流,用于读取文本数据
- OutputStreamWriter:将字节输出流转换为字符输出流,用于向文件写数据
InputStreamReader :
package com.imooc.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderDemo {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("set\\a.txt");
InputStreamReader isr = new InputStreamReader(fis);//流的连接
//读取数据
int n=0;
while ((n=isr.read())!=-1){
System.out.print((char) n);//这样中文读出来就没有乱码问题
}
fis.close();
isr.close();
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
OutputStreamWriter:
package com.imooc.stream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
public static void main(String[] args) {
try {
//创建一个字节输出流
FileOutputStream fos = new FileOutputStream("set\\b.txt");
//使用 OutputStreamWriter 包装 FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("你好世界!abc");//
/*
流关闭顺序:
当使用 OutputStreamWriter 包装 FileOutputStream 时,
只需要关闭最外层的包装流(在这个例子中是 OutputStreamWriter),
因为关闭包装流也会关闭它所包装的所有底层流。
然而,显式关闭两者通常不会导致错误,但这不是必要的,
并且如果底层流(FileOutputStream)在包装流(OutputStreamWriter)之前被关闭,
则可能会引发异常。但最好是只关闭 osw。
*/
osw.close();//
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
9.BufferedReader
BufferedReader 是 Java 中用于读取文本的一个类,它包装了其他字符输入流,如 FileReader,提供了缓冲字符输入以及按行读取文本的功能。BufferedReader 提高了读取效率,因为它内部使用了一个字符缓冲区来存储从源读取的字符,从而减少了实际读取操作的次数。
使用 BufferedReader 读取文件时,你通常会按照以下步骤进行:
- 创建 FileReader:首先,你需要创建一个 FileReader 对象,该对象将作为 BufferedReader 的源。FileReader 是用于读取字符文件的便利类。
- 包装 BufferedReader:然后,使用 FileReader 对象作为参数来创建 BufferedReader 对象。
- 读取数据:通过 BufferedReader 提供的 readLine() 方法,你可以按行读取文本。该方法会读取包含行终止符(如换行符)的字符序列,直到但不包括下一个行终止符,然后将这些字符作为字符串返回。如果已到达流的末尾,则返回 null。
- 关闭流:最后,完成读取后,你应该关闭 BufferedReader 和它包装的 FileReader 以释放与之关联的系统资源。由于 BufferedReader 封装了 FileReader,所以只需要关闭 BufferedReader 即可,它会负责关闭底层的 FileReader。
例:
package com.imooc.stream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileExample {
public static void main(String[] args) {
try {
FileReader fileReader = new FileReader("set\\b.txt");
BufferedReader br = new BufferedReader(fileReader);
String line;
while ((line= br.readLine())!=null){
System.out.println(line);
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
10.对象的序列化和反序列化
步骤:
- 创建一个类,实现Serializable接口
- 创建对象
- 将对象写入文件
- 从文件读取对象信息
对象的序列化涉及到两个类
- 对象输入流ObjectInputStream
- 对象输出流ObjectOutputStream
序列化:把Java对象转换为字节序列的过程
反序列化:把字节序列恢复为Java对象的过程
例:
Goods类实现Serializable接口
package com.imooc.stream;
import java.io.Serializable;
public class Goods implements Serializable {
private int id;
private String name;
private double price;
public Goods(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
测试:
package com.imooc.stream;
import java.io.*;
public class GoodsTest {
public static void main(String[] args) {
//创建Goods类对象
Goods goods1 = new Goods(1, "电脑", 50);
//先把对象写入文件
try (
//try-with-resources 语句来自动管理资源,即使在发生异常时也能正确关闭资源
//1.定义一个文件输出流
FileOutputStream fileOutputStream = new FileOutputStream("set/goods.txt");
//2.定义一个对象输出流,并将文件输出流连接到对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//3.使用文件输入流进行对象读取
FileInputStream fileInputStream = new FileInputStream("set/goods.txt");
//对象输入流连接到文件输入流
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
) {
//3.goods1对象存到文件中
objectOutputStream.writeObject(goods1);
//4.读取对象并输出
System.out.println(objectInputStream.readObject());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
11.try-with-resources 语句
try-with-resources 语句特性:
- try-with-resources 语句是 Java 7引入的一个特性,它用于自动管理资源,确保每个资源在语句结束时都能被正确关闭。这主要适用于实现了java.lang.AutoCloseable 接口(或继承自 java.io.Closeable 接口,因为 Closeable继承自 AutoCloseable)的资源,如文件流、数据库连接等。
- 使用 try-with-resources 语句时,你可以将一个或多个资源放在 try 语句的括号 () 中,这些资源在 try 代码块执行前被初始化,并在 try 代码块执行完毕后(无论是否发生异常)自动关闭。
使用传统的 try-finally 手动资源关闭存在的问题:
- 容易忘记关闭资源,从而引发内存泄漏
- 资源比较多的时候,代码嵌套层次较深,代码可读性不佳
- try 块与 finally 块同时发生异常时,存在异常压制问题