一、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;//遍历完了会返回-1while ((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();}
}
```javaFileOutputStream 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写入对象。
- 编辑商品管理类;
