黑马程序员——Java基础---IO流(三)

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------



IO流(三)

一、对象的序列化。

        对象存在于堆内存中,当一个程序运行结束之后,该程序产生的对象就会在堆内存中释放其空间,当我们需要保留这些对象的时候,比如将这些对象存入硬盘之中——对象的序列化,这时就需要用到对象输入和输出流:ObjectInputStream和ObjectOutputStream。

        对象之中会封装一些数据,当使用对象流之后,文件中也就存在了这些封装的数据,当我们再次需要这些对象的时候就可以直接从文件中获取对象。

        它的主要方法主要是writeObject()和readObject()方法,分别读入和写出一个对象。

        注意:对需要写出的对象,那么该对象必须实现Serializable接口,该接口没有抽象方法,这种接口一般叫做标记接口,标记该对象可以被序列化。该类会产生一个serialVersionUID,该标记是由类中的成员计算出来的,用来标示一个类。

package com.itheima;
import java.io.*;
public class ObjectIODemo 
{
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException
	{
		//writeObj();
		readObj();//之所以定义两个函数这是因为这个类设计过来就是为了将对象存储起来。
	}
	public static void readObj() throws FileNotFoundException, IOException, ClassNotFoundException
	{
		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\测试\\text.obj"));
		Studenter s=(Studenter)ois.readObject();//注意它返回的是一个Object对象,这时候serialVersionUID也会检查左边的和右边的是否相等,不相等时会报ClassNotFoundException错
		Studenter t=(Studenter)ois.readObject();
		ois.close();
		System.out.println(s.toString());
		System.out.println(t.toString());
	}
	public static void writeObj() throws FileNotFoundException, IOException
	{
		ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\测试\\text.obj"));
		oos.writeObject(new Studenter("张三",14,201412));
		oos.writeObject(new Studenter("李四",22,201422));
		oos.close();
	}
}
class Studenter implements Serializable
{
	private static final long serialVersionUID = 1L;
	String name;
	transient int age;//transient代表该成员不会被序列化
	double id;
	Studenter(String name,int age,double id)
	{
		this.age=age;
		this.name=name;
		this.id=id;
	}
	public String toString()
	{
		return name+","+age+","+id;
	}
}

二、管道流。

        管道流也是一个输入流PipedInputStream和PipedOutputStream想对应的,所谓管道流就是将输入流和输出流连到一起,它们写出和读入都不需要中间介质介入,它们的使用最好是使用多线程技术来使用,注意Read()方法是一个阻塞方法,当没有可以读取数据该线程就会被阻塞等待数据的到来。

        它们之间接起来的方法是直接调用流对象的connection()方法。

package com.itheima;

import java.io.*;

