您的位置:首页 > 职场人生

黑马程序员_IO流四(对象的序列化,管道流,RandomAccessFile,DataStream,ByteArrayStream)

2013-05-22 00:25 706 查看
---------android培训java培训、期待与您交流!---------

一.对象的序列化

1.OutPutStream ---> 类 ObjectOutputStream(java,io包)

1)ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。

可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。

如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,

编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

2)构造方法摘要

<1>protected ObjectOutputStream()

为完全重新实现 ObjectOutputStream 的子类提供一种方法,

让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据。

<2>ObjectOutputStream(OutputStream out)

创建写入指定 OutputStream 的 ObjectOutputStream。

3)特有方法:

<1>void writeObject(Object obj)

将指定的对象写入 ObjectOutputStream。

<2>void writeInt(int val)

写入一个 32 位的 int 值。

2.InputStream ---> 类 ObjectInputStream (java.io包)

1)ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream

一起使用时 可以为应用程序提供对对象图形的持久存储

ObjectInputStream 用于恢复那些以前序列化的对象。

其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

objectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。

使用标准机制按需加载类。

只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。

2)构造方法摘要

protected ObjectInputStream()

为完全重新实现 ObjectInputStream 的子类提供一种方式,

让它不必分配仅由 ObjectInputStream 的实现使用 的私有数据。

ObjectInputStream(InputStream in)

创建从指定 InputStream 读取的 ObjectInputStream。

3)特有方法:

Object readObject() 从 ObjectInputStream 读取对象。

3. 接口 Serializable (java.io包)

1)public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。

未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

序列化接口没有方法或字段,仅用于标识可序列化的语义。

2)可序列化类可以通过声明名为 "serialVersionUID" 的字段

(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,

则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值.

4.注意:

1)实现了Serializable接口的类都会有一个UID的序列号(java自动生成)标示,类改变,序列号也会改变。

要想改变类而不改变序列号,可手动给类定义一个固定的序列号(方便序列化)。方法就是:

显式声明其自己的 serialVersionUID: public static final long serialVersionUID = 42L;

2)静态变量不能被序列化,因为静态在方法区中,而对象是在堆里。序列化是对堆中的对象进行的。

3)如果对堆中的成员也不想进行序列的化的话。只需加上关键字transient修饰就可以了。

二.管道流

1.InputStream ---> PipedInputStream类(java.io包)

1)管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,

数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。

不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,

可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,

则认为该管道已损坏。

2)构造方法摘要

<1>PipedInputStream()

创建尚未连接的 PipedInputStream。

<2>PipedInputStream(int pipeSize)

创建一个尚未连接的 PipedInputStream,并对管道缓冲区使用指定的管道大小。

<3>PipedInputStream(PipedOutputStream src)

创建 PipedInputStream,使其连接到管道输出流 src。

<4>PipedInputStream(PipedOutputStream src, int pipeSize)

创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。

3)特有方法:

void connect(PipedOutputStream src)

使此管道输入流连接到管道输出流 src。

2.OutputStream ---> PipedOutputStream类(java.io包)

1)可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,

数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。

不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。

如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,

则该管道被视为处于 毁坏 状态

2)构造方法摘要

<1>PipedOutputStream()

创建尚未连接到管道输入流的管道输出流。

<2>PipedOutputStream(PipedInputStream snk)

创建连接到指定管道输入流的管道输出流。

3)特有方法:

void connect(PipedInputStream snk)
将此管道输出流连接到接收者。

3.例题:

class  PipedStreamDemo
{
public static void main(String[] args)
{
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos);
new Thread(new Reader(pis)).start();
new Thread(new Writer(pos)).start();

}
}
class Reader implements Runnable
{
private PipedInputStream pis;
Reader(PipedInputStream pis)
{
this.pis = pis;
}
public void run()
{
try
{
byte[] buf = new byte[1024];
int len = pis.read(buf);
System.out.println(new String(buf,0,len));
}
catch (IOException e)
{
e.printStackTrace();
}

}
}
class Write implements Runnable
{
private PipedOutputStream pos ;
Write(PipedOutputStream pos)
{
this.pos = pos;
}
public void run()
{
try
{
pos.write("PipedStrea lai le!".getBytes());
pos.close();
}
catch (IOException e)
{
e.printStackTrace();
}

}
}


三.RandomAccessFile

1. RandomAccessFile类:

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

该类不算是IO体系中的子类。

而是直接继承Object.

但是它是IO包中成员。因为它具备读写功能。

内部封装了一个数组。而且通过指针对数组的元素进行操作。

