---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
合并流
SequenceInputStream:表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
SequenceInputStream(InputStreams1,InputStream s2)
将按顺序读取这两个参数,先读取s1,然后读取s2
读取完毕后,直接关闭SequenceInputStream即可,内部会关闭两个参数的输入流
如果有多个文件需要合并为一个文件,构造方法也提供了
SequenceInputStream(Enumeration<?extends InputStream> e)
附:Enumeration是Vector的迭代器
步骤与思路:
(1)创建Vector集合,把多个输入流添加到Vector集合中
Vector<FileInputStream> v =new Vector<FileInputStream>()
(2)获取Vector的迭代器对象
Enumeration<FileInputStream> en =v.elements()
(2)把迭代器对象传入
SequenceInputStream sis = newSequenceInputStream(en);
(4)创建输出流FileOutputStream fos = new FileOutputStream(file);
(5)创建缓冲区byte[] bt = new byte[1024];
合并流使用范例
Vector<FileInputStream>v = new Vector<FileInputStream>();//创建一个Vector集合,也可以创建ArrayList集合
v.add(newFileInputStream("D:\\test\\Day19\\1.txt"));//把流添加到集合当中
v.add(newFileInputStream("D:\\test\\Day19\\2.txt"));
v.add(newFileInputStream("D:\\test\\Day19\\3.txt"));
Enumeration<FileInputStream>en = v.elements();返回一个集合内容的枚举
SequenceInputStreamsis = new SequenceInputStream(en);
FileOutputStreamfos = new FileOutputStream("4.txt");
intlen = 0;
byte[]bt = new byte[1024];
while((len=sis.read(bt))!=-1)
{
fos.write(bt,0,len);
}
fos.close();
sis.close();
拓展:使用Vector可能会导致效率低下,因为Vector是线程安全,如果想使用ArrayList存储输入流,并实现合并流,应该如何实现?
观察构造方法
SequenceInputStream(Enumeration<?extends InputStream> e)
参数必须是Enumeration类型的(附:Enumeration是一个接口类
),也就是说可以是Enumeration及其子类对象,但是ArrayList的迭代器类型是Itorator
思路如下:
以匿名内部类的形式传入Enumeration的子类,然后覆写接口内部的抽象方法
Iterator<E> it =arraylist.iterator();
SequenceInputStream(new Enumeration()
{
boolean hasNextelement()
{
return it.hasNext();
}
E next()
{
return it.next();
}
})
切割流
示例:
FileInputStream fis = newFileInputStream("d:\\test\\Day19\\IMG_0461.JPG");//创建读取流,关联文件
FileOutputStreamfos = null;
intcount = 1;
intlen;
byte[]buf = new byte[1024];
while((len=fis.read(buf))!=-1)
{
fos= new FileOutputStream("d:\\test\\jpg\\" + (count++) +"part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
对象的序列化
ObjectInputStream
ObjectOutputStream
两者都是操作对象的,必须成对使用
对象本身存在于堆内存中的,这两个类的功能就是存取对象的
如果要序列化一个类,必须要实现一个接口:Serializable否则编译时会报错
这个Serializable接口没有任何的方法,只用于标记,该类能够被序列化
该接口虽然没有方法,但是给实现该接口的类添加了一个ID标识号语句,在编译时期为每一个对象产生一个特有的ID号,标记着类与对象的所属关系,该ID是根据对象的属性和方法名计算出来
如果修改了对象类的属性或者方法,那么在反序列化的时候,两者的ID不一致,会导致反序列化失败
解决方法如下:
此ID可以手动设置,如果手动添加ID,java虚拟机则不会再计算ID,而是直接使用用户自定义的ID,这种方式可以解决修改了类对象的属性导致ID不一致再导致反序列化失败
static final long serialVersionUID = 42L;
被static修饰的属性不能被序列化
如果对于某个非静态的属性也不想被序列化,那么可以加上一个transient关键字修饰,告诉编译器不要把该属性写到文件中
或者在反序列化的时候,告诉编译器忽略被transient关键字修饰的属性,告诉编译器不要读取这个属性的值
用法示例:
class WriteObjectDemo
{
publicstatic void main(String[] args) throws Exception
{
writeObj();
readObj();
}
public staticvoid writeObj()throws IOException
{//对象序列化,把对象信息存储进文件中
ObjectOutputStreamoos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(newPerson999("liangjian",23));
oos.close();
}
publicstatic void readObj()throws Exception
{//对象反序列化,把对象的内容从文件中读取出来
ObjectInputStream ois = new ObjectInputStream(newFileInputStream("obj.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
}
}
拓展:创建对象一定会调用构造方法吗?
不一定,有特殊的情况
在对象的反序列化中,不会调用构造方法
ObjectInputStream ois =new ObjectInputStream(new FileInputStream("obj.txt"));
Object o =ois.readObject();
内部的实现方式如下:
执行ois.readObject();会创建一个Object对象,把从obj.txt文件中读取到的对象信息赋予该对象,Object o再指向该对象
注意的地方:
如果一个类内部维护着另外一个类的对象,那么另外一个类也必须实现Serializable接口,否则,序列化失败
示例:
class Address
{
String addr;
}
Class Person implementsSerializable
{
String name;
int age;
Address addr;
}
此时如果要序列化Person的对象,序列化失败,因为person对象内部维护着Address类的对象,但是Address类没有实现Serializable接口
管道流
RandomAccessFile
该类不是算是IO体系中子类。
而是直接继承自Object。
但是它是IO包中成员。因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。
用于操作字节数组的流对象。
ByteArrayInputStream:在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。不会发生任何的IO异常(但是有可能有别的异常)
所以,不用进行close关闭。
在流操作规律讲解时:
源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。
用流的读写思想来操作数据。
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------