public class PipedStream 
{
	public static void main(String[] args) throws IOException
	{
		PipedInputStream pi = new PipedInputStream();//两者链接没有目的
		PipedOutputStream pw=new PipedOutputStream();//没有源
		pi.connect(pw);
		Read r = new Read(pi);
		Write w = new Write(pw);
		Thread t1=new Thread(r);
		Thread t2=new Thread(w);
		t1.start();
		t2.start();
	}
}
class Read implements Runnable
{
	PipedInputStream ps;
	Read(PipedInputStream ps)
	{
		this.ps=ps;
	}
	public void run()
	{
		try 
		{
			byte[] b=new byte[1024];
			int count=0;
			count=ps.read(b);
			System.out.println(new String(b,0,count));
			ps.close();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
}
class Write implements Runnable
{
	PipedOutputStream pw;
	Write(PipedOutputStream pw)
	{
		this.pw=pw;
	}
	public void run()
	{
		try 
		{
			byte[] b = "我们来了!我们是最棒的!".getBytes();
			pw.write(b);
			System.out.println("写入成功!");
			pw.close();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}
              注意,一定不要在单线程里面使用管道流,这样会导致死锁!

三、RandomAccessFile

        RandomAccessFile不是IO体系中的子类,因为它直接继承了Object,但是它存在于IO包中,这是因为它是可以读写的类。它的内部封装了一个数组,可以通过指针来对数组的元素进行操作,可以通过getFilePointer()获取指针位置,也可以通过seek方法改变指针位置。

        通过其构造函数可知它只能操作文件(传入的是文件或者文件名)而且操作文件还有模式"rw"代表读写,”r“代表读。

        注意:

        如果模式为只读”r“,则不会创建文件而去读已经存在的文件,若文件不存在,则会抛出异常。

        如果模式为”rw“,文件不存在则会创建文件,文件存在则不会覆盖,会续写。

        该流最大的特点就在于可以获取指针和设置指针,这样可以利用多线程技术来同时对一个文件进行读取或者写入(一个线程读第一个字节数组,第二个线程跳指针到未被读取的下一个字节数组读取,以此类推)。

        对ObjectOutputStream和RandomAccessFile来说,它们共有一种方法 writeInt()这个方法代表一次写入一个int类型整数所代表的字节数——一次写出4个字节,类似的还有writeLong()一次写出8个字节等,想对应的在ObjectInputStream和RandomAccessFile中有readInt()方法,读取4个字节的数据。

package com.itheima;

import java.io.*;

public class RandomAccessFileDemo 
{
	public static void main(String[] args) throws IOException
	{
		//write();
		read();
	}
	public static void read() throws IOException
	{
		RandomAccessFile rafr=new RandomAccessFile("D:\\测试\\Text.txt","r");
		byte[] arr=new byte[4];
		int count=0;
		count=rafr.read(arr);
		String name1 = new String(arr,0,count);
		int age1 = rafr.readInt();//直接读取4个字节然后以int类型返回。
		//rafr.skipBytes(8);
		rafr.seek(8);
		count = rafr.read(arr);
		String name2 = new String(arr,0,count);
		int age2=rafr.readInt();
		System.out.println(name1+","+age1);
		System.out.println(name2+","+age2);
		rafr.close();
	}
	public static void write() throws IOException
	{
		RandomAccessFile rafw=new RandomAccessFile("D:\\测试\\Text.txt","rw");
		rafw.write("张三".getBytes());
		rafw.writeInt(22);//输入一个int整数,以4个字节写出,该方法内部自动编码。
		System.out.println(rafw.getFilePointer());
		rafw.write("李四".getBytes());
		rafw.writeInt(24);
		System.out.println(rafw.getFilePointer());
		rafw.close();
	}
}

四、操作基本数据类型的流对象DataOutputStream和DataInputStream

        这个流主要用来操作基本数据类型,其方法主要有:

        读操作:int num = dis.readInt();//读取4个字节然后返回int类型整数
      boolean b = dis.readBoolean();//读取一个字节,若该字节不是0则返回true,反之返回false
      double d = dis.readDouble();//读取8个字节返回一个Double值

                      String s=dis.readUTF();//将一个UTf-8编码的字符串读入         写操作:dos.writeInt(234);//以四个字节编码写出一个int类型整数
      dos.writeBoolean(true);//以一个字节写出

      dos.writeDouble(9887.543);//以八个字节写出

                      dos.writeUTF("你好");//将表示长度信息的两个字节写入输出流,后跟字符串s 中每个字符的UTF-8表示形式。

package com.itheima;
import java.io.*;
public class DataStreamDemo 
{
	public static void main(String[] args) throws IOException
	{
		//write();
		read();
	}
	public static void read() throws IOException
	{
	    DataInputStream dis = new DataInputStream(new FileInputStream("D:\\测试\\Data.txt"));
	    int num = dis.readInt();//读取4个字节然后返回int类型整数
	    boolean b = dis.readBoolean();//读取一个字节,若该字节不是0则返回true,反之返回false
	    double d = dis.readDouble();//读取8个字节返回一个Double值
            String s=dis.readUTF();//将一个UTf-8编码的字符串读入
            System.out.println(num+","+b+","+d+","+s);
            dis.close();
	}
	public static void write() throws IOException
	{
	    DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\测试\\Data.txt"));
	    dos.writeInt(234);//以四个字节编码写出一个int类型整数
	    dos.writeBoolean(true);//以一个字节写出
	    dos.writeDouble(9887.543);//以八个字节写出
            dos.writeUTF("你好");//将表示长度信息的两个字节写入输出流,后跟字符串 s 中每个字符的UTF-8表示形式。
            dos.close();
	}
}

五、ByteArrayStream

        该流对象主要用于在内存之中对数据进行操作。

        ByteArrayInputStream:在构造过程中接受一个字节数组,这就是它的数据源。

        BytaArrayOutputStream:在构造过程中不需要接受目的,因为该对象内部封装了一个字节数组,这就是它的目的。

        这个流对象就是用字节数组作为源和目的在内存之中进行数据的读取操作。

package com.itheima;
import java.io.*;
public class ByteArrayStreamDemo 
{
	public static void main(String[] args)
	{
		ByteArrayInputStream bais=new ByteArrayInputStream("asugbfiauf".getBytes());
		ByteArrayOutputStream baos= new ByteArrayOutputStream();
		int x=0;
		while((x=bais.read())!=-1)
		{
			baos.write(x);
		}
	}
}
        注意:因为在读写过程中只是在内存中操作,所以它们没有使用系统资源,所以可以不用对流对象进行关闭操作。

六、字符编码和解码

        编码过程:"dauioghfuaf".getBytes();
        解码过程:String(byte[],0,length);




------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值