IO流六:IO包中其他流对象

1  PrintStreamPrintWriter打印流

打印流:

该流提供了print打印方法,可以将各种数据类型的数据都原样打印。

 

字节打印流:PrintStream

构造函数可以接收的参数类型:

1file对象。 File

2,字符串路径。 String

3,字节输出流。 OutputStream

 

字符打印流:PrintWriter

构造函数可以接收的参数类型:

1file对象。 File

2,字符串路径。 String

3,字节输出流。 OutputStream

4,字符输出流。 Writer

 

代码示例:

import java.io.*; 

class PrintWriterDemo{
	public static void main(String[] args) throws IOException{
		BufferedReader bufr = 
			new BufferedReader(new InputStreamReader(System.in));
			
	    PrintWriter out = new PrintWriter(System.out,true); //true表示,println将自动刷新缓冲区。
	  //PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
		
		String line = null;
		while((line=bufr.readLine())!=null) {
			if(line.equals("over"))
				break;
			out.println(line.toUpperCase()); //把line转成大写后写入打印流。
			//PrintWriter的构造函数中传递了参数true,println会自动刷新缓冲区。
			
			//out.flush();
		}
		out.close();
		bufr.close();
	}
}

2  SequenceInputStream合并流

SequenceInputStream:表示其他输入流的逻辑串联。

它从输入流的有序集合开始,并从第一个输

入流开始读取,直到到达文件末尾,

接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

 

构造方法:

SequenceInputStream( Enumeration<? extends InputStream> e);

SequenceInputStream( InputStream s1, InputStream s2);

 

使用到了Vector类的elements方法,返回一个枚举Enumeration

代码示例:

import java.io.*;
import java.util.*; 

class SequenceDemo{
	public static void main(String[] args) throws IOException{
		Vector<FileInputStream> v = new Vector<FileInputStream>(); //Vector集合,元素是输入流
		
		v.add(new FileInputStream("e:\\1.txt")); //添加一个流到集合中
		v.add(new FileInputStream("e:\\2.txt"));
		v.add(new FileInputStream("e:\\3.txt"));
		
		Enumeration<FileInputStream> en = v.elements(); //返回枚举,Enumeration接口
		SequenceInputStream sis = new SequenceInputStream(en); //把枚举集合传递到合并读取流
		FileOutputStream fos = new FileOutputStream("e:\\4.txt");
		
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	}
}

3  合并流扩展:切割文件然后合并

把一个文件切割成多个碎片文件。

然后,再把这些碎片文件合并,得到原文件。

思路:

1,切割文件:定义一个1KB大的数组,读取一个文件,每一次读取1KB大小的数据,把这一次读取的数据单独定义一个输出流,输出为一个碎片文件。最终有多少个碎片文件,就定义了多少个输出流。

2,合并文件:假如有N个碎片文件,就定义N个输入流,这些输入流对象存储到一个集合中。获取这个集合的迭代器,用匿名内部类方式创建一个枚举对象,并在实现中调用迭代器的方法,实现枚举对象的判断和取出。用合并流实现从多个输入流中连续的读取数据,再连续的写入到一个输出流中,实现碎片文件的合并。创建合并流时,要把枚举对象作为参数,传递给合并流的构造函数。因为要把枚举中的多个输入流,合并为一个输入流。枚举的元素就是输入流。

 

代码示例:

import java.io.*;
import java.util.*;

class SplitFile{
	public static void main(String[] args) throws IOException{
		splitFile();  //切割文件
		merge();   //合并文件
	}
	
	//切割文件,把文件切割成碎片文件
	public static void splitFile() throws IOException{
		FileInputStream fis = new FileInputStream("e:\\EVE.jpg"); //源
		FileOutputStream fos = null; //目的
		
		byte[] buf = new byte[1024]; //1KB
		int len = 0;
		int count = 1;
		while((len=fis.read(buf))!=-1){
			fos = new FileOutputStream("e:\\Split Files\\"+(count++)+".part");
			fos.write(buf,0,len);
			fos.close();
		}
		fis.close();
	}
	
	//合并碎片文件,复原
	public static void merge() throws IOException{
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		
		for(int x=1; x<=6; x++){
			al.add(new FileInputStream("E:\\Split Files\\"+x+".part"));
		}
		final Iterator<FileInputStream> it = al.iterator(); //集合的迭代器
		
		//新建一个枚举,枚举中调用迭代器的方法。迭代器通过集合al获得。
		//枚举一般通过Vector获得,这里没有Vector。
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
		{
			public boolean hasMoreElements(){  //内部类
				return it.hasNext();
			}
			public FileInputStream nextElement(){
				return it.next();
			}
		};
		SequenceInputStream sis = new SequenceInputStream(en); //源,枚举en作为参数传递给合并流
		FileOutputStream fos = new FileOutputStream("E:\\Split Files\\EVE.jpg"); //目的
		
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	}
}

4  ObjectOutputStreamObjectInputStream及对象的序列化

ObjectOutputStreamObjectInputStream,这两个流对象可以操作对象。

