ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。使用标准机制按需加载类。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。
还可以使用 DataOutput 中的适当方法将基本数据类型写入流中。还可以使用 writeUTF 方法写入字符串。
对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。可使用引用共享机制对单个对象的多个引用进行编码,这样即可将对象的图形恢复为最初写入它们时的形状。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectStreamDemo { public static void main(String [] args)throws Exception{ writeObj(); readObj(); } public static void readObj()throws Exception{//这里抛的是Exception,而不是IOException,因为readObject() ObjectInputStream ois=new ObjectInputStream(new FileInputStream("c:\\obj.txt")); Person p=(Person) ois.readObject(); System.out.println(p); ois.close(); } public static void writeObj()throws IOException{ ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("c:\\obj.txt"));//一般在实际应用当中,后缀名存的都是.object oos.writeObject(new Person("wangda",39,"USA"));//写完后就存在硬盘上,打印的结果还是cn,原因见person表 oos.close(); } }
某个要序列化的对象不能实现,java.io.scrialable接口
Serializable这是一个接口
对象被存到文件里了,就被持久化
当某一个类被修改后,这个时候序列号就发生了改变,我们再对该文件进行读取时,就会发生异常。序列号就是根据成员变量来产生的。
import java.io.Serializable; public class Person implements Serializable {//实现Serializable public static final long serialVersionUID =421;//这个uid就是指定了该类的序列号,下面改动类的方法属性都能使以后可以读写 String name; transient int age;//对于非静态的成员,也不想将其序列化的话,可以加上关键字修饰。虽然还在堆内存当中,但是还是不能被序列化 static String country="cn";//静态是不能被序列化的,它在方法学里面。而对象是在堆里面。能把堆里面的数据序列化,而不能把其他里面的东西序列化 Person(String name,int age,String country){ this.name=name; this.age=age; this.country=country; } public String toString(){ return name+":"+age+":"+country; } }
从这个管道写,从这个管道就可以读到,两根管子可以对接到一起。
管道输入流应该连接到管道输出流,管道输入流提供要写入管道输出流的所有数据字节,通常:数据由某个线程从PipedInputStream取,并由其他线程将其写入到相应的PipedOutPutStream,不建议对这两个对象尝试使用单个线程,因为这样可能死锁,管道输入流包含一个缓冲区,可在缓冲区限定的范围将读操作和写操作分开。如果向连接管道流输出流提供的数据字节的线程不再存在,则认为该管道流已损坏。涉及多线程技术的IO流。
import java.io.PipedInputStream; import java.io.PipedOutputStream; //使用多线程,一个是读,一个是写 class Read implements Runnable{ private PipedInputStream in; Read(PipedInputStream in) { this.in=in; } public void run(){ try { System.out.println("读取前..没有数据阻塞"); byte[] buf=new byte[1024]; int len=in.read(); System.out.println("读取后..阻塞结束"); String s=new String(buf,0,len);//把int转化成字符串 System.out.println(s);//打印管道流里面读取到的数据 in.close(); } catch (Exception e) { throw new RuntimeException("管道读取流失败"); } } } class Write implements Runnable { private PipedOutputStream out; Write(PipedOutputStream out){ this.out=out; } public void run() { try { System.out.println("开始写入数据,等待2s.."); Thread.sleep(2000); out.write("zheshishenme".getBytes()); out.close(); } catch (Exception e) { throw new RuntimeException("管道输出流失败"); } } } public class PipedStream { public static void main(String [] args) throws Exception{ PipedInputStream in=new PipedInputStream();//管道读取流 PipedOutputStream out=new PipedOutputStream();//管道输出流 in.connect(out);//把这两个流给接上 Read r=new Read(in); Write w=new Write(out); new Thread(r).start();//这两个线程没有先后顺序,是随机性的 new Thread(w).start(); } }
DataOutputStream:
数据输出流允许应用程序以适当方式将基本 Java数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
DataInputStream:
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责。
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 记事本显示的是字符,它对应查字符编码表 * @author hjl * */ public class DataStream { public static void main(String [] args) throws IOException{ writeData(); readData(); readUTFDemo(); writeUTFDemo(); } public static void readUTFDemo()throws IOException{ DataInputStream dis=new DataInputStream(new FileInputStream("uftdate.txt")); String s=dis.readUTF(); System.out.println(s); dis.close(); } public static void writeUTFDemo() throws IOException{ DataOutputStream dos=new DataOutputStream(new FileOutputStream("uftdate.txt")); dos.writeUTF("你好"); dos.close(); } public static void readData() throws IOException{ DataInputStream dis=new DataInputStream(new FileInputStream("data.txt")); int num=dis.readInt(); boolean b=dis.readBoolean(); double d=dis.readDouble(); System.out.println("num="+num); System.out.println("b="+b); System.out.print("d="+d); } public static void writeData() throws IOException{ DataOutputStream dos=new DataOutputStream(new FileOutputStream("data.txt")); dos.writeInt(234); dos.writeBoolean(true); dos.writeDouble(9888.90877); } }
RandomAccessFile
此类的实例却支持对随机访部文件的读取和写入。随机访问文件的行为类似存储在文件系统中的大型byte数组,存在指向该隐含数组的光标或索引,称为文件指针,输入操作从文件指针开始读取字节,并随着对字节的读取前移此文件指针。如果随机访问文件以读取、写入模式创建,则输出操作也可以,输出操作从文件指针开始写入字节,并随着对字节的写入面前移此文件指针。写入隐含数组的当前未尾之后的输出操作导致该数组扩展,该 文件指针可以通过getFilePointer,并通过seek方法设置。
该类不是算是IO体系中子类
而是直接接继承自Object.
但是它是IO包中成员,因为它具备读和写功能,内部封装了了一个数组,而且通过指针对数组元素进行操作。同时可以通过Seek改变指针的位置
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
通过调节指针来取数据。随机访问文件
而且操作文件还有模式:只读r,读写等。
如果模式为只读r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常
如果模式为rw,而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖。
import java.io.*; /* RandomAccessFile 该类不是算是IO体系中子类。 而是直接继承自Object。 但是它是IO包中成员。因为它具备读和写功能。 内部封装了一个数组,而且通过指针对数组的元素进行操作。 可以通过getFilePointer获取指针位置, 同时可以通过seek改变指针的位置。 其实完成读写的原理就是内部封装了字节输入流和输出流。 通过构造函数可以看出,该类只能操作文件。 而且操作文件还有模式:只读r,,读写rw等。 如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。 如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。 */ class RandomAccessFileDemo { public static void main(String[] args) throws IOException { writeFile_2(); readFile(); } public static void readFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //调整对象中指针。 //raf.seek(8*1); //跳过指定的字节数 raf.skipBytes(8); 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("ran.txt","rw"); raf.seek(8*0); raf.write("周期".getBytes()); raf.writeInt(103); raf.close(); } public static void writeFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.write("李四".getBytes()); raf.writeInt(97); raf.write("王五".getBytes()); raf.writeInt(99); raf.close(); } }
DataIntputStream
DataOutputStream:创建一个新的数据输出流,将数据写入指定的基础输出流。
这两个流可以用于操作基本数据类型的数据的流对象。
用于操作字节数组的流对象
ByteArrayInputStream
ByteArrayOutputStream
因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭。
用于操作字节数组的流对象。
ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭。
在流操作规律讲解时:
源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。
用流的读写思想来操作数据。
import java.io.*; class ByteArrayStream { public static void main(String[] args) { //数据源。 ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".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(new FileOutputStream("a.txt")); } }
IO包中的其他类。
操作基本数据类型
DataInputStream 与DataOutputStream
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数组
charArrayReader与CharArrayWrite
操作字符串
StringReader与StringWriter
这些原理都是一样的。找到源和目的,
append(添加);