一、IO流概述
1.1 流的简介
- IO Input Output
- 通过IO可以完成硬盘文件的读和写
- 往内存中去,叫做输入(Input)。或者叫做读(Read)
- 从内存中出来,叫做输出(Output)。或者叫做写(Write)
二、流的分类
2.1 字符流和字节流
- 字符流(读取普通文本,读不了音频、视频、图片)
- 字节流(读取任意文件类型file)
- byte字节表示计量单位,我们可以设置流对象一次性可以读取多少个字节
- 字节流读取数据的方式是读取字符对应的asclI码值,每一个字符都有对应的ascll;
如:一个文件中有字符串’ABCDEFG’ 字符流按照一个字符一个字符的读取; 字节流是一次性读取一个字节,但是读取的是每个字符对应的ascll码
- 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。
- 按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的。
2.2 输入流和输出流
定义
文件 <—> 内存
输入流 :就是将文件中的数据读取到内存中
输出流: 将内存中的数据写到文件中按操作分类:
- 字节输入流
- 字节输出流
- 字符输入流
- 字符输出流
- 以stream结尾的就是字节流,以reader/writer结尾的就是字符流
- java.io.InputStream字节输入流
- java.io.OutputStream字节输出流
- java.io. Reader字符输入流
- java.io. Writer字符输出流
- 所有的流都实现了java.io.Closeable接口
- 都是可关闭的,都有close()方法。
- 所有的输出流都实现了java.io. Flushable接口,都是可刷新的,都有flush()方法。防止写入管道存在残留数据。
- 文件专属流
- java.io.FileInputStream
- java.io. FileOutputStream
- java.io. FileReader
- java.io. FileWriter
三、文件流读写操作
```java FileInputStream fileInputStream = null;
//创建流对象 try {
fileInputStream = new FileInputStream("D:\\temp\\IOTest01.java");
//创建一个字节数组 一次性可以读取多个字节
//存储数据采取覆盖机制。
byte[] bytes = new byte[500];
//read用来存储读取到的字节数;
int read = 0;
//遍历完了会返回-1
while ((read = fileInputStream.read(bytes)) != -1){
//将字节数组中的ascll转成字符串
//参数:数组,起始位置,转换个数;
String str = new String(bytes,0, read);
System.out.print(str);
}
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
} finally {
//关闭流对象
try {
fileInputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
```java
FileOutputStream fileOutputStream = null;
//创建流对象
try {
fileOutputStream = new FileOutputStream("D:\\temp\\aaa.txt");
//写数据到文件中
fileOutputStream.write(65);
//创建一个字节数组
byte[] bytes = {66,67,68,69,70,71};
fileOutputStream.write(bytes);
//将字符串写入文件中
String str = "\nhello world";
//将字符串转成字节数组
byte[] strBytes = str.getBytes();
fileOutputStream.write(strBytes,0,3);
//刷新
fileOutputStream.flush();
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
} finally {
//关闭流对象
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
案例,拷贝文件
package com.eaglslab.copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopyUtils {
private static FileInputStream fileInputStream = null;
private static FileOutputStream fileOutputStream= null;
private FileCopyUtils(){
}
/**
*
* @param inputPath 输入路径
* @param outputPath 输出路径
*/
public static void FileCopy(String inputPath,String outputPath){
try {
//输入对象
fileInputStream = new FileInputStream(inputPath);
//输出对象
fileOutputStream = new FileOutputStream(outputPath);
int read = 0;
//创建字节数组
byte[] bytes = new byte[1024 * 1024];
while ((read = fileInputStream.read(bytes)) != -1){
//一边读一边写,读取到多少个就写多少个
fileOutputStream.write(bytes,0,read);
}
//刷新
fileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
//关闭流
if (fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
四、文件缓冲流操作BufferedReader
关于缓存流的使用:自带缓存区的流,在一次性读取数据的时候,可以不用创建数组来进行操作
可以通过缓冲流来提升效率,不必创建字符数组和字节数组;
public static void main(String[] args) throws Exception {
//缓存流对象 缓冲流(字节流转字符流)
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\temp\\IOTest01.java"));
String readLine = null;
while ((readLine = bufferedReader.readLine()) != null){
System.out.println(readLine);
}
//关闭流
bufferedReader.close();
}
五、数据流使用DataOutputStream
数据流的使用:会将数据按照特定的数据类型写入文件中,然后在将数据按照数据类型进行取出。
写入的文件是加密的,必须按写入顺序读取。
public static void main(String[] args) throws Exception {
//创建数据输出流对象,会新建一个data.txt文件
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("data.txt"));
boolean flag = true;
float f = 10f;
int i = 100;
double d = 3.14;
//写入数据
dataOutputStream.writeBoolean(flag);
dataOutputStream.writeFloat(f);
dataOutputStream.writeInt(i);
dataOutputStream.writeDouble(d);
//刷新
dataOutputStream.flush();
//关闭
dataOutputStream.close();
}
在进行数据读取时,我们根据我们写入的顺序进行读取,不然会导致数据错乱。
//创建数据输出流对象
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("data.txt"));
boolean aBoolean = dataInputStream.readBoolean();
float readFloat = dataInputStream.readFloat();
int i = dataInputStream.readInt();
double v = dataInputStream.readDouble();
System.out.println(aBoolean);
System.out.println(readFloat);
System.out.println(i);
System.out.println(v);
//关闭
dataInputStream.close();
六、标准输出流PrintStream
public static void main(String[] args) throws Exception {
//创建标准输出流对象
PrintStream printStream = new PrintStream(new FileOutputStream("write.txt"));
//设置输出路径
System.setOut(printStream);
//默认情况下输出路径是控制台,没有设置输出路径就会默认打印在控制台
System.out.println("hello java");
printStream.flush();
printStream.close();
}
案例 ;完成一个日志收集工具。
收集日志对应的事件和信息,通过标准输出流的方式写入文件内。<br />日期格式化对象:
//获取当前系统的时间
Date date = new Date();
//创建日期格式化对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat( pattern: "yyy-MM-dd hh :mm:ss");
//格式化日期
String dateTime = simpleDateFormat . format (date);
System. out. println(dateTime);
public static void logger(String message){
PrintStream printStream = null;
try {
//创建标准输出流对象 添加true就是开始追加,避免覆盖机制
printStream = new PrintStream(new FileOutputStream("logger.txt",true));
//设置输出路径
System.setOut(printStream);
//创建日期格式化对象
String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
System.out.println(dateTime+" : "+message);
//刷新
printStream.flush();
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}finally {
if (printStream != null){
printStream.close();
}
}
}
七、对象专属流ObjectOutputStream
- 对象专属流:专门用于操作对象,可以将javaa对象序列化到一个文件夹中,在通过序列化的方式取出来。
- 序列化
- 反序列化
反序列化取出文件中的java对象
public static void main(String[] args) throws Exception {
//创建序列化对象
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.txt"));
//创建用户对象
User user1 = new User("zs001", "q123456");
User user2 = new User("zs002", "a123456");
User user3 = new User("zs003", "s123456");
User user4 = new User("zs004", "d123456");
User user5 = new User("zs005", "f123456");
//创建集合对象
ArrayList<User> userArrayList = new ArrayList<>();
userArrayList.add(user1);
userArrayList.add(user2);
userArrayList.add(user3);
userArrayList.add(user4);
userArrayList.add(user5);
//将java对象写到文件中
//list已经继承了Serializable接口
objectOutputStream.writeObject(userArrayList);
//如果直接写入对象,自定义的对象需要先继承一个接口(Serializable)序列化接口
objectOutputStream.writeObject(user1);
}
- 序列化相关操作:
- 如果直接使用对象专属流写入对象,自定义的对象需要先继承一个接口(Serializable)序列化接口。
取消序列化操作,transient关键字 修饰的属性不再参与序列化。
private transient String name
只有序列化的数据才能通过反序列化操作取出。
- 对类继承接口后,进行序列化操作后,不能再修改该类的数据,会导致序列化版本号不同,导致报错。需要写死一个序列化版本号。
- 写死序列化版本号之后再添加属性数据,就不会出现版本号冲突。
操作如下 private static final long serialVersionUID = 版本号;
- 案例
描述: 购物车案例:完成对购物车商品的增删改查。将商品的数据通过序列化的方式放到文件中。
- 编辑商品类,并继承Serializable。
- 通过序列化读取 objectOutputStream.writeObject写入对象。
- 编辑商品管理类;