序列化:序列化就是此对象的所属类实现Serializable接口,实现了Serializable接口以后,为每个对象分配了一个UID,这个UID即 serialVersionUID

可以在对象的所属类中自定义serialVersionUID的值,这样就永远一个对象。

静态不能被序列化。

 

代码示例:

import java.io.*;

class ObjectStreamDemo {
	public static void main(String[] args) throws Exception{
		writeObj();
		readObj();
	}
	
	//创建一个Person对象,并把这个对象存到obj.txt文件中。
	public static void writeObj() throws IOException{
		ObjectOutputStream oos = 
			new ObjectOutputStream(new FileOutputStream("e:\\obj.txt"));
		
		oos.writeObject(new Person("lisi",39)); //把对象写入流中
		oos.close();
	}
	
	//从obj.txt文件中读取那个对象。
	public static void readObj() throws Exception{
		ObjectInputStream ois = 
			new ObjectInputStream(new FileInputStream("e:\\obj.txt"));
		
		Person p = (Person)ois.readObject(); //从流中读取对象
		System.out.println(p);
		ois.close();
	}
}

//Serializable标记接口,想要序列化必须实现此接口,起标记作用。
class Person implements Serializable{ //被标记的可以序列化
	private String name = null;
	private int age = 0;
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String toString(){
		return name+" : "+age;
	}
}

5  管道流

IO包中的管道流:

PipedInputStream

PipedOutputStream

PipedReader

PipedWriter

管道读取流流和管道写入流可以像管道一样对接上,即管道读取流可以读取管道写入流写入的数据。

可以认为有一个虚拟的“管道”,PipedInputStream从这个管道中读取数据,而PipedOutputStream把数据写入到这个管道中。写入之后,PipedInputStream就可以读取到数据了。如果管道中没有数据,PipedInputStream会线程阻塞。

管道流需要加入多线程技术。

 

代码示例和注释:

import java.io.*;

class Read implements Runnable{ //实现Runnable接口并覆盖run,多线程
	private PipedInputStream in;
	Read(PipedInputStream in){ //管道输入流
		this.in = in;
	}
	public void run(){
		try{
			byte[] buf = new byte[1024];
			
			int len = in.read(buf);  //in中没有数据时,线程阻塞。
			String s = new String(buf ,0,len);
			System.out.println(s);
			in.close();
		}
		catch(IOException e){
			System.out.println("管道读取流失败");
		}
	}
}

class Write implements Runnable {
	private PipedOutputStream out;
	Write(PipedOutputStream out){ //管道输出流
		this.out = out;
	}
	public void run(){
		try{
			//将指定的字节数组写入管道输出流,write是把指定数据写入流中,
			//往管道流中写入数据,Read中阻塞的线程可以读到数据,继续执行。
			out.write("piped lai la".getBytes());        
			out.close();
		}
		catch(IOException e){
			System.out.println("管道输出流失败");
		}
	}
}

class PipedStreamDemo {
	public static void main(String[] args) throws IOException{
		PipedInputStream in = new PipedInputStream(); //负责读取管道中的数据到流中。
		PipedOutputStream out = new PipedOutputStream(); //负责向管道中写入数据,以便读取
		in.connect(out); //connect方法把管道流的输入流和输出流关联起来,形成一条管道。
		
		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}

6  RandomAccessFile随机访问文件

随机访问文件,RandomAccessFile自身具备读写的方法。

通过skipBytes(int x), seek(int x)来达到随机访问的目的。

 

该类不是IO体系中的子类,而是直接继承自Object

但是它是IO包中的成员,因为它具备读和写功能。

内部封装了一个数组,而且通过指针对数组的元素进行操作。

可以通过getFilePointer获取指针位置,同时可以通过seek方法改变指针的位置。

 

其完成读写的原理就是内部封装了字节输入流和输出流。

 

通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式。

 

RandomAccessFile(File file, String mode)

RandomAccessFile(String name, String mode)

mode: r——以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException

      rw——打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。

 

如果模式为只读r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。

如果模式为读写rw,而且该对象的构造函数要操作的文件不存在,则会自动创建,若存在则不会覆盖。

 

代码示例:

import java.io.*;

class RandomAccessFileDemo{
	public static void main(String[] args) throws IOException{
		//writeFile();
		readFile();
		writeFile_2();
	}
	
	public static void writeFile() throws IOException{
		RandomAccessFile raf = new RandomAccessFile("e:\\ran.txt","rw"); //读写模式
		
		raf.write("李四".getBytes()); //基于字节流,写入的是字节数组。
		
		raf.writeInt(97); //writeInt写四个字节,97是“a”的ASCII码,即写“000a”;int类型32位即四个字节。
		
		raf.write("王五".getBytes());
		raf.writeInt(98);
		raf.close();
	}
	
