1. 打印流:
printStream是FilterOuterputStream的直接子类,FilterOutputStream是OutputStream的直接子类,printStream的构造方法:
PrintStream(File file)
PrintStream(OutputStream out)
PrintStream(String fileName)
printWriter是Writer的直接子类,printStream的构造方法:
PrintWriter(File file)
PrintWriter(OutputStream out)
PrintWriter(String fileName)
PrintWriter(Writer out)
打印流的构造方法决定了其技能操作其他输入又能直接操作文件流,当然打印流也能根据指定的编码打印。
打印流中提供了各种打印方法,可以将各种数据类型照原样打印。
import java.io.*;
public classPrintWriterDemo {
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[]args) {
// TODO Auto-generated method stub
BufferedReaderbr = newBufferedReader(newInputStreamReader(System.in));
//打印在控制台上
//PrintWriter pw = new PrintWriter(newOutputStreamWriter(System.out));
//PrintWriter pw = new PrintWriter(System.out);
//打印到文件
PrintWriterpw = null;
Stringstr = null;
try {
//打印到文件
pw = new PrintWriter("D:\\2.txt");
while((str = br.readLine())!=null){
if(str.equalsIgnoreCase("exit"))
break;
pw.println(str);
pw.flush();
}
}catch (FileNotFoundExceptione) {
// TODO Auto-generated catchblock
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(br !=null)
br.close();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pw.close();
}
}
}
合并流SequenceInputStream(一个输出流对应多个输入流)是InputStream的直接子类
SequenceInputStream 表示其他输入流的串联,他从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,以此类推直到达到包含的最后一个文件的尾部为止
构造方法:
SequenceInputStream(Enumeration<? extends InputStream>e) SequenceInputStream(InputStream s1,InputStream s2)
合并流在操作时要用到Vector和Enumeration来遍历。
实例:
import java.io.*;
import java.util.*;
public classSequenceInputStreamDemo {
/**
* @param args
*/
public static void main(String[] args)throws IOException{
// TODO Auto-generated method stub
//定义一个Vector对象用来存放字节输入流
Vector<InputStream>v = newVector<InputStream>();
//往v中装指定类型的元素
v.add(new FileInputStream("D:\\count.ini"));
v.add(new FileInputStream("D:\\2.txt"));
v.add(new FileInputStream("D:\\count.ini"));
//拿到v的Enumeration,以便传给SequenceInputStrem的构造函数
Enumeration<InputStream>e = v.elements();
//创建一个合并流,必将vector的Enemeration传入
SequenceInputStreamsis = newSequenceInputStream(e);
//定义一个输出流用来接收合并流中的数据,被将这些数据写入D:\\3.txt,
BufferedWriterbw = newBufferedWriter(newFileWriter("D:\\3.txt"));
int r = 0;
while((r = sis.read()) != -1){
bw.write(r);
}
sis.close();
bw.close();
}
}
切割流:(注意:并没这个类,但我们可以自己实现);
与合并流对应的是切割流(一个输入流对应多个输出流)
例子:切割一个图片后并将其合并
import java.io.*;
import java.util.*;
public classSplitFile {
/**
* @param args
*/
public static void main(String[] args)throws IOException {
// TODO Auto-generated method stub
//splitFile();
hebing();
}
//将文件分割
public static void splitFile()throws IOException{
//建立一个文件输入,并将要被分割的文件作文参数传入
InputStreamin = newFileInputStream("D:\\0.gif");
//定义一个输出流,用来接收分割后的数据
FileOutputStreamout= null;
//定义一个大小为1M的字节数组,此数组用来分割数组的工具,当此数组装满时,
//文件就又被分割了1M大小的数据,若最后文件对完了数组未装满,则,将读到的实际长度的字节存入一个独立文件
byte[] b =new byte[1024*1024];
int len = 0;
int i = 0;
while((len = in.read(b)) !=-1){
//每当数组存满1M时,就创建一个文件,数组中的数据存入此新建文件
//若最后文件对完了数组未装满,则,将读到的实际长度的字节存入一个此新建文件
out= newFileOutputStream("D:\\"+ ++i +".part");
out.write(b,0,len);
out.close();
}
in.close();
}
//将分割后的文件合并起来,
public static void hebing()throws IOException{
//定义一个ArrayList用来存放输入流
ArrayList<InputStream>al=newArrayList<InputStream>();
//将要合并的文件出入流中并,将流加入ArrayList中,以便合并流
for(int i = 1; i < 6 ; i++){
al.add(new FileInputStream("D:\\"+ i +".part"));
}
final Iterator<InputStream> it =al.iterator();
//因为此处定义了一个局部内部类并且用到了方法中的变量it,所以it必须定义为final的后则不能访问
//为什么要这样做,因为ArrayList的效率比Vector的效率高
Enumeration<InputStream> e = new Enumeration<InputStream>(){
//此处在方法中定义了一个内部类,将ArrayLIst的Iterator转成Enumeration是为了提高效率
@Override
public boolean hasMoreElements() {
// TODO Auto-generated method stub
return it.hasNext();
}
@Override
public InputStreamnextElement() {
// TODO Auto-generated method stub
return it.next();
}
};
//定义一个合并流,将以上三个流合并
SequenceInputStream sis = new SequenceInputStream(e);
//定义一个输出流用来接说合并流的数据,并将数据存入文件,于是被切割的文件就还原了
FileOutputStream fos = new FileOutputStream("D:\\1.gif");
int r = 0;
while((r = sis.read())!= -1){
fos.write(r);
}
sis.close();
fos.close();
}
}
对象的序列化:
ObjectOutputStream--àOutputStream
特有方法(写入对象的方法)writeObject(Object)
ObjectOutputStream
(OutputStream out)
对象想被序列化必须实现一个接口,Serializable接口,(否则报NotSerializableException)此接口中没有定义方法。这样的接口称为标记接口。
反序列化:
ObjectInputStream--àInputStream
ObjectInputStream
(InputStream in)
Object readObject();
类在序列化后,再改变类的源文件,再读是读取不了的,因为读的时候是跟据类文件来读的,类变化后,反序列时Jvm会找不到原有类。其实每个类都有一个UId号来区分类的不同的,所以当类以改变,此uid也就改变了。注意Uid是唯一的(改变方法或成员变量Uid都会发生变化)
但是我们可以自己定义一个UId,此时改变类的成员时不会改变这个Uid,所以还是可以反序列化的。
(该字段必须是静态(static)、最终 (final) 的 long
型字段)显式声明其自己的 serialVersionUID:
例如:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;和面的值可以自己随意赋值。
静态的成员也是不能被序列化的,序列化只是将堆内存中的内容序列化,而静态变量存放在数据区的中,从这里也可以看出来,其实反序列化是根据类来反序列化的
Transient关键字修饰的成员变量,其值在堆内存中存在,而在文件中不存在,所以在反序列化时,Transient关键字修饰的成员变量的值为默认值,(即引用型变量为null,基本输入类型为0或0.0,boolean为false)
管道流:
PipedInputStream----àInputStream
PipedOutputStream---àOutputStream
管道流之间可以直接进行连接,通过结合线程使用
怎么连接呢?
1. 使用构造函数,传入彼此
2. 使用connect方法,输入输出流中都有connect方法
当要从输入流中数据中获得数据时,用输出流中的connect方法,当要从输出流中读数据时,用输入流中的connect方法(构造方法的用法一样)字符的管道流与直接的管道流的操作时一样的
package piped;
import java.io.*;
public classPipedDemo {
public static void main(String[] args){
PipedInputStreamin = newPipedInputStream();
PipedOutputStreamout = newPipedOutputStream();
try {
in.connect(out);
/*当要从输入流中数据中获得数据时,用输出流中的connect方法,
* 当要从输出流中读数据时,用输入流中的connect方法
* (构造方法的用法一样)字符的管道流与直接的管道流的操作时一样的*/
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Readr =newRead(in);
Writew = newWrite(out);
new Thread(r).start();
new Thread(w).start();
}
}
//建立一个线程来从输出流读取数据
class Read implementsRunnable{
PipedInputStreamin ;
Read(PipedInputStreamin ){
this.in = in;
}
@Override
public void run() {
// TODO Auto-generated method stub
byte[] b =new byte[1024];
int len = 0;
try{
while((len =in.read(b)) != -1){
System.out.println(new String(b,0,len));
}
}catch(IOException e){
e.printStackTrace();
throw new RuntimeException("读取失败");
}finally{
try {
if(in !=null)
in.close();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//建立一个输出流来往输入流中写入数据
class Write implements Runnable{
PipedOutputStreamout;
Write(PipedOutputStreamout){
this.out = out;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
out.write("ma jing yu I love you I want to fuck you!".getBytes());
}catch(IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("写入失败");
}finally{
try {
if(out !=null)
out.close();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
可用用于操作基本数据类型的流对象:是流和数据相结合的流;所以他她们的构造函数都要接收一个相应的流对象
DataInputStream -------àFilterInputStream----àInputStream
DataInputStream
(InputStream in)
DataOutputStream----àFilterOutputStream---àOutputStream
DataOutputStream
(OutputStream out)
import java.io.*;
public classDataStreamDemo {
/**
* @param args
*/
public static void main(String[] args)throws IOException {
// TODO Auto-generated method stub
//write() ;
read();
}
//将基本数据类型写入文件
public static void write() throws IOException{
//定义一个数据输入流,并关联一个文件输出流,准备将基本类型的数据写入文件
DataOutputStreamdos = newDataOutputStream(newFileOutputStream("D:\\1.txt"));
//写入Int型数据
dos.writeInt(4);
//写入double型数据
dos.writeDouble(2.345);
//写入boolean型数据
dos.writeBoolean(false);
//写入String型数据,注意如果用WriteUTF方法写入,则必须用ReadUTF读取否则,数据错乱,
dos.writeUTF("majingyu woxiangcaoni ");
dos.close();
}
//将基本数据类型从文件中读取出来,并且读取顺序要和写入时的一样,即先写Int就先读int
public static void read() throws IOException{
//定义一个数据读取流,并接受一个文件输入流,从文件中读取基本数据类型的数据
DataInputStreamdis = newDataInputStream(newFileInputStream("D:\\1.txt"));
//从文件中读取一个int数据
int i = dis.readInt();
sop("i = " + i);
//从文件中读取一个double数据
double d =dis.readDouble();
sop("d = "+d);
//从文件中读取一个boolean数据
boolean b = dis.readBoolean();
sop("b = " + b);
//用readUTF方法从文件中读取一个String数据
Stringstr = dis.readUTF();
sop("str::"+ str);
dis.close();
}
public static void sop(Object o){
System.out.println(o);
}
}
ByteArrayInputStream-------àInputStream 在构造时,需要接受数据源。而且数据源是一个字节数组
ByteArrayInputStream
(byte[] buf)
ByteArrayInputStream(byte[] buf,int offset,int length)
ByteArrayOutputStream------àOutputStream:在构造时,不用定义数据的目的地,因为该对象中已经封装了一个可变长度的字节数组 :这就是数据目的地,
ByteArrayOutputStream
(int size)
由于这两个流对象造作的都是数组,并没有操作系统资源。所以不用进行关闭,即使关闭了,流还是可以使用。也不会产生任何的IO异常。
只有一个方法会抛异常:writeTo(OutputStream os);将字节数组输出流中的可变长度数组的内容,写入指定的输出流。
特有方法:size();获得可变长度字节数组的长度。没有写入数据时是0;
toString
()方法是可变长度字节数组转成String。
import java.io.*;
public classByteArrayDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
method_1();
method_2();
}
//字节数组输出流的方法的用法
public static void method_1(){
ByteArrayOutputStreambaos = newByteArrayOutputStream();
//获取字节输出流中可变长度的数组的大小,在未往里写数据之前,为0
sop(baos.size());
try {
baos.write("liaoli".getBytes());
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取字节输出流中可变长度的数组的大小,在未往里写数据之前,为0,写入数据后为写入的字节数
int i = baos.size();
//字节数组输出流,中定义了将可变长度的字符数组转成String的方法toString()方法
Stringstr = baos.toString();
sop(i);
sop(str);
try {
//将字节数组输出流中的可变长度数组的内容,写入指定的输出流。
baos.writeTo(new FileOutputStream("D:\\1.txt"));
}catch(FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(baos !=null)
baos.close();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void method_2(){
//定义了一个字节数组输入流。并传入一个字节数组,作为数据源
ByteArrayInputStreambais = newByteArrayInputStream("majingyuiloveyou".getBytes());
//定义了一个字节数组输出流,用来接收从字节数组输入流中读取的数据,将接收的数据存入字节数组输出流的可变长度数组中
ByteArrayOutputStreambaos = newByteArrayOutputStream();
//获取字节输出流中可变长度的数组的大小,在未往里写数据之前,为0
sop(baos.size());
int i = 0;
//从字节数组输出流中读取数据,并将读取的数据存入字节输出流中的可变长度的字节数组中
while((i = bais.read())!=-1){
baos.write(i);
}
//获取字节输出流中可变长度的数组的大小,在未往里写数据之前,为0,写入数据后为写入的字节数
sop(baos.size());
sop(baos.toString());
}
public static void sop(Object o){
System.out.println(o);
}
}