IO中的功能流对象


一、综述

IO中的功能流对象为其他输出流添加了新功能,能够方便解决特定的问题。

   1、打印流

PrintStream与PrintWriter
可以直接操作输入流和文件

   2、序列流

SequenceInputStream
对多个流进行合并


   3、操作对象

ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable


   4、RandomAccessFile

随机访问文件,自身具备读写的方法。
通过seek(int x)来达到随机访问


   5、管道流

PipedInputStream 与PipedOutputStream


   6、操作基本数据类型

DataInputStream与DataOutputStream


   7、操作字节数组

ByteArrayInputStream与ByteArrayOutputStream

   8、操作字符数组

CharArrayInputStream与CharArrayOutputStream
   

   9、操作字符串

       StringReader与StringWriter


二、详细介绍

1、打印流---输出流

PrintStream(字节流) PrintWriter(字符流)
特点:
   1,打印
   2,不抛异常
打印的数据汇(目的)
   File对象、字符串路径、字节输出流
解决的问题
   方便地打印各种数据值表示形式,它的打印方法可以保证数值的表现形式不变。

实例
public static void main() throws IOException {
	    File dir = new File("tempfile");
	    if(!dir.exists()){
		dir.mkdir();
	    }
	    //PrintStream中特有的方法 print()
	    //1,创建PrintStream对象,目的就定为文件。
	    PrintStream out = new PrintStream(tempfile\\print.txt);

	    //2,将数据打印到文件中
	    out.write(97);//结果:a,因为字节流对象的write方法一次只写出一个字节,也就是将一个整数的最低8位写出。
	    out.write("97".getBytes());//结果:97
	    out.print(97); //结果:97	保证数值的表现形式,其实原理就是将数值转成字符串。
	    out.close();
	}
PrintWriter:一样具备打印功能。
打印的目的:File对象、字符串路径、字节输出流、字符输出流。
实例
/**
	 *	读取键盘录入,将数据转成大写显示在屏幕上。
	 */
	public static void main() throws IOException {
	    //1,键盘录入
	    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
	    //2,定义目的,可以使用BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
	    PrintWriter pw = new PrintWriter(System.out,true);	//对println方法可以实现自动刷新。
	    //读一行写一行。键盘输入一定要定义结束标记
	    String line = null;
	    while((line = bufr.readLine())!=null){	//readLine()是阻塞式方法
		if("over".equal(line)){
		    break;
		}
		pw.println(line.toUpperCase());
		//pw.flush();
	    }
	    pw.close();
	    //bufr.close();不需要关闭键盘录入这种标准输入流,一旦关闭后面就获取不到了。
	}

 2、序列流

特点:
流对象的有序排列
解决问题:
将多个输入流合并成一个输入流。将多个源合并成一个源。对于多个源的操作会变得简单。
功能:
特殊之处在构造函数上,一初始化就合并了多个流进来。
使用场景之一:
对多个文件进行数据的合并,多个源对应一个目的。

实例:
/**
	 *	将多个文件合并成一个文件。
	 */
	public static void main(String[] args) throws IOException {
	    ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
	    //添加多个输出流对象,和指定的具体文件相关联
	    for(int x = 1;x<=3;x++){
		al.add(new FileInputStream("tempfile\\"+x+".txt"));
	    }

	    //使用Collections工具类中的方法,将ArrayList转成Enumeration
	    Enumeration<FileInputStream> en = Collections.enumeration(al);
	    //创建序列流对象,需要传递Enumeration
	    SequenceInputStream sis = new SequenceInputStream(en);
	    //创建目的,文件
	    FileOutputStream fos = new FileOutputStream("tempfile\\4.txt");

	    //频繁读写操作
	    //1,创建缓冲区
	    byte[] buf = new byte[1024];
	    int len = 0;
	    while((len=sis.read(buf))!=-1){
		fos.write(buf,0,len);
	    }

	    //关闭流
	    fos.close();
	    sis.close();
	}

3、操作对象

用于操作对象的流对象。对象要序列化
ObjectOutputStream与ObjectInputStream
特点:用于操作对象
解决问题:对象存储到硬盘中
writeObject(Object obj):将指定的对象写入 ObjectOutputStream。对象的类、类的签名,以及类及其所有超类型的 非瞬态 和 非静态 字段的值都将被写入
序列化接口  public interface Serializable
类通过实现java.io.Serializable接口以启用其序列化功能。实现此接口的类可以使其序列化(writeObj方法)和反序列化(readObj方法)。
序列化接口没有方法和字段,仅用于标识可序列化的语义,也称为标记接口。