可以通过getFilePointer获取指针位置。
同时可以通过seek改变指针的位置。

实现完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件。

而且操作文件还有模式:只读r,读写rw等。

如果模式为只读r.不会创建文件。会去读取一个已存在文件。如果该文件不存在。则会出现异常。

如果模式为rw.操作的文件不存在,会自动创建,如果存在,则不会覆盖。

2.Object ----> RandomAccessFile类:

1)此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的

一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,

并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;

输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。

写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,

并通过 seek 方法设置。

2)构造方法摘要

<1>RandomAccessFile(File file, String mode)

创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

<2>RandomAccessFile(String name, String mode)

创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

3)特有方法:

<1>void writeInt(int v)

按四个字节将 int 写入该文件,先写高字节。

<2>int skipBytes(int n)

尝试跳过输入的 n 个字节以丢弃跳过的字节。

<3>void write(byte[] b)

将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。

<4>void write(int b)

向此文件写入指定的字节。

<5>void writeBoolean(boolean v)

按单字节值将 boolean 写入该文件。

<6>void writeByte(int v)

按单字节值将 byte 写入该文件。

<7>void writeBytes(String s)

按字节序列将该字符串写入该文件。

<8>void seek(long pos)

设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。

<9>int readInt()

从此文件读取一个有符号的 32 位整数。

<10>String readLine()

从此文件读取文本的下一行。

<11>long getFilePointer()

返回此文件中的当前偏移量。

<12>long length()

返回此文件的长度。

<13>int read()

从此文件中读取一个数据字节。

<14>int read(byte[] b)

将最多 b.length 个数据字节从此文件读入 byte 数组。

<15>void close()

关闭此随机访问文件流并释放与该流关联的所有系统资源。

四.基本数据类型的数据的流对象

1.DataInputStream与DataOutputStream

1)数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,

应用程序可以使用数据输入流将数据读入。

2)构造方法摘要

DataOutputStream(OutputStream out)

创建一个新的数据输出流,将数据写入指定基础输出流。

3)特有方法:

void writeBoolean(boolean v)

将一个 boolean 值以 1-byte 值形式写入基础输出流。

void writeDouble(double v)

使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,

然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。

void writeInt(int v)

将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。

void writeUTF(String str)
以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。

2.InputStream ---> DataInputStream类

1)数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。

应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。

DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责

2)构造方法摘要

DataInputStream(InputStream in)

使用指定的底层 InputStream 创建一个 DataInputStream。

3)特有方法:

boolean readBoolean()

参见 DataInput 的 readBoolean 方法的常规协定。

double readDouble()

参见 DataInput 的 readDouble 方法的常规协定。

int readInt()

参见 DataInput 的 readInt 方法的常规协定。

String readUTF()

参见 DataInput 的 readUTF 方法的常规协定。

3.注意UTF与UTF-8的差别:
UTF-8是6个字节的两字。而UTF是8个字节的两字。

五.ByteArrayStream

1.其它流

1)操作基本数据类型:

DataInputStream与DataOutputStream

2)操作字节数组

ByteArrayInputStream与ByteArrayOutputStream

3)操作字符数组

CharArrayReader与CharArrayWrite

4)操作字符串

StringReader与StringWriter

2.InputStream ---> ByteArrayInputStream类

1)ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。

内部计数器跟踪 read 方法要提供的下一个字节。

2)构造方法摘要

ByteArrayInputStream(byte[] buf)

创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

ByteArrayInputStream(byte[] buf, int offset, int length)

创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

3)方法摘要

int available()

返回可从此输入流读取(或跳过)的剩余字节数。

int read()

从此输入流中读取下一个数据字节。

int read(byte[] b, int off, int len)

将最多 len 个数据字节从此输入流读入 byte 数组。

long skip(long n)

从此输入流中跳过 n 个输入字节。

3.OutputStream ---> ByteArrayOutputStream类

1)此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。

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

关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。

2)构造方法摘要

ByteArrayOutputStream()

创建一个新的 byte 数组输出流。

ByteArrayOutputStream(int size)

创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。

3)方法摘要

void close()

关闭 ByteArrayOutputStream 无效。

void write(byte[] b, int off, int len)

将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流。

void write(int b)

将指定的字节写入此 byte 数组输出流。

void writeTo(OutputStream out)

将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。

int size()

返回缓冲区的当前大小。

byte[] toByteArray()

创建一个新分配的 byte 数组。

String toString()

使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。

六.转换流

1.字符编码


