在字符流、字节流之下,java.io包下,还有其他几种基于这两种流为基础的新生类型。打印流PrintWriter、PrintStream,序列流SequenceInputStream,操作对象流ObjectInputStream、ObjectOutputStream。这些流,即可以看作是原有字节字符流的功能专精的强化版,也可以认为是单独衍生出来的新类型。
------- android培训、java培训、期待与您交流! ----------
PrintWriter与PrintStream
这两个类的作用相仿,但是PrintWriter着重从字符流的角度来操纵输入流,另一个PrintStream则是直接从字节来实现的。PrintWriter的构造函数中,可以用OutputStream及其子类来作为初始化操作赋值。这两个类都是原类的修饰类,提供了打印print、println方法,并继承了父类的write方法,他们的write都具有父类的特征,即写入数据类型与父类保持一致。因此,相较而言字符更贴近通常操作,PrintWriter更常用一些。唯一一点不便的是,使用PrintWriter类,每次输入都需要flush刷新,而PrintStream类则不需要。
我们来看一个对Properties类与PrintWriter类等I/O类的综合运用例题:
/**@author:LZ
*/
/*目标:读取当前目录下的config.ini文件,并对其中的参数进行修改或创建
要求:1 对其中的参数进行修改或创建
2 对配置文件进行备份,并将备份文件建立在当前目录下,命名为backup.ini
思路:1 读取配置文件,没有则创建
2 判断是否修改或添加,并进行相关操作
3 备份配置文件
*/
import java.io.*;
class CreateConfigDocTest
{
public static void main(String[] args)
{
Properties p =new Properties();
File config = newFile("config.ini");
p = loadProp(config); //载入原有config.ini默认设定,如没有则创建
changeProp(config); //判断是否需要对面参数进行修改
back(p); //实现配置文件备份,如没有则创建
}
public static Properties loadProp(Fileconfig)
{
if (!config.exists())
config.createNewFile();
FileInputStream br = newFileInputStream(config); //连接配置文件
Properties p = new Properties();
p.load(br);
p.list(System.out); //输出读取到的配置情况
br.close();
return p;
}
public static void changeProp(Propertiesp)
{
BufferedReader in =
new BufferedReader(newInputStreamReader(System.in);
String a = null
while(!(a=in.readLine()).equals("end"))
{
sop(a+"_search_result:"+p.getProprity(a));
sop("change?(y\\n)");
if(in.readLine()=="y") //判断更改配置与否
p.setProperty(a,in.readLine()); //读取相应配置值,赋值
}
in.close();
}
public static void backup(Properties p)
{
File back = newFile("backup.ini");
if (!back.exists())
back.createNewFile();
PrintWriter pw = newPrintWriter(back); //连接备份文件
p.list(back); // Properties的list方法参数为PrintWriter或者PrintStream类型
//也可以,或者建议使用store( OutputStream o,String c)方法
pw.close();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
上面的例题展现了配置文件、配置类Properties非临时性配置形式的基本应用,不难看出,如果想要存储相应的配置信息,我们所涉及的I/O操作就肯定会比较多。其中的一些操作,如PrintWriter类对象给list函数参数赋值等,就使得程序在I/O部分的代码可读性提高。
SequenceInputeStream序列输入流
SequenceInputStream类为InputStream类的子类,能够将多个输入流整合为一个输入流,继承了父类方法。该类的主要不同,就在于它的构造函数实现了多个字节输入流串联,对应的构造函数SequenceInputStream(Enumeration e)。
序列流只有输入流,无输出流。下面的使用案例中,我们用序列流来简称序列输入流:
import java.io.*;
import java.util.*;
class SequenceISTest
{
public static void main(String[] args)
{
Vector<FileInputStream> v =new Vector<FileInputStream>(); //建立输出流集合
v.add(newFileInputStream("1.txt"));
v.add(newFileInputStream("2.txt"));
v.add(newFileInputStream("3.txt"));
Enumeration<FileInputStream>e = v.elements(); //建立输出流对应枚举类
SequenceInputStream si = newSequenceInputStream(e); //关联枚举类到序列流
byte[] b = new byte[1024];
int num = 0;
while ((num=si.read(b))!=-1)
{
System.out.write(b,0,num);//将合并后的文档内容输出到控制台
}
si.close(); //关闭序列流
}
}
相比起数据的合流,分割操作就需要通过对字节流的基本操作来实现了。我们的思想是通过输出流的write方法,和输入流的read方法,将读到的数据通过我们给定的暂存,存放到一定大小的不同文件当中,来完成文件及数据的分割。如下所示:
/**@author:LZ
*/
/*目标:实现对本Java程序文档的拆分,和重组操作
要求:1 能够实现对本程序的拆分,按照2Mb的准则进行
2 给予用户重组文档选项,并按用户要求命名保存
思路:1 初始化变量,建立表List,便于恢复
2 拆分文件为为2Mb大小的碎片文件,后缀为".p"
3 按要求,如要恢复则在用户指定位置存储
*/
import java.io.*;
import java.util.*;
class Split_MergeTest
{
public static void main(String[]args) //程序主函数
{
//定义需要拆分的文档,完成控制台读取流初始化
File fs = newFile("Split_MergeTest.java");
BufferedReader br =
new BufferedReader(newInputStreamReader(System.in));
ArrayList a = null;
//执行拆分操作
a = split(fs);
sop("done!!\nDo you want tomerge the pack?(y/n)");
String c = null;
//判断是否需要执行拆分后碎片文档的合并操作
if((c=br.readLine()).equals("y"))
{
merge(a,newFile(br.readLine()));
sop("mergedone!!");
}
else if(c.equals("no"))
sop("done!!");
else
sop("error: wronginput!");
//关闭控制台读取流
br.close();
}
//拆分函数,参数为需要拆分文档
public staticArrayList<FileInputStream> split(File f)
{
FileInputStream in = newFileInputStream(f);
FileOutputStream out = null;
ArrayList<FileInputStream>res = new ArrayList<FileInputStream>();
byte[] b = new byte[1024*1024*2];
int num = 0;
for (int i=0;(num=in.read(b))!=-1; i++)
{
out = newFileOutputStream(i+".p");
out.write(b,0,num);
res.add(out); //将划分文件添加到结果集中
out.close();
sop("split to part"+i+" !");
}
in.close();
return res;
}
//合并操作,参数a为
public static void merge(ArrayList<?extends InputStream> a, File f)
{
Iterator ite = a.iterator();
Enumeration e = new Enumeration() //枚举类,自定义覆盖原方法
{
public booleanhadMoreElements()
{
returnite.hasNext();
}
public booleannextElement()
{
return ite.next();
}
}
SequenceInputStream sin = newSequenceInputStream(e);
FileOutputStream out = newFileOutputStream(f);
byte[] b = new byte[1024]
int num = 0;
while ((num=sin.read(b))!=-1)
{
out.write(b,0,num);
}
out.close();
sin.close();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
当然,在文件的分割上,我们可以通过固定的暂存与计数器配合的方式,来实现人为可定的分割大小。计数器来计量每个包大小,当达到一定程度的时候,就重新定义一个新的分割包,来装载剩余文件。
------- android培训、java培训、期待与您交流! ----------