IO流(四)

 IO 中的其他内容

  一.对象的序列化

    ObjectInputStream(InputStream in)

    ObjectOutputStream(OutputStream out)

    将对象持久化,保存到硬盘,它必须实现Serializable接口。Serializable接口中没有方法。这样的接口叫做标记接口。其原理就是给实现这个接口的类加一个ID值。这个ID值是根据成员生成的。

    如果,我们在将对象写入硬盘后,因为某些原因修改了这个类,此时再去读硬盘上的对象,就会报异常。这就是因为类发生了改变,从而ID值发生了改变。

  

  将对象写在本地硬盘中

public static void writeObj() throws Exception
    {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
        
        Person p = new Person("lisi",32);
        
        oos.writeObject(p);
        
        System.out.println("写入对象完成...");
        
        oos.close();
    }

  读取本地硬盘中的对象

public static void readObj() throws Exception
    {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
        
        Person p1 = (Person)ois.readObject();
        
        System.out.println("读取对象完成...");
        System.out.println(p1);
        ois.close();
    }

其中Person类的源码:

import java.io.*;

class Person implements Serializable
{    
  //public static final long serialVersionUID = 42L
  
private String name;//人名 private Integer age;//年龄 //测试ID是否改变 //private String contry; public Person(String name,Integer age) { this.name = name; this.age = age; } public String toString() { return name+":"+age; } }

    我们可以测试其ID值是否改变,以及改变对读写对象的影响。

    首先,将ID值写死,我们将对象写入文本中,然后改变Person类,并且编译它,再去读去文本中的对象,此时不会报异常。

    然后,当我们把写死的ID值注释掉,再进行重复操作。此时,就会报异常。(InvalidClassException)

  注:静态的成员是不能被序列化的。(原因:它只能序列化堆内存中的数据,而不能序列化其他的)

  注:如果成员被 transient 修饰,也不会被序列化。

  

  二.  管道流

       PipedInputStream

    PipedOutputStream

      管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用      单个线程,因为这样可能死锁线程。

 

    构造函数:PipedInputStream();

         PipedInputStream(PipedOutputStream out);

         PipedOutputStream();

         PipedOutputStream(PipedInputStream in);

    如果使用了空构造函数,那么我们要使用connect()方法,将管道输入流和管道输出流连接起来。

 示例:

public static void demo2() throws Exception
    {
        PipedInputStream pis = new PipedInputStream();
        PipedOutputStream pos = new PipedOutputStream();
        pis.connect(pos);
        
        WritePip wp = new WritePip(pos);
        ReadPip rp = new ReadPip(pis);
        
        new Thread(wp).start();
        new Thread(rp).start();
    }

 

WritePip类:

class WritePip implements Runnable
{
    private PipedOutputStream pos;
    public WritePip(PipedOutputStream pos)
    {
        this.pos = pos;
    }
    
    public void run()
    {
        try{
            System.out.println("开始写入数据...");
            Thread.sleep(5000);
            pos.write("管道已经建立...".getBytes());
            System.out.println("数据写入完毕...");
            
            pos.close();
        }catch(Exception e){
            throw new RuntimeException("数据写入失败...");
        }
    }
}

 

ReadPip  类

class ReadPip implements Runnable
{
    private PipedInputStream pis;
    public ReadPip(PipedInputStream pis)
    {
        this.pis = pis;
    }
    
    public void run()
    {
        try{
            byte[] buff = new byte[1024];
            
            System.out.println("开始读取数据...");
            int len = pis.read(buff);
            System.out.println("读取数据完毕...");
            System.out.println("==================");
            
            System.out.println(new String(buff,0,len));
            
            pis.close();
        }catch(Exception e){
            throw new RuntimeException("读取输入失败...");
        }
    }
}

 

  三.RandomAccessFile

    虽然这个也是IO流,但是这个很特殊,它是一个自成派系的,继承于Object,并且它可以写文件,也可以读文件。

    随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。

 

    3.1 创建对象。

      构造函数:RandomAccessFile(String filename,String mode)

           RandomAccessFile(FIle filename,String mode)

      注:这里就有一个缺陷,那就是只能操作文件。

      mode:  访问文件的模式

        "r"  只读。

        "rw"  读写。

        "rws"  读写,并且文件的内容或元数据同步更新到底层设备。

        "rwd"  读写,并且文件的内容同步更新到底层设备。

      :如果,mode 的值为 "r " 时,却调用write方法,就会报异常。

      :当mode 的值为 "rw" ,调用write方法,如果文件不存在就会创建一个文件,如果文件存在,就不会覆盖掉原来的方法。写入数据:

public static void write() throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("raf.txt","rw");
        
        raf.write("历史".getBytes());
        
        raf.close();
     }

 读取数据:

public static void read() throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("raf.txt","r");
        
        byte[] buff = new byte[4];
        int len = raf.read(buff);
        System.out.println("len = "+len);
        
        System.out.println(new String(buff,0,len));
        
    }

   注: write(int i)  这个方法,是将   i   的最后8位写进去了,而不是,将整个32位写入数据了。如果要将整个32 位写入数据中,需要使用 writeInt(int i) 方法。

  

  3.2 其中的特殊方法。

    设置指针。从什么位置开始写入数据或读取数据。

    seek(long n);

    skipBytes(int n)

    写入数据示例:

public static void write_2() throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("raf.txt","rw");
        
        raf.seek(4);
        raf.write("哈哈".getBytes());
        
        raf.close();
    }

 读取示例:

public static void read_2() throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("raf.txt","r");
        
        raf.seek(4);
        
        byte[] buff = new byte[4];
        int len = raf.read(buff);
        
        System.out.println(new String(buff,0,len));
    }

  设置了指针的偏移量之后,就是从偏移后的位置开始读写。但是指针可以随意设置。而另外一个方法skipBytes(int n),只能往后设置。

  作用:一般的下载软件的多线程下载原理就是这样的。

 

四.DataStream (操作基本数据类型的流)

  有可以写入或读取基本数据的方法。

  特殊:writeUTF(String str);  这个方法是使用修改版的UTF编码。用这个方法写入的数据,只能用与之对应的readUTF 方法读取。

五.ByteArrayStream(操作数组的流)

  ByteArrayInputStream包含一个内部缓冲区,在构造的时候需要一个数据源,而且数据源是一个数组,

  ByteArrayOutputStream 在构造的时候不需要定义数据目的地,因为其内部封装了一个可变长度的数组。

  这两个流都是操作的数组,没有操作系统底层资源的,所以不用 close,就算close了,也可以继续操作这个流。

 

  补充:

    源设备:    键盘:System.in  硬盘:FileStream  内存:ArrayStream

    目的设备 控制台:System.out  键盘:FileStream  内存:ArrayStream

  可以使用 toByteArray() ,toString() 获取数据。

示例:

public static void demo()
    {
        ByteArrayInputStream bais = new ByteArrayInputStream("哈哈哈".getBytes());
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        int len = 0;
        while((len=bais.read())!=-1)
        {
            baos.write(len);
        }
        
        System.out.println(baos.size());
        System.out.println(baos.toString());
    }

 

转载于:https://www.cnblogs.com/alwaysJP/p/8094940.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值