IO流概述
字节流
文件复制
字符流
IDK9新特性
Properties类
转换流
序列化和反序列化
打印流
IO流概述
输入输出流顶级父类
字节流
- 一切皆为字节:一切数据都是以二进制行式保存
FileOutputStream类
- 注意:GBK中二个字节是一个中文,UTF-8中三个字节是一个中文
- 向文件中写入一个字节图解
- 构造方法作用:
- 会根据构造方法中传递的文件路径,创建空的文件
- 会把FileOutputStream对象指向创建好的文件
- 写入数据的原理(内存-》硬盘)
- Java程序-》jvm虚拟机-》OS(操作系统)-》OS调用写数据的方法-》把数据写入到文件中
向文件中写入一个字节
/**
* 向文件中写入一个字节
* public void write(int n);
*/
public static void show() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("a.txt");
/**
* 在文件中会显示a 用了记事本原理
* 写入97时会以二进制行式存储到硬盘,当记事本读取时会按照记事本原理显示
*/
fos.write(97);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
向文件中一次写入多个字节
/**
* public void write(byte[] bytes);
* 一次向文件中写入多个字节
* 如果写入的第一个字节是正数(0-127),那么现实的时候会查询ASCII码表
* 如果写入的第一个字节是负数那么第一个字节和第二个字节,俩个字节会组成一个中文显示,查询系统默认码表(GBK)
*/
public static void show2() {
byte[] bytes = {48, 49, 50}; //文件中显示 012
byte[] bytes1 = {-10, 3, -2, 5, 7};
FileOutputStream fos = null;
try {
fos = new FileOutputStream("b.txt");
//向文件中写入整个字节数组
fos.write(bytes);
//先文件中写入部分字节数组
fos.write(bytes, 0, 1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
向文件中写入字符串
/**
* 写入字符的方法:可以使用String类中方法将字符串转换为字节数组
*/
public static void show3() {
String s = "你好";
byte[] bytes = s.getBytes();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("b.txt");
//向文件中写入整个字节数组
fos.write(bytes);
//先文件中写入部分字节数组
fos.write(bytes, 0, 1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
向文件中续写数据
/**
* 追加写/续写
* FileOutputStream(String name, boolean append) 创建一个向指定名称的文件写入数据的文件输出流
* FileOutputStream(File file, boolean append) 创建一个向指定File对象文件中写入数据的文件输出流
* boolean append:追加写开关
* true:创建对象时不会覆盖原文件,继续在文件末尾追加数据
* false:创建一个新的 文件覆盖原文件
*
* 写换行:
* windows:\r\n
* linux:/n
* mac:/r
*/
public static void show() {
FileOutputStream fos = null;
String s = "你好";
try {
fos = new FileOutputStream("d.txt");
//在文件中写入10个换行的你好
for (int i = 0; i < 10; i++) {
fos.write(s.getBytes());
//写入换行符
fos.write("\r\n".getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次读取多个字节原理
FileInputStream类
- 从文件读出数据原理
- 构造方法作用
- 创建一个FileInputStream对象
- 会把FileInputStream对象指定构造方法中要读取的文件
- 读取数据的原理(硬盘-》内存)
- Java程序-》JVM-》OS->OS读取数据的方法-》读取文件
- 使用步骤
- 创建FileInputStream对象
- 使用read方法读取数据
- 关闭流
从文件中读取一个字节
/**
* 从文件中一个一个读取字节
*/
public static void show () {
FileInputStream fis = null;
try {
//1、创建对象
fis = new FileInputStream("a.txt");
// int len = fis.read(); //91
// System.out.println(len);
// len = fis.read(); //98
// System.out.println(len);
// len = fis.read();
// System.out.println(len);
//使用while循环读取
/**
* 这里注意必须要用一个变量来接受读取的数据否则会跳读
*/
int len = 0;
while ((len = fis.read()) != -1) {
System.out.println(len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
从文件中一次读取多个字节
/** int read(byte[] bytes)
* 将文件中数据读取到字节数组中,一次读取多个字节
* 参数:byte[]数组的作用,起到缓冲作用,存储每次读取的字节
* int len 每次读取字节的长度一般为1024字节
*/
public static void show2 () {
FileInputStream fis = null;
try {
fis = new FileInputStream("b.txt");
// byte[] bytes = new byte[2];
// int len = fis.read(bytes); //len代表每次读取字节的个数
// System.out.println(new String(bytes));
//循环输出读出的数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
//System.out.println(new String(bytes)); //此时会输出空格,因为字节数组长度为1024
System.out.println(new String(bytes, 0, len)); //使用此方法输出无空格
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件复制
文件复制原理
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo04FileCopy {
/**
* 文件复制原理:
* 从一个文件中读出,再写入另一个文件
*/
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
//从文件中读取
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fis.close();
fos.close();
}
}
字符流
使用字节流读取字节文件
- 读取一个中文
- GBK占2俩个字节
- UTF-8占3个字节
- 为了避免字节流当每次读取一个字节时会产生错误使用字符流
字符输出流
import java.io.FileWriter;
import java.io.IOException;
/**
* 字符输入流
* 构造方法:
* FileWriter(String name);
* FileWriter(File file);
* 作用:
* 创建一个FileWriter对象
* 根据构造方法的文件/文件路径,创建文件
* 将FileWriter对象指向创建好的文件
* 使用步骤:
* 创建FileWriter对象
* 调用write方法将数据写入到内存缓冲区(字符转换为字节的过程)
* 调用flush方法,将内存缓冲区中的数据,写入到文件中
* 释放资源(会先把内存缓冲区的数据刷新到文件中)
*
*/
public class Demo01FileWriter {
public static void main(String[] args) throws IOException {
FileWriter fr = new FileWriter("b.txt");
//将数据写入到内存缓冲区
fr.write(97);
//将数据从内存缓冲区刷新到文件中
fr.flush();
//关闭资源(此时会自动将数据刷新到文件中)
fr.close();
}
}
/**
* 写数据的其它方法:
* void write(char[] buf) ; 写入字符数组
* void write(char ch); //写入字符
* void write(char[] buf, int off, int len); 写入部分字符数组
* void write(String string); 写入字符串
*/
public class Demo03WriteMethod {
public static void main(String[] args) throws IOException {
char[] chars = {'a', 'b', 'c', 'd'};
FileWriter fr = new FileWriter("a.txt");
//写入一个字符到缓冲区
fr.write(97);
//写入字符数组到缓冲区
fr.write(chars);
//写入字符数组部分到缓冲区
fr.write(chars, 0, 2);
//写入字符串到缓冲区
fr.write("传智播客");
//写入字符串部分到缓冲区
fr.write("程序员",0 ,3);
//刷新数据到文件中
fr.flush();
fr.close();
}
}
续写和换行
/**
* 续写和换行
* FileWriter(String name, boolean append) 创建一个向指定名称的文件写入数据的文件输出流
* FileOWriter(File file, boolean append) 创建一个向指定File对象文件中写入数据的文件输出流
* 换行:
* windows:\r\n
* linux:/n
* mac:/r
*/
public class Demo04WriteMethod {
}
字符输出流和字节输出流最大区别
- 字节输出流将数据写入到文件中
- 字符输出流将文件写入到缓冲区
close方法和flush方法区别
/**
* close方法和flush方法区别:
* close:先刷新缓冲区,然后再通知系统释放资源,该对象不能再被使用了
* flush:刷新缓冲区,该对象可以继续被使用
*/
JDK7新特性
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* JDK7新特性
* 再try后面可加一个(),在括号里定义流对象
* 那么这个流对象的作用域就在try中有效
* try代码执行完毕,会自动将流对象释放,不用再写finally
* 格式:
* try(定义流对象;定义流对象......) {
* 可能会抛出异常的代码
* } catch(异常类变量 变量名) {
* 异常的处理逻辑
* }
*/
public class Demo05JDK {
public static void main(String[] args) {
try (
FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
FileOutputStream fos = new FileOutputStream("D:\\b.jpg");) {
//从文件中读取
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK9新特性
/**
* jdk9新特性
* 在try前面可以定义流对象
* 在try后面的括号中可以直接引入流对象的名称(变量名)
* 在try代码执行完毕,也可以直接释放掉,不用再写finally
* 格式:
* A a = new A();
* B b = new B();
* try(a; b) {
* * 可能会抛出异常的代码
* * } catch(异常类变量 变量名) {
* * 异常的处理逻辑
* * }
*/ // 一般使用jdk7新特性,因为jdk9还要抛出异常
public class Demo06JDK {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
try (fis; fos) {
//从文件中读取
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
区别
- 一般使用jdk7新特性,因为jdk9还要抛出异常
Properties类
/**
* Properties 类
* extends Hashtable<Object,Object>Properties 类表示了一个持久的属性集,
* Properties 可保存在流中或从流中加载
* Properties集合是唯一一个与IO流相结合的集合
* 可用Properties集合中的store方法,将集合中的临时数据,持久写入到磁盘中存储
* 可用Properties集合中的load方法,把硬盘中的文件(键值对),读入到集合中
* 属性列表中每个键和值对应的都是一个字符串
* Properties集合是一个双列集合,默认key和value都是字符串
*/
将磁盘文件数据读取存储到集合中
/***
* 使用Properties集合中的load方法,把硬盘中保存的文件(键值对),读取到集合中
* void load(Reader reader)
* 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
* void load(InputStream inStream)
* 从输入流中读取属性列表(键和元素对)。
* 参数:
* OutputStream out 字节输入流,不能写中文
* Writer writer 字符输入流,可以写中文
* 使用步骤:
* 创建Properties集合对象
* 调用load方法读取保存键值对的文件数据到集合中
* 遍历集合
* 注意:
* 存储键值对的文件中,键与值默认的连接符号可以使用
* 存储键值对的文件中,可以使用#作为注释,被注释的键值对不再被读取
* 存储键值对的文件中,键与值默认都是字符串,不用再加引号
*/
private static void show03() throws IOException {
//创建集合对象
Properties prop = new Properties();
//将文件中数据读取到集合中保存
prop.load(new FileReader("a.txt"));
//遍历集合
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key + "=" + value);
}
}
将集合中数据存储到文件中
/**
* 使用Properties集合中的store方法,可将集合中的临时数据,持续化写入到磁盘中存储
* void store(OutputStream out, String comments);
* void store(Writer writer, String comments);
* 参数:
* OutputStream out 字节输入流,不能写中文
* Writer writer 字符输入流,可以写中文
* String comments 注释,用来解释说明保存的文件是做什么用的
* 不能使用中文,会产生乱码,一般默认是UNICODE编码
* 一般不使用空字符串
* 使用步骤:
* 创建Properties集合对象,添加数据
* 创建字节输出流/字符输出流对象,构造方法中要绑定的输出的目的地
* 使用Properties集合中的store方法,把集合中的临时数据,持久化存储到磁盘中
* 释放资源
*/
private static void show02() {
//1、创建集合对象
Properties prop = new Properties();
//向集合中添加数据
prop.setProperty("马龙", "175");
prop.setProperty("张继科", "180");
prop.setProperty("樊振东", "170");
//2、创建字符输入流对象
FileWriter fr = null;
try {
fr = new FileWriter("a.txt");
//3、将数据存储到文件中
prop.store(fr, "save data");
} catch (IOException e) {
e.printStackTrace();
}
//4、释放资源
prop.clone();
}
字节缓冲输入流
- 给基本的字节输入流增加一个缓冲区(数组)提高基本输入流的缓冲效率,字符缓冲输入流也是如此
/**
* java.io.BufferedInputStream extends InputStream
* 继承自父类的成员方法
* abstract int read()
* 从输入流中读取数据的下一个字节。
* int read(byte[] b)
* 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
* int read(byte[] b, int off, int len)
* 将输入流中最多 len 个数据字节读入 byte 数组。
* void close()
* 关闭此输入流并释放与该流关联的所有系统资源。
* 构造方法:
* BufferedInputStream(InputStream in) 创建一个BufferedInputStream并保存其参数,即输入流 in,以便蒋来使用
* BufferedInputStream(InputStream in, int size) 创建指定缓冲区大小 BufferedInputStream 并保存其参数,即输入流
* 参数:
* 可以传递一个FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream
* size:指定缓冲流大小,不指定默认
* 使用步骤:
* 创建BufferedInputStream对象
* * 创建BufferedInputStream对象
* * 调用BufferedInputStream对象的read()方法
* * 释放资源
* 注意:当关闭资源时只需要关闭缓冲流资源就可以
*/
public class Demo02BufferedInputStream {
}
字节缓冲输出流
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* java.io.BufferedOutputStream extends OutputStream
* 继承父类的共享成员方法:
* void close()
* 关闭此输出流并释放与此流有关的所有系统资源。
* void flush()
* 刷新此输出流并强制写出所有缓冲的输出字节。
* void write(byte[] b)
* 将 b.length 个字节从指定的 byte 数组写入此输出流。
* void write(byte[] b, int off, int len)
* 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
* abstract void write(int b)
* 将指定的字节写入此输出流。
* 构造方法:
* BufferedOutputStream(OutputStream out)
* 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
* BufferedOutputStream(OutputStream out, int size)
* 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
* 参数:
* 可以传递一个FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream
* size:指定缓冲流大小,不指定默认
* 使用步骤:
* 创建FileOutputStream对象
* 创建BufferedOutputStream对象
* 调用BufferedOutputStream对象的write()方法,把数据写入到缓冲区
* 调用BufferedOutputStream对象的flush方法把内部缓冲区的数据,刷新到文件中
* 释放资源
*/
public class Demo01BufferedOutputStream {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("把数据写入到内存缓冲区".getBytes());
//将内存缓冲区数据刷新到文件中
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符缓冲输入流
/**
* java.io.BufferedReader extends Reader
* int read()
* 读取单个字符。
* int read(char[] cbuf, int off, int len)
* 将字符读入数组的某一部分。
* void close()
* 关闭该流并释放与之关联的所有资源。
* 构造方法:
* BufferedReader(Reader in)
* 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
* BufferedReader(Reader in, int sz)
* 创建一个使用指定大小输入缓冲区的缓冲字符输入流。
* 参数:
* 传递FileReader,给它增加一个缓冲区,提高FileReader的读取效率
* 特有的成员方法:
* String readLine()
* 读取一个文本行。
* 返回值:包含该行内容的字符串,不包含任何终止符,如果已到达流末尾,则返回null
*/
public class Demo04BufferedReader {
}
字符缓冲输出流
/**
* java.io.BufferedWriter extends Writer
*
*/
/**
* * 继承父类的共享成员方法:
* * void close()
* * 关闭此输出流并释放与此流有关的所有系统资源。
* * void flush()
* * 刷新此输出流并强制写出所有缓冲的输出字节。
* * void write(byte[] b)
* * 将 b.length 个字节从指定的 byte 数组写入此输出流。
* * void write(byte[] b, int off, int len)
* * 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
* * abstract void write(int b)
* * 将指定的字节写入此输出流。
* 构造方法:
* BufferedWriter(Writer out)
* 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
* BufferedWriter(Writer out, int sz)
* 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
* 参数:
* 传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高写入效率
* sz:指定缓冲区的大小,不写则默认大小
* 特有的成员方法:
* void newLine()
*/
public class Demo03BufferedWriter {
}
练习
import java.io.*;
import java.util.HashMap;
/**
* 练习:
* 对文本内容进行排序
* 按照1,2,3进行排序
* 分析
* 创建一个HashMap集合,将key存放每行的序号1,2,3,value存放文本内容
*/
public class Demo05Text {
public static void main(String[] args) throws IOException {
//创建HashMap集合存放键值对
HashMap<String, String> map = new HashMap<>();
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
//1、创建FileReader对象
FileReader fr = new FileReader("in.txt");
//2、创建BufferedReader对象
BufferedReader br = new BufferedReader(fr);
//3、以每行读取文本内容
String line = null;
while ((line = br.readLine()) != null) {
//3、以.作为分隔符分割
String[] arr = line.split("\\.");
//将内容写入map集合中(key序号是有序的,会自动排序)
map.put(arr[0], arr[1]);
}
//4、遍历集合将内容写入文本中
for (String key : map.keySet()) {
String value = map.get(key);
line = key + "." + value;
bw.write(line);
bw.newLine();
}
//释放资源
bw.close();
br.close();
}
}
转换流
/**
* 编码和解码
* idea默认使用UTF-8类型编码,
* FileReader默认只能读取UTF-8类型编码
*/
public class Demo06 {
}
字符编码与字符集
- 按照某种规则,将字符存储到计算机称为编码
- 将存储在计算机中的二进制数按照某种规则解析出来称为解码
- 编码:字符->字节
- 解码:字节->字符
- 注意:编码和解码必须按照同一对应规则
- 当指定了编码,字符集就自然指定了,所以编码才是最终关心的
- 常用的编码及编码集
字符转换流
- 字符输入转换流
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/**
* java.io.OutputStreamWriter extends Writer
* OutputStreamWriter 是字符流流向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节
*
* 继承父类的共性成员方法:
* * * void close()
* * * 关闭此输出流并释放与此流有关的所有系统资源。
* * * void flush()
* * * 刷新此输出流并强制写出所有缓冲的输出字节。
* * * void write(byte[] b)
* * * 将 b.length 个字节从指定的 byte 数组写入此输出流。
* * * void write(byte[] b, int off, int len)
* * * 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
* * * abstract void write(int b)
* * * 将指定的字节写入此输出流。
* 构造方法:
* OutputStreamWriter(OutputStream out)
* 创建使用默认字符编码的 OutputStreamWriter。
* OutputStreamWriter(OutputStream out, String charsetName)
* 创建使用指定字符集的 OutputStreamWriter。
* 参数:
* OutputStream out:字节输出流,可以用来转换之后的字节到文件中
* String charsetName:指定编码表的名称,不区分大小写,不指定默认是哟个UTF-8
* 使用步骤:
* 1、创建OutputStreamWriter对象,构造方法中指定字节输出流和编码表
* 2、调用OutputStreamWriter对象的write()方法,把字符转换为字节存储在缓冲区
* 3、调用OutputStreamWriter对象的flush()方法,把缓冲区数据刷新到文件中
* 4、释放资源
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
write_utf_8();
}
/**
* 使用转换流OutputStreamWriter写UTF-8文件
*/
public static void write_utf_8() throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
//OutputStreamWriter osw = new OutputStreamWriter(fos); //默认UTF-8编码
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
osw.write("你好");
osw.flush();
osw.close();
}
}
- 字符输出转换流
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* java.io.InputStreamReader extends Reader
* 继承父类共有的成员方法
* int read()
* 读取单个字符。
* int read(char[] cbuf, int offset, int length)
* 将字符读入数组中的某一部分。
* 构造方法:
* InputStreamReader(InputStream in)
* 创建一个使用默认字符集的 InputStreamReader。
* InputStreamReader(InputStream in, String charsetName)
* 创建使用指定字符集的 InputStreamReader。
* 参数:
* InputStream in:字节输入流,读取文件中保存的字节
* String charsetName:指定编码表的名称,不区分大小写,不指定默认是哟个UTF-8
* 使用步骤:
* 1、创建InputStreamReader对象,构造方法中指定字节输出流和编码表
* * 2、调用InputStreamReader对象的read()方法,把字符转换为字节存储在缓冲区
* * 4、释放资源
* ` 注意事项:
* 构造方法中的编码表要和文件的编码相同,否则会发生编码乱码现象
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
read_utf_8();
}
public static void read_utf_8() throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
int len = 0;
while ((len = isr.read()) != -1) {
System.out.println((char) len); //这里注意要转换为char类型,否则输出的是一个汉字的码值
}
isr.close();
}
}
转换文件编码
/**
* 练习:转换文件编码
* 将GBK文件转换为UTF-8文件类型
* 思路:
* 先将GBK格式文件读取出来,然后再哟个UTF-8文件写进去
*/
public class Demo02Test {
public static void main(String[] args) throws IOException {
gbkToutf_8();
}
public static void gbkToutf_8() throws IOException {
//创建InputStreamReader对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\b.txt"), "UTF-8");
//创建OutputStreamWriter对象
OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("b.txt"), "UTF-8");
//读取GBK文件并以UTF-8行式写进去
int len = 0;
while ((len = isr.read()) != -1) {
osr.write(len);
}
isr.close();
osr.close();
}
}
序列化和反序列化
序列化
- 把对象以流的形式写入到文件中保存,叫做写对象,也叫对象的序列化
import java.io.Serializable;
/**
* 序列化和反序列化都会抛出 NotSerializableException 没有序列化异常
* 类通过实现 Serializable 接口以启用其序列化功能,来实现此接口的类将无法使用任何序列化或反序列化
* Serializable类型接口也称为标记类型接口
* 要进行序列化和反序列化的类必须实现 Serializable 接口,就会给类添加一个标记
* 当我们进行序列化和反序列化的时候,就会检测类上是否有这个异常
* 有:可以序列化和反序列化
* 没有:则抛出 异常
* 去市场买肉-》肉上有一个蓝色章(检测合格)-》放心购买-》买回来随意吃
*/
public class Person implements Serializable {
//定义一个序列号,当执行反序列化操作时,Person类中name和age的值,而反序列化操作输出的还是原值
private static final long serialVersionUID = 1L;
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* java.io.ObjectOutputStream extends OutputStream
* ObjectOutputStream 对象的序列化流
* 作用:把对象以流的形式写入到文件中保存
* 构造方法:
* ObjectOutputStream(OutputStream out)
* 创建写入指定 OutputStream 的 ObjectOutputStream。
* 参数:
* OutputStream out:字节输出流
* 特有的成员方法:
* writeObject(Object obj)
* 将指定的对象写入 ObjectOutputStream。
*
* 序列化前提:
* 类必须实现Serializable接口
* 必须存在类对象的class文件
*
*/
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
//创建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(new Person("好还有", 18));
oos.close();
}
}
反序列化
- 把文件中保存的对象,以流的方式读取出来,也叫做对象的反序列化
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* java.io.ObjectInputStream extends InputStream
* ObjectInputStream 对象的反序列化流
* 作用:
* 把文件中保存的对象,以流的方式读取出来使用
* 构造方法:
* ObjectInputStream(InputStream in)
* 创建从指定 InputStream 读取的 ObjectInputStream。
* 特有的成员方法:
* Object readObject()
* 从 ObjectInputStream 读取对象。
*
* static:静态关键字
* 静态优先于非静态加载到内存中(静态优先于对象加载到内存中)
* 被static修饰的成员变量不能被序列化,序列化的都是对象
* transient:瞬态关键字
* 被transient修饰的成员变量不能被序列化
*
* 若age被static则age一直为0
*
*/
public class Demo02ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
//从中读取一个对象
Object o = ois.readObject();
//释放资源
ois.close();
//打印对象
System.out.println(o);
if (o instanceof Person) {
Person person = (Person)o;
System.out.println(person);
}
}
}
序列化冲突异常
序列化集合
import java.io.*;
import java.util.ArrayList;
/**
* 序列化集合:
* 当我们要在一个文件中保存多个对象
* 可以把多个对象保存到一个集合中
* 对集合进行序列化和反序列化
* 分析:
* 1、定义一个存储Person对象的ArrayList的集合
* 2、再集合中存储Person对象
* 3、创建一个序列化流ObjectOutputStream对象
* 4、调用writeObject()方法,对集合进行序列化
* 5、创建一个反序列化ObjectInputStream集合
* 6、调用readObject()方法将读取到的对象保存到集合中
* 7、把Object类型集合转换为ArrayList类型
* 8、遍历集合
* 9、释放资源
*/
public class Demo03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建集合
ArrayList<Person> list = new ArrayList<>();
//向集合中添加对象
list.add(new Person("好还有", 18));
list.add(new Person("打包", 80));
list.add(new Person("小狗", 90));
//创建要对象写的目的地
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c.txt"));
//对集合进行序列化操作
oos.writeObject(list);
//创建一个反序列化操作对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c.txt"));
//读取对象集合
Object o = ois.readObject();
//转换集合类型
ArrayList<Person> list1 = (ArrayList<Person>)o;
//遍历集合
for (Person person : list1) {
System.out.println(person);
}
//释放资源
oos.close();
ois.close();
}
}
打印流
import java.io.FileNotFoundException;
import java.io.PrintStream;
/**
* java.io.PrintStream
* PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
* 特点:
* 与其他输出流不同,PrintStream 永远不会抛出 IOException;
* 只负责数据的输出,不负责数据的读取
* 特有的成员方法:
* void print(任意类型数据)
* void println(任意类型数据并换行)
* 构造方法:
* PrintStream(File file)
* 创建具有指定文件且不带自动行刷新的新打印流。
* PrintStream(OutputStream out)
* 创建新的打印流。
* PrintStream(String fileName)
* 创建具有指定文件名称且不带自动行刷新的新打印流。
* PrintStream extends OutputStream
* 继承自父类的成员方法:
* * * * void close()
* * * * 关闭此输出流并释放与此流有关的所有系统资源。
* * * * void flush()
* * * * 刷新此输出流并强制写出所有缓冲的输出字节。
* * * * void write(byte[] b)
* * * * 将 b.length 个字节从指定的 byte 数组写入此输出流。
* * * * void write(byte[] b, int off, int len)
* * * * 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
* * * * abstract void write(int b)
* * * * 将指定的字节写入此输出流。
*
* 注意事项:
* 如果使用继承自父类的成员方法write()方法写数据,那么查看数据的时候会查询编码表:a->97
* 如果使用自己特有的成员方法print,println方法写数据,写的数据是原样
*/
public class Demo01PrintStream {
public static void main(String[] args) throws FileNotFoundException {
PrintStream pr = new PrintStream("d.txt");
//调用父类的方法写入数据
pr.write(97);
//调用特有的成员方法写入数据
pr.println(97);
pr.close();
}
}
设置指定目的地的打印流
import java.io.FileNotFoundException;
import java.io.PrintStream;
/**
* 可以改变输出语句的目的地(打印流语句)
* 输出语句,默认在控制台输出
* 使用System.setOut()方法改变输出语句的目的地改为参数中传递打印流的目的地
* static void setOut(PrintStream out)
* 重新分配标准输出流
*/
public class Demo02PrintStream {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("我在控制台输出");
//设置打印流目的地
PrintStream ps = new PrintStream("e.txt");
//把输出语句中目的地改变为打印流的目的地
System.setOut(ps);
System.out.println("我在打印流目的地中输出");
}
}