上面两篇博客主要总结了一下IO流的基础字节流和字符流,这篇总结一下几个特殊的封装流。
SequenceInputStream
序列流
序列流可以把多个字节输入流整合成一个, 从序列流中读取数据时,
将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.
将多个字节流整合成一个:
public class Demo01 {
public static void main(String[] args) throws Exception {
//SequenceInputStream序列流使用二
//需求,把a.txt b.txt c.txt 的内容拷贝到d.txt
//1.Vector是集合 区别于arrylist 它是线程安全的
Vector<InputStream> vector = new Vector<InputStream>();
vector.add(new FileInputStream("a.txt"));
vector.add(new FileInputStream("b.txt"));
vector.add(new FileInputStream("c.txt"));
//2.Enumeration枚举
Enumeration<InputStream> e = vector.elements();
//3.序列流
SequenceInputStream sis = new SequenceInputStream(e);
//4.创建输出流
FileOutputStream fos = new FileOutputStream("d.txt");
//读写
int b = 0;
while((b = sis.read()) != -1){
fos.write(b);
}
sis.close();
fos.close();
}
}
ByteArrayOutputStream
字节数组输出流
ByteArrayOutputStream 字节数组输出流
ByteArrayOutputStream 不需要关联文件 只是写入内存。
此类实现了一个输出流,其中的数据被写入一个 byte 数组 缓冲区。
缓冲区会随着数据的不断写入而自动增长。
可使用 toByteArray() 和 toString() 获取数据。
ByteArrayOutputStream的使用
//1.创建字节数组输出流对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//2.输入流
FileInputStream fis = new FileInputStream("a.txt");
//3.写入输出流
int b = 0;
while((b = fis.read()) != -1){
baos.write(b);
}
//自动把字节数组 转成 字符串
System.out.println(baos.toString());
System.out.println(baos.toString("UTF-8"));//指定编码格式的字符串
//获取文件数据
byte[] bytes = baos.toByteArray();
System.out.println(new String(bytes));
System.out.println(new String(bytes, "UTF-8"));//指定编码格式的字符串
//4.关流
fis.close();
对象操作流
1ObjectInputStream
这个类是从文件中读取对象
2 ObjectOutputStream
这个类是将一个对象写入文件
如果使用这个类写入对象,这个对象需要序列化
ps:
序列化就是让这个对象实现一个Serializable接口
如果没实现Serializable接口,会抛异常NotSerializableException
对象写入文件时,乱码没有关系,取出来正确就行了
序列化相关概念
归档(序列化) :将对象存在一个文件的过程
解归档(反序列化):把一个文件解析出对象
Serializable接口的ID讲解
1.要归档或者序列化的对象必须实现Serializable接口才能被序列化
2.Serializable 中有个id,但ID不是一定要加的
3.SerialVersionUid,简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
4.如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。
5.如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;
6.如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。
7.一般不会添加ID,就算添加了ID,版本号最好不要修改
ublic class 对象操作流 {
public static void main(String[] args) {
// 这里使用一下Vector
Vector<car> cars = new Vector<car>();
cars.add(new car("宝马", 1000));
cars.add(new car("奔驰", 100));
cars.add(new car("大众", 10000));
try (OutputStream outputStream = new FileOutputStream("a.data");
InputStream inputStream = new FileInputStream("a.data");
ObjectOutput objectOutput = new ObjectOutputStream(outputStream);
ObjectInput objectInput = new ObjectInputStream(inputStream);) {
objectOutput.writeObject(cars);
Vector<car> cars2 = (Vector<car>) objectInput.readObject();
//转成枚举
Enumeration<car> enumeration = cars.elements();
//遍历枚举
for(Enumeration e=enumeration;e.hasMoreElements();)
{
System.out.println(e.nextElement());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class car implements Serializable {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public car(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "car: [ name:" + name + " price:" + price + " ]";
}
}
打印流
PrintStream 打印字节流
System.out就是一个PrintStream, 其默认向控制台输出信息
该流可以很方便的将对象的toString()结果输出, 并且自动加上换行
PrintWriter 打印字符流
这个流是向文件打印信息,也就是将打印的内容写入文件
//1.打印的字节流【打印到控制台】
PrintStream ps = System.out;
ps.println("你好,元宵节快乐");//打印字符串
ps.println(19.6);
//2.打印的字符流
/**
* 1.PrintWriter调用打印方法,控制台是没有内容,它是把内容写到文件中
* 2.如果打印了内容,没有调用flush或者close,内容在文件中也不存在
*/
PrintWriter pw = new PrintWriter("test.txt");
pw.println("吃汤圆了...");
pw.print("超市一包汤圆10几块钱");
pw.print(13.01);
//pw.flush();
pw.close();
标准输入输出流
System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
随机访问流
RandomAccessFile类不属于流,是Object类的子类。
但它融合了InputStream和OutputStream的功能。
支持对随机访问文件的读取和写入。
/**
* 构造方法两个参数:
* name:文件名称、路径
* mode:模式 ,r=read 只读、 w=write
*/
//1.创建一个随机访问流对象,以读写的方式打开文件
RandomAccessFile raf = new RandomAccessFile("a.txt", "rw");
//2.读字符
/**
* 使用RandomAccessFile的readChar/readLine方法读文件有乱码问题
*/
/* System.out.println(raf.readChar());
System.out.println(raf.readChar());
System.out.println(raf.readChar());
System.out.println(raf.readLine());*/
//使用字节数组来读比较好
/* byte[] buf = new byte[1024];
int len;
while((len = raf.read(buf)) != -1){
System.out.println(new String(buf,0,len));
}*/
//3.写数据
//raf.writeChars("abc");
//raf.writeBytes("abc");
raf.seek(4);//指定位置
raf.write(97);
raf.write(98);
raf.write(99);
}
数据输入输出流
DataInputStream, DataOutputStream可以按照基本数据类型大小读写数据
例如按Long大小写出一个数字, 写出时该数据占8字节.
读取的时候也可以按照Long类型读取, 一次读取8个字节.
long a = 997;
long b = 998;
long c = 999;
//使用FileOutputStream没法写入long类型数据
FileOutputStream fos = new FileOutputStream("a.txt");
//byte -128~127 0~255
/* fos.write(997);只会写一个字节,不会写8个字节
fos.write(998);
fos.write(999);*/
//fos.wr
DataOutputStream dos = new DataOutputStream(fos);
dos.writeLong(a);//写8个字节
dos.writeLong(b);
dos.writeLong(c);
dos.close();
//读3个long数据
DataInputStream dis = new DataInputStream(new FileInputStream("a.txt"));
System.out.println(dis.readLong());//读8个字节
System.out.println(dis.readLong());//读8个字节
System.out.println(dis.readLong());//读8个字节
Properties类【掌握-经常用】
Properties:属性,与Map的使用有点类似
Properties 类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载,这个类可以读写文件。
属性列表中每个键及其对应值都是一个字符串。
存中文时,会转成Unicode编译存储
// 声明对象
Properties properties = new Properties();
// 设置键值对
properties.setProperty("名字", "林大哥");
properties.setProperty("密码", "123");
try {
// 写入
properties.store(new FileWriter("a.properties"), null);
// 读取
properties.load(new FileReader("a.properties"));
// 遍历一
// 获取所有的键
Set<Object> set = properties.keySet();
for (Object key : set) {
System.out.println(key + ":" + properties.get(key));
}
System.out.println(".............");
// 遍历二
for (Entry<Object, Object> entry : properties.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
} catch (IOException e) {
e.printStackTrace();
}