字符流的出现为了方便操作字符。

更重要的是加入了编码转换。

通过子类转换流来完成。

InputStreamReader

OutputStreamWriter

在两个对象进行构造的时候可以加入字符集。

2常见的编码表

1)ASCII:美国标准信息交换码。

用一个字节的7位可以表示。

2)ISO8859-1:拉丁码表,欧洲码表。

用一个字节的8位表示。

3)GB2312:中国的中文编码表。

4)GBK:中国的中文编码表升级,融合了更多的中文文字符号。

5)Unicode:国际标准码,融合了多种文字。

所有文字都用两个字节来表示,Java语言使用的就是unicode.
6)UTF-8:最多用三个字节来表示一个字符。

3.转换流的编码应用

1)可以将字符以指定编码格式存储。

2)可以对文本数据指定编码格式来解读。

3)指定编码表的动作由构造函数完成。

4 编码解码

1.编码:字符串变成字节数组

解码:字节数组变成字符串。

String --> byte[]: str.getBytes(charsetName);

byte[] ---> String : new String(byte[],charsetName);

2.用到的方法:

1)String类(java.lang包)

<1>构造方法摘要

String()

初始化一个新创建的 String 对象,使其表示一个空字符序列。

String(byte[] bytes)

通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

String(byte[] bytes, Charset charset)

通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。

<2>特有方法:

byte[] getBytes()

使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

byte[] getBytes(Charset charset)

使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。

2)Arrays类(java.util包)

static String toString(byte[] a)

返回指定数组内容的字符串表示形式。

static String toString(Object[] a)

返回指定数组内容的字符串表示形式。

5.代码示例:

String s = "你好";

//String s = "哈哈"

byte[] b1 = s.getBytes("gbk");

Sytem.out.println(Arrays.toString(b1));

String s1 = new String(b1,"iso8859-1");

//String s1 = new String(b1,"utf-8");//因为utf-8和gbk都可以解码中文字符,所以出现乱码。故常用iso8859-1

System.out.println("s1="+s1);

//对s1进行iso8859-1编码。

byte[] b2 = s1.getBytes("iso8859-1");

//byte[] b2 = s1.getBytes("utf-8");

System.out.println(Arrays.toString(b2));

String s2 = new String(b2,"gbk");

System.out.println("s2="+s2);

七.IO练习题

/*
有五个学生,每个学生有3门课的成绩,
从键盘输入以上数据(包括姓名,三门课成绩),
输入的格式:如:zhangsan,30,40,60计算出总成绩,
并把学生的信息和计算出的总分高低顺序存放在磁盘文件"stud.txt"中。

1,描述学生对象
2,定义一个可操作学生对象的工具类。

思路:
1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
2,因为学生有很多,那么就需要存储,使用到集合,因为要对学生的总分排序。
所以可以使用TreeSet.
3,将集合的信息写入到一个文件中。
*/

class Student implements Comparable<Student>
{
private String name;
private int cn,en,ma,sum;
Student(String name,int cn,int en,int ma)
{
this.name = name;
this.cn = cn;
this.en = en;
this.ma = ma;
this.sum = cn+en+ma;
}

public String getName()
{
return name;
}
public int getSum()
{
return  sum;
}
public int compare(Student s)
{
int num = new Integer(this.sum).compareTo(new Integer(s.sum))
if(num==0)
return this.name.compareTo(s.name)
return num;
}
public int hashCode()
{
return name.hashCode()+age*23;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("类型错误");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age== s.age;
}

public String toString()
{
return name+en+cn+ma;
}
}

class StudentTool
{
public static Set<Student> getStudents{
BufferedReader bufr =
new BuffereReader(new InputStreamReader(System.in));
TreeSet<Student> students = new TreeSet<Student>();

String line = null;
while((line = bufr.readLine())!= null)
{
if("over".equals(line))
break;
String[] str = line.split(",");
Student stu  = new Student(str[0],
Integer.parseInt(str[1]);
Integer.parseInt(str[2]);
Integer.parseInt(str[3]);

students.add(stu);
}
bufr.close();
return students;
}

public static write2File(Set<Student> students)
{
BufferedWriter bufw = new BufferedWriter(new FileWriter("Studentinfo.txt");
for(Student student : students)
{
bufw.write(student.toString+"\t");
bufw.write(student.getSum());
bufw.newLine();
bufw.flush();
}
}
}
class  StudentInfoTest
{
public static void main(String[] args)
{
Set<Student> stus = StudentTool.getStudents();

StudentTool.write2File(stus);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