	public static void readFile() throws IOException{
		RandomAccessFile raf = new RandomAccessFile("e:\\ran.txt","r"); //只读模式。
		
		//通过seek和skipBytes方法,达到随机访问的目的。
		//调整对象中开始读写位置,调整文件指针的位置。
		raf.seek(8*1);  //从第8脚标开始取,即调整指针到第9个字节。
		
		//跳过指定的字节数。
	  //raf.skipBytes(8); //跳过8个字节,从第9个字节开始取。
		
		byte[] buf = new byte[4];
		
		raf.read(buf);
		String name = new String(buf);
		int age = raf.readInt();
		
		System.out.println("name="+name);
		System.out.println("age="+age);
		
		raf.close();
	}
	
	public static void writeFile_2() throws IOException{
		RandomAccessFile raf = new RandomAccessFile("e:\\ran.txt","rw");
		
		raf.seek(8*3); //从第25个字节处开始写入数据。
					  //也可以通过seek方法指定指针位置,来修改数据。
		
		raf.write("周七".getBytes());
		raf.writeInt(100);
	}
}

7  DataStream操作基本数据类型的流对象

DataInputStreamDataOutputStream,可以用于操作基本数据类型的数据的流对象。

DataInputStream( InputStream in)

DataOutputStream( OutputStream out) 

八大基本数据类型:byteintshortlongfloatdoublecharboolean

DataInputStream可以直接读取基本数据类型的数据,比如readInt可以读取Int类型。

DataOutputStream可以直接写入基本数据类型的数据,比如writeInt可以写入Int类型。

转换流的构造函数可以传递字符编码,指定所需的是哪种字符编码。

 

代码示例和注释:

import java.io.*;

class DataStreamDemo {
	public static void main(String[] args) throws IOException{
		 writeData();
		 readData();
		 writeUTFDemo();
		 readUTFDemo();
		 
		 //存取转换流
		 OutputStreamWriter osw = 
			new OutputStreamWriter(new FileOutputStream("e:\\utf.txt"),"UTF-8");
		 osw.write("你好");
		 osw.close();
	}
	
	//DataOutputStream中写基本数据类型的方法。
	public static void writeData() throws IOException{
		DataOutputStream dos = 
			new DataOutputStream(new FileOutputStream("e:\\data.txt"));
		
		dos.writeInt(234);  //写入int类型。
		dos.writeBoolean(true);  //写入boolean类型。
		dos.writeDouble(9883.421);  //写入double类型。
		dos.close();
	}
	
	//DataInputStream中读基本数据类型的方法。
	public static void readData() throws IOException{
		DataInputStream dis = 
			new DataInputStream(new FileInputStream("e:\\data.txt"));
		
		int num = dis.readInt();  //一次读四个字节,以int形式返回。
		boolean b = dis.readBoolean(); //一次读两个字节,以Boolean形式返回。
		double d = dis.readDouble(); //读取double类型
		
		System.out.println("num="+num);
		System.out.println("b="+b);
		System.out.println("d="+d);
		dis.close();
	}
	
	//writeUTF()演示,操作中文。
	public static void writeUTFDemo() throws IOException{
		DataOutputStream dos = 
			new DataOutputStream(new FileOutputStream("e:\\UTFdata.txt"));
		
		dos.writeUTF("你好"); //以UTF编码写入
		dos.close();
	}
	
	//readUTF()演示,操作中文
	public static void readUTFDemo() throws IOException{
		DataInputStream dis = 
			new DataInputStream(new FileInputStream("e:\\UTFdata.txt"));
		
		String s = dis.readUTF(); //以UTF编码读取,返回String形式。
		System.out.println(s);
		dis.close();
	}
}

8  ByteArrayStream用于操作字节数组的流对象

ByteArrayInputStreamByteArrayOutputStream:用于操作字节数组的流对象。

 

ByteArrayInputStream:在构造的时候,需要接收数据源,而数据源是一个字节数组。

ByteArrayInputStream(byte[] buf) 

ByteArrayInputStream(byte[] buf, int offset, int length)

 

ByteArrayOutputStream:在构造的时候,不用定义数据目的,

因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。

ByteArrayOutputStream() 

ByteArrayOutputStream(int size) 

 

因为这两个流对象都是操作数组,并没有使用file,即没有使用系统资源,所以,不用进行close关闭。

 

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。

关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException

 

ByteArrayOutputStream 此类实现了一个输出流,其中的数据被写入一个 byte 数组(内部封装)。

缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。

关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException

 

在流操作规律讲解时:

源设备:

键盘 System.in,硬盘 FileStream,内存 ArrayStream。   //数组流,即ByteArrayStream 

目的设备:

控制台 System.out,硬盘 FileStream,内存 ArrayStream

 

代码示例:

import java.io.*;

class ByteArrayStreamDemo{
	public static void main(String[] args){
		//数据源。
		ByteArrayInputStream bis = 
			new ByteArrayInputStream("ABCDEFG".getBytes());
		
		//数据目的。
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		int by = 0;
		while((by=bis.read())!=-1) {
			bos.write(by);
		}
		System.out.println(bos.size());  //打印缓冲区大小。
		System.out.println(bos.toString());  //以字符串形式打印bos的内容。
		
		//writeTo(outputStream)方法把byte数组输出流中的全部内容,写入到指定输出流中。
	  //bos.writeTo(new FileOutputStream("e:\\ArrayStream.txt"));  
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值