实例
/**
	 *	将一个对象存储到持久化的设备上
	 *	首先创建Person类 属性,name age  
	 */
	 pubilc static void writeObj() throws IOException{					对象的序列化
	    //1,明确存储对象的文件
	    FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
	    //2,给操作文件对象加入写对象功能
	    ObjectOutputStream oos = new ObjectOutputStream(fos);
	    //3,调用写对象的方法
	    oos.writeObject(new Person("lisi",20));
	 }

	 /**
	 *	从持久化的设备上读取一个对象
	 */
	 public static void readObj() throws IOException ,ClassNotFountException {		对象的反序列化
	    //建立读取流对象关联存储了对象的文件
	     FileInputStream fis = new FileInputStream("tempfile\\obj.object");
	    //2,建立用于读取对象的功能对象
	     ObjectInputStream ois = new ObjectInputStream(fis);

	     Person p = (Person)ois.readObject();
	     System.out.println(p.toString());
	 }

 4、序列化

概述:
 
实体类的对象如果需要序列化,就需要实现Serializable标记接口。
该接口给需要序列化的类提供了一个序列版本号。SerialVersionUID,
该版本号的目的在于验证序列化的对象与对应类是否版本匹配。


异常
InvolidClassException: 当Serialization运行时检测到某个类具有以下问题之一时抛出。
   1,该类的序列版本号与从流中读取的类描述符的版本号不匹配。
   2,该类包含未知数据类型
   3,该类没有可访问的无参构造函数


序列版本号:
   1,序列版本号作用
序列化运行时使用一个称为serialVersionUID 的版本号与每个可序列化类相关联。可序列化类通过声明名为serialVersionUID 的字段(该字段
必须是静态的(static),最终(final)的,long类型),显式声明其serialVersionUID。


   2,为什么必须显式声明序列版本号
如果可序列化类未显式声明serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认的serialVersionUID。
强烈建议所有可序列化类都显式声明serialVersionUID的值。原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,
根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException

 5、瞬态关键字

transient : 内存中存在,不需要持久化出去。瞬间的,短暂的。能够防止一些字段被序列化。

 6、RandomAccessFile

特点:
   1,只能操作文件
   2,既能读,又能写
   3,维护了一个byte数组。内部定义了字节流的读取和写入
   4,通过对指针的操作可以实现对文件任意位置的读取和写入


功能:
   getFilePointer  seek 用于操作文件指针的方法


构造方法:
   RandomAccessFile(File file , String mode);
   RandomAccessFile(String fileName , String mode);
参数:mode 指定用以打开文件的访问模式
"r" 只读
"rw" 读写,如果该文件不存在,创建

实例:
 /**
	 *	随机写入数据
	 */
	 public static void writeFile() throws IOException {
	    //1,创建一个随机访问文件的对象,文件不存在,则创建,存在,不创建也不覆盖
	    RandomAccessFile raf = new RandomAccessFile("tempfile\\random.txt" , "rw");

	    //2,写入姓名和年龄
	    raf.write("张三".getBytes());
	    raf.writeInt(97);	//保证整数的字节原样性
	    raf.write("王武".getBytes());
	    raf.writeInt(98);	//保证整数的字节原样性
	    //3,随机写入
	    raf.seek(8);//设置指针的位置
	    raf.write("李四".getBytes());
	    raf.writeInt(99);	//保证整数的字节原样性
	    
	    System.out.println(raf.getFilePointer());
	 }

 7、管道流

特点:
   1,读取管道和写入管道可以连接
   2,需要使用多线程技术,单线程容易死锁
功能:
   connect()  连接两个流

实例:
public static void main(String[] args) throws IOException {
	    //创建管道流对象
	    PipedInputStream pis = new PipedInputStream();
	    PipedOutputStream pos = new PipedOutputStream();

	    //将两个流连接上
	    pis.connect(pos);

	    new Thread(new Input(pis)).start();
	    new Thread(new Output(pos)).start();
	}

	//定义输入任务
	Class Input implements Runnable {
	    private PipedInputStream pis;
	    public Input(PipedInputStream pis) {
	        super();
		this.pis = pis;
	    }
	    @Override
	    public void run() {
	        byte[] buf = new byte[1024];
		int len;
		try {
		    len = pis.read(buf);
		    String str = new String(buf,0,len);
		    System.out.println(str);
		    pis.close();
		} catch (IOException e) {
		    e.printStackTrace();
		}
	    }
	}
	//定义输出任务
	Class Output implements Runnable {
	    private PipedOutputStream pos;
	    public Output(PipedOutputStream pos) {
	        super();
		this.pos = pos;
	    }
	    @Override
	    public void run() {
		//通过write写方法完成
		try{
		    pos.write("管道输出流运行".getBytes());
		    pos.close();
		} catch (IOException e) {
		    e.printStackTrace();
		}
	    }
	}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值