序列流 SequenceInputStream
如果要实现多个文件的合并,怎么办?
没有序列流之前,想法是为每个文件创建各自的输入流, 然后将这些输入流放入集合中, 创建唯一一个输出流, 遍历读取。
但是JAV提供了序列流来做这个事情,更方便啦。
SequenceInputStream :
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
直接看着定义写了一个小片段。。
public static void main(String[] args) throws IOException {
File inFile1= new File("E:\\a.txt");
File inFile2= new File("E:\\b.txt");
File outFile= new File("E:\\c.txt");
FileInputStream fis1 =new FileInputStream(inFile1);
FileInputStream fis2 =new FileInputStream(inFile2);
FileOutputStream fos =new FileOutputStream(outFile);
SequenceInputStream sis =new SequenceInputStream(fis1,fis2);
byte[] buf =new byte[1024];
int length;
while((length=sis.read(buf))!=-1)
fos.write(buf, 0, length);
}
sis.close();;//其实没有读写能力, 就是把传入参数的流关闭
fos.close();
然后我打开文档看一下这个序列流。。。发现他的构造方法有点蛋疼
注意,只要构造方法需要InputStream的参数,显然这个流没有读写能力,只是把传入的流进行一些封装。 所以关闭这个流就等于关闭2个inputStream流啦
要么只能合并2个, 要么就要用什么enumeration。。。。那是vector里的东西吧。。我都不怎么记得了。。
回忆一下。
Vector的elements方法返回一个Enumeration类的迭代器。
这个迭代器有hasMoreElements() nextElement()两个方法。。
public static void main(String[] args) throws IOException {
File inFile1= new File("E:\\a.txt");
File inFile2= new File("E:\\b.txt");
File inFile3= new File("E:\\c.txt");
File outFile= new File("E:\\d.txt");
FileInputStream fis1 =new FileInputStream(inFile1);
FileInputStream fis2 =new FileInputStream(inFile2);
FileInputStream fis3 =new FileInputStream(inFile3);
FileOutputStream fos =new FileOutputStream(outFile);
Vector v =new Vector();
v.addElement(fis1);
v.addElement(fis2);
v.addElement(fis3);
Enumeration e =v.elements();
SequenceInputStream sis =new SequenceInputStream(e);
byte[] buf =new byte[1024];
int length;
while((length=sis.read(buf))!=-1)
fos.write(buf, 0, length);
}
注意::
可以用读写去切割合并音频,但是视频不行。
因为视频的二进制文件有规定的10101010作为起始终止符。。你切刀中间没有终止符,他不是一个正常的视频文件 懂吗!!
对象的输出流 ObjectOutputStream
把对象的信息写到硬盘上, 称为对象的序列化
对于对象的输出流,一看构造方法, 需要传入一个输出流当做参数,显然的,这个流本身也没有读写能力,是借助参数的流的读写能力。。
于是写了一个小DEMO
class Us {
String name ;
String password;
public Us(String name , String password){
this.name= name;
this.password =password;
}
public String toString(){
return this.name+this.password;
}
}
public class sss {
public static void main(String[] args) throws IOException {
File dest = new File("E:\\a.txt");
FileOutputStream fos = new FileOutputStream(dest);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Us luo = new Us("cxksren","atfield321");
oos.writeObject(luo);
oos.close();
}
居然报错。。。
Exception in thread "main" java.io.NotSerializableException: cn.Us
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at cn.sss.main(sss.java:34)
再返回文档看类的说明,
发现有解释::
只能将支持 java.io.Serializable 接口的对象写入流中。
再打开这个接口。。。发现啥方法都没有。。。
原来只是一个标志接口。。。。。实现下就好了
对象的输入流 ObjectInputStream
把文件中对象的信息读取出来, 称为对象的反序列化!!
同样的一看构造方法, 需要传入参数的输入流, 和对象的输出流一样。。
class Us implements Serializable {
String name ;
String password;
public Us(String name , String password){
this.name= name;
this.password =password;
}
public String toString(){
return this.name+" "+this.password;
}
}
public class sss {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File dest = new File("E:\\a.txt");
FileOutputStream fos = new FileOutputStream(dest);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Us luo = new Us("cxksren","atfield321");
oos.writeObject(luo);
oos.close();
FileInputStream fis = new FileInputStream(dest);
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.println((Us)ois.readObject());//返回一个对象,但是并没有用到构造方法。 但是创建对象起码要依赖class文件!!
ois.close();
}
}
对象输入输出流要注意的细节:
1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。
2. 对象的反序列化创建对象的时候并不会调用到构造方法的、
3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID进行对比,如果这两个id不一致,那么反序列化就失败了。
5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
7. 如果一个类维护了另外一个类的引用,那么另外一个类也需要实现Serializable接口。
Properties类生成配置文件
属于Map体系
因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用 store 或 save 方法,则该调用将失败。类似地,如果在“不安全”的 Properties 对象(即包含非 String 的键)上调用 propertyNames 或 list 方法,则该调用将失败。
用load 如果存的时候有中文, 要用字符流去存, 不然用的IOS8859-1 存中文, 会有乱码
public static void main(String[] args) throws IOException {
Properties p1 =new Properties();
Properties p2 =new Properties(); //Properties 是继承HashMap的集合 只是一个集合 并不是配置文件
p1.setProperty("cxksren", "atfield321");
p1.setProperty("zjl", "19950209");
p1.setProperty("luoyi", "sb");
p1.setProperty("傻逼", "白痴");
p1.store(new FileWriter(new File("E:\\p.properties")), "aloha~"); //把集合的内容写到文件里面去
//生成了配置文件
p2.load(new FileReader("E:\\p.properties")); //又用一个集合读取了配置文件的信息
Set<Entry<Object, Object>> entrys = p2.entrySet();
for(Entry<Object, Object> entry: entrys )
System.out.println(entry.getKey()+" "+entry.getValue());
p2.setProperty("傻逼", "周锦岚"); //想修改配置文件的内容,实际这一步只修改了装有读取了配置文件内容的集合
p2.store(new FileWriter(new File("E:\\p.properties")), "aloha1~"); //重新修改了文件
}