zoukankan      html  css  js  c++  java
  • IO流__【对象的序列化】【管道流】【RandomAccessFile】【DataStream】【ByteArrayStream等】


    对象的序列化(持久化)


    就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。
    虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给我们提供了一种应该比自己更好的保存对象状态的机制,那就是序列化。
    简单说:把对象转换为字节序列的过程称为对象的序列化
        把字节序列恢复为对象的过程称为对象的反序列化

    操作对象
    ObjectInputStream与ObjectOutputStream(两个类要一起使用)
    被操作的对象需要实现Serializable (标记接口)以启用其序列化功能
    该接口没有方法;没有方法的接口通常称为标记接口
    writeObject();、readObject();操作对象

    示例:通过序列化操作一个Person类

    import java.io.*;
    class  ObjectStreamDemo
    {
    	public static void main(String[] args) throws Exception
    	{
    //		writeObj();
    		readObj();
    	}
    	public static void readObj() throws Exception	//反序列化
    	{
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
    		Person p = (Person)ois.readObject();//类型强转,引用了另一个。java文件的Person类,所以会抛异常ClassNotFoundException
    		System.out.println(p);
    		ois.close();
    	}
    	public static void writeObj() throws IOException	//序列化
    	{
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
    		oos.writeObject(new Person("xiaoqiang",22,"America"));
    		oos.close();
    	}
    }
    Person类

    被操作的对象

    import java.io.*;
    class Person implements Serializable //标记接口
    {
    	public static final long serialVersionUID = 42L;//1,自定义UID
    	private String name;//1,私有化的成员
    	transient int age;//3,修饰符,不会被序列化
    	static String country ="cn";//2,静态成员
    	Person(String name, int age, String country){
    		this.name = name;
    		this.age = age;
    	}
    	public String toString(){	//伪代码,没写set,get
    		return name+" : "+age+" : "+counrty;
    	}
    }

    1,将Person的成员私有化后就不能再被序列化,说明序列号是根据成员获取的
    可以设置UID固定标识:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
    设置后Person的成员即使被私有化也能被序列化
    2,静态的成员不能被私有化,例如静态的成员country序列化修改后依然是cn
    因为序列化操作的是堆内存中的对象,而静态成员随着类加载,存在于栈中的方法区,所以执行不到
    3,如果想让非静态成员不被序列化,就在该成员前面加上transient修饰

    管道流

    PipedInputStream和PipedOutputStream
    一般流的输入输出没有太大关联,而管道流输入输出可以直接进行连接,必须相互连接后创建通信管道;通过结合多线程使用,单线程可能会死锁。

    示例:

    import java.io.*;
    class Read implements Runnable	//管道输入流线程
    {
    	private PipedInputStream in;
    	Read(PipedInputStream in){	//构造函数
    		this.in = in;
    	}
    	public void run(){	//实现run方法
    		try{
    			byte[] buf = new byte[1024];//缓冲数组
    			System.out.println("阻塞...数据读取中...");
    			int len = in.read(buf);		//字节输入流读取方法
    			System.out.println("读到数据,阻塞结束");
    			String s = new String(buf,0,len);//转成字符串
    			System.out.println(s);
    			in.close();
    		}
    		catch (IOException e){
    			throw new RuntimeException("管道流read读取失败!!!");
    		}
    	}
    }
    class Write implements Runnable	//管道输出流线程
    {
    	private PipedOutputStream out;
    	Write(PipedOutputStream out){	//构造函数
    		this.out = out;
    	}
    	public void run(){	//覆盖run方法
    		try{
    			System.out.println("开始写入...等待中。。。");
    			Thread.sleep(3000);
    			out.write("hello Piped !".getBytes());//字节读取流write方法,需要将字符转为字节
    			out.close();
    		}
    		catch (Exception e){
    			throw new RuntimeException("管道流write输出失败");
    		}
    	}
    }
    class PipedStreamDemo
    {
    	public static void main(String[] args) throws IOException
    	{
    		PipedInputStream in = new PipedInputStream();
    		PipedOutputStream out=new PipedOutputStream(in);
    //		in.connect(out);//connect()创建通信管道,也可直接将in传入out构造参数列表
    		new Thread(new Read(in)).start();
    		new Thread(new Write(out)).start();
    	}
    }

    运行结果:


    由运行结果可以看出:管道流输入输出两个线程在执行的过程中,输入流线程如果没有读到输出流的数据,就会一直处于阻塞状态,直到输出流write完毕输入流才开始read。

    如果是单线程,极有可能会线程死锁,所以要和多线程配合使用。

    RandomAccessFile

    随机读写文件
    该类不算是IO体系的子类,直接继承自Object;
    但RandomAccessFile是IO包中成员,具备文件读写功能,能够读写是其内部封装了字节输入流和输出流
    能够随机是因为在内部封装了一个byte[] 数组,通过指针对数组的元素进行操作,同时可以通过getFilePointer获取指针位置,通过seek改变指针位置。seek相当强大

    通过其构造函数可以看出:该类只能操作文件
    而且还有操作文件的模式:只读r,读写rw

    如果模式为r,不会创建文件,而是读取一个已存在的文件,若该文件不存在会抛出异常
    如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖,而是直接在该文件上操作

    示例:

    import java.io.*;
    class RandomAccessFileDemo
    {
    	public static void main(String[] args) throws IOException
    	{
    //		writeFile(1);
    //		readFile(0);
    		writeFile_2(1);
    	}
    	public static void readFile(int x) throws IOException	//随机获取
    	{
    		RandomAccessFile raf = new RandomAccessFile("raf.txt","r");//"r"只读权限
    //		raf.seek(8*x);	//调整对象中指针,一个人的信息为8个字节,可以通过8的倍数来决定取哪个人的资料
    		raf.skipBytes(8*x);//跳过指定的字节数,只能往后跳
    
    		byte[] buf = new byte[4];
    		raf.read(buf);			//一次读取四个字节,因为设置的名字是由2个字符(4个字节)组成
    		String name = new String(buf);//将该字节数组转换成字符串
    		int age = raf.readInt();//直接一次读取四个字节,并转成int型
    
    		sop("name: "+name);
    		sop("age: "+age);
    		raf.close();
    	}
    	public static void writeFile_2(int x)throws IOException		//随机写入
    	{
    		RandomAccessFile raf = new RandomAccessFile("raf.txt","rw");
    		raf.seek(8*x);	//调整指针,直接将信息插入到第五个信息栏,也可对指定位置信息修改(覆盖原有信息)
    		raf.write("王五".getBytes());
    		raf.writeInt(110);
    		raf.close();
    	}
    	public static void writeFile() throws IOException
    	{
    		RandomAccessFile raf = new RandomAccessFile("raf.txt","rw");//"rw"权限,读写
    		raf.write("小强".getBytes());//将字符转成字节
    		raf.writeInt(98);	//write只写int型的最低八位(一个字节),该类提供了writeInt()方法,写入4个字节
    		raf.write("小明".getBytes());
    		raf.writeInt(99);
    		raf.close();
    	}
    	public static void sop(Object obj){
    		System.out.println(obj);
    	}
    }

    RandomAccessFile类具备强大的随机读写功能,可以对数据进行分段录入,如果引入多线程技术,可以大大提高效率,实际应用:P2P多线程下载

    该类要做重点掌握!


    一、专门操作基本数据类型的流对象
    DataInputStream与DataOutputStream

    import java.io.*;
    class DataStreamDemo 
    {
    	public static void main(String[] args) throws IOException
    	{
    //		writeData();
    //		readData();
    //		writeUTFDemo();
    		readUTFDemo();
    	}
    	public static void readUTFDemo()	throws IOException{
    		DataInputStream dis = new DataInputStream(new FileInputStream("utfData.txt"));
    		String s = dis.readUTF();
    		sop(s);
    		dis.close();
    	}
    	public static void writeUTFDemo() throws IOException{	//以 UTF-8 修改版格式写入此 String 的基本数据。
    		DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfData.txt"));
    		dos.writeUTF("小强");
    		dos.close();
    	}
    	public static void readData()	throws IOException{	//读取基本数据类型
    		DataInputStream dis = new DataInputStream(new FileInputStream("Data.txt"));
    		int		n = dis.readInt();
    		boolean b = dis.readBoolean();
    		double  d = dis.readDouble();
    		sop("n= "+n);
    		sop("b= "+b);
    		sop("d= "+d);
    		dis.close();
    	}
    	public static void writeData()	throws IOException{	//写入基本数据类型
    		DataOutputStream dos = new DataOutputStream(new FileOutputStream("Data.txt"));
    		dos.writeInt(22);		//4个字节
    		dos.writeBoolean(true);	//1个字节
    		dos.writeDouble(3.1415926535);//8个字节
    		dos.close();
    	}
    	public static void sop(Object obj){
    		System.out.println(obj);
    	}
    }

    二、用于操作字节数组的流对象

    用流的读写思想操作数组
    ByteArrayInputStream:在构造时需要接受数据源,数据源是一个字节数组
    ByteArrayOutputStream:在构造时不用定义数据目的,因为该对象内部封装了可变长度的字节数组,该数组就是数据目的地。
    因为这两个流对象都操作数组,并没有操作系统资源,所以不用close()关闭

    流操作规律
    源: 键盘System.in、硬盘FileStream、内存ArrayStream
    目的: 控制台System.our、硬盘FileStream、内存ArrayStream
    writeTo(OutputStream out);
    示例:

    import java.io.*;
    class  ByteArrayStream
    {
    	public static void main(String[] args) //操作的是数组,一般不用抛异常
    	{
    		ByteArrayInputStream bais = new ByteArrayInputStream("ABCDEFG".getBytes());//数据源
    		ByteArrayOutputStream baos =new ByteArrayOutputStream();		//数据目的
    		int by = 0;
    		while ((by=bais.read()) !=-1){
    			baos.write(by);
    		}
    		System.out.println(baos.size());		//返回缓冲区大小length长度
    		System.out.println(baos.toString());	//将缓冲区字节
    //		baos.writeTo(new FileOutputStream("a.txt")); //该方法调用了底层资源,会抛异常
    	}

    三、操作字符数组
    CharArrayReader与CharArrayWrite
    四、操作字符串
    StringReader 与 StringWriter

    这两个类与ByteArrayStream类似



  • 相关阅读:
    Unity文件操作路径
    自定义协议封装包头、包体
    完全卸载删除gitlab
    shell脚本报错:syntax error: unexpected end of file
    Shell脚本创建的文件夹末尾有两个问号怎么回事?
    您与此网站之间建立的连接并非完全安全
    linux 查看磁盘文件大小
    mysql连接问题
    Linux查看当前开放的端口
    本地Linux备份服务器[Client]定期备份云服务器[Server]上的文件(下)
  • 原文地址:https://www.cnblogs.com/Joure/p/4337209.html
Copyright © 2011-2022 走看看