第九章 其他对象和IO流(四)
一、IO流(对象的序列化)
想要序列化必须实现,java.io.Serializable 接口。Serializable没有方法,只要实现这个接口就行,仅仅起标记作用将对象写入底层存储或流。
每个类都有 自己的id,根据成员和类来算出来的,如果已经持久化一个类,但是后来这个类修改了,但是持久化的还是原来的类,那么会出错
如果非要使用,则需要在该类中 定义 static final long serialVersionUID = 42L; 把id定死就可以了
import java.io.*;
public class Demo{
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void writeObj() throws Exception{
//存的文件一搬以object作为扩展名
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("demo.txt"));
//可以存入多个对象
//取得时候,readObject()几次就去几个
oos.writeObject(new Person("lisi",39,"kr"));
oos.close();
}
public static void readObj() throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("demo.txt"));
Person p = (Person)ois.readObject();
sop(p);
ois.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class Person implements Serializable{
String name;
//transient int age;普通变量被transient修饰后,也不能被序列化
int age;
//静态是不能静态化的,只能把堆内存序列化,但是i静态在方法区内
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;
}
}
二、IO流(管道流)
IO包中的其他类
1、RandomAccessFile
(1)、随机访问文件,自身具备读写的方法
(2)、通过skipBytes(int x),seek(int x)来达到随机访问。
2、管道流
(1)、PipedInputStream和PipedOutputStream
(1)、输入输出可以直接进行连接,通过结合线程使用。
3、public class PipedInputStreamextends InputStream管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
4、public class PipedOutputStreamextends OutputStream可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态
/*
谁先执行都可以,因为会阻塞
*/
import java.io.*;
public class Demo{
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();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class Read implements Runnable{
private PipedInputStream in;
Read(PipedInputStream in){
this.in = in;
}
public void run(){
try{
byte[] buf = new byte[1024];
int length = in.read(buf);
String s = new String(buf,0,length);
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{
Thread.sleep(3000);
out.write("piped lai la".getBytes());
out.close();
}catch(Exception e){
throw new RuntimeException("管道输出流失败");
}
}
}
三、IO流(RandomAccessFile).
public class RandomAccessFileextends Objectimplements DataOutput, DataInput, Closeable此类的实例支持对随机访问文件的读取和写入。
随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,
称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。
如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。
写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
/*
RandomAccessFile
该类不算是IO体系中的子类
而是直接继承自Object
但是它是IO包中的成员,因为它具备读和写的功能
内部封装了一个数组,而且通过指针对数组的元素进行操作
可以通过getFilePointer获取指针位置
同时可以通过seek改变指针位置
其实完成读写的原理就是内部封装了字节输入流,和输出流
通过构造函数可以看出,该类只能操作文件,而不能是键盘什么的
而且操作文件还有格式 r rw 。。。
如果模式为只读 r ,不会创建文件,会读取一个已存在文件,如果该文件不存在,则会出现异常
如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖
而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在则不会覆盖
*/
import java.io.*;
public class Demo{
public static void main(String[] args) throws Exception{
//write();
//read();
writeFile_2();
}
public static void writeFile_2() throws Exception{
RandomAccessFile raf = new RandomAccessFile("demo.txt","rw");
//raf.seek(32);
raf.seek(8);
raf.write("周期".getBytes());
//raf.writeInt(87);
raf.close();
}
public static void write() throws Exception{
RandomAccessFile raf = new RandomAccessFile("demo.txt","rw");
raf.write("李四".getBytes());
//write写入int的最低八位
//raf.write(97);
//writeInt写入int 的 全部 4个八位
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}
public static void read() throws Exception{
RandomAccessFile raf = new RandomAccessFile("demo.txt","rw");
byte[] buf = new byte[4];
//read为读单个字节 readInt() 为读4个字节
raf.read(buf);
String str = new String(buf);
sop(str);
//调整对象中指针
raf.seek(0);
//跳过指定的字节数,只能往后跳,不能往回跳
raf.skipBytes(8);
int num = raf.readInt();
sop(num);
raf.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
四、IO流(操作基本数据类型的流对象DataStream)
1、操作基本数据类型
DataInputStream 与 DataOutputStream
2、操作字节数
ByteArrayInputStream 与ByteArrayOutputStream
3、操作字符数组
CharArrayReader 与 CharArrayWriter
4、操作字符串
StringReader 与 StringWriter
/*
DataInputStream 与 DataOutputStream
可以用来操作基本数据类型的数据流对象
*/
import java.io.*;
public class Demo{
public static void main(String[] args) throws Exception{
//writeData();
//readData();
writeUTFDemo();
readUTFDemo();
//writeUTFNormal();
}
public static void writeData() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("demo.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
}
public static void readData() throws IOException {
DataInputStream dos = new DataInputStream(new FileInputStream("demo.txt"));
sop(dos.readInt());
sop(dos.readBoolean());
sop(dos.readDouble());
dos.close();
}
public static void writeUTFDemo() throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("demo.txt"));
dos.writeUTF("你好");
}
public static void readUTFDemo() throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream("demo.txt"));
sop(dis.readUTF());
dis.close();
}
public static void writeUTFNormal() throws IOException{
OutputStreamWriter dos = new OutputStreamWriter(new FileOutputStream("demo.txt"),"utf-8");
OutputStreamWriter dos2 = new OutputStreamWriter(new FileOutputStream("demo.txt"),"gbk");
dos.write("你好");
dos2.write("我好");
dos.close();
dos2.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
五、IO流(ByteArrayStream)
/*
用于操作字节数组的流对象
ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组
这就是数据目的地
因为这两个流对象都操作的是数组,并没有使用系统资源。
所以,不用进行close关闭
在流操作规律讲解时:
源设备;
键盘(System.in)、硬盘(FileStream)、内存(ArrayStream)
目的设备
控制台(System.out)、硬盘(FileStream)、内存(Array.Stream)
用流的思想来操作数组
*/
import java.io.*;
public class Demo{
public static void main(String[] args) throws Exception{
//数据源
ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while((by=bis.read())!=-1){
bos.write(by);
}
sop(bos.size());
sop(bos.toString());
}
public static void sop(Object obj){
System.out.println(obj);
}
}
六、IO流(转换流的字符编码)
字符编码
1、字符流的出现是为了方便操作字符
2、更重要的是加入了编码转换
3、通过子类转换流来完成
(1)、InputStreamReader
(2)、OutputStreamWriter
4、在两个对象进行构造的时候可以加入字符集
import java.io.*;
public class Demo{
public static void main(String[] args) throws Exception{
writeText();
readText();
}
public static void writeText() throws Exception{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
public static void readText() throws Exception{
InputStreamReader isw = new InputStreamReader(new FileInputStream("demo.txt"),"UTF-8");
char[] buf = new char[20];
int len = isw.read(buf);
String str = new String(buf,0,len);
sop(str);
isw.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
七、字符编码
/*
编码:将字符串变成字节数组
解码:字节数组变成字符串
String---->byte[]:str.getBytes();
byte[]---->String: new String(byte)
*/
import java.io.*;
import java.util.*;
public class Demo{
public static void main(String[] args) throws Exception{
String s = "你好";
byte[] bs1 = s.getBytes("GBK");//可以传入字符集。s.getBytes("utf-8");
String s1 = new String(bs1,"iso8859-1");
byte[] bs2 = s1.getBytes("iso8859-1");
String s2 = new String(bs2,"GBK");
sop(s2);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
八、字符编码-联通
/*
编码:将字符串变成字节数组
解码:字节数组变成字符串
String---->byte[]:str.getBytes();
byte[]---->String: new String(byte)
*/
import java.io.*;
import java.util.*;
public class Demo{
public static void main(String[] args) throws Exception{
String s = "联通";
byte[] by = s.getBytes("gbk");
for(byte b : by){
sop(Integer.toBinaryString(b&255));
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
九、练习
/*
有五个学生,每个学生有3们课程的成绩
从键盘输入以上数据(包括姓名,三门课程成绩)
输入格式:如:zhangsan,30,40,60。计算出中成绩。
并把学生的信息和计算出来的总分数按照顺序高低放在磁盘文件中
1、描述学生对象
2、定义一个可以操作学生对象的工具类
思想:
1、通过获取键盘录入的一行数据,并将该行中的信息取出封装成学生对象
2、因为学生对象有很多,那么就需要存储使用到集合,因为要对学生的总分排序,所以可以使用TreeSet
3、将集合中的信息写入到一个文件中
*/
import java.util.*;
import java.io.*;
class Student implements Comparable<Student>{
private String name;
private int ma,cn,en;
private int sum;
Student(String name,int ma,int cn,int en){
this.name = name;
this.ma = ma;
this.cn = cn;
this.en = en;
sum = ma+cn+en;
}
public String getName(){
return name;
}
public int getSum(){
return sum;
}
public int hashCode(){
return name.hashCode()+(sum*78);
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){
throw new ClassCastException("类型不匹配");
}
Student stu = (Student)obj;
return this.equals(stu.getName())&&this.sum==stu.getSum();
}
public int compareTo(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 String toString(){
return "student[name="+name+",ma="+ma+",cn="+cn+",en="+en+",sum="+sum+"]";
}
}
class StudentInfoTool{
public static Set<Student> getStudents() throws Exception{
return getStudents(null);
}
public static Set<Student> getStudents(Comparator<Student> cmp) throws Exception{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
Set<Student> stus = null;
if(cmp==null){
stus = new TreeSet<Student>();
}else{
stus = new TreeSet<Student>(cmp);
}
while((line = bufr.readLine())!=null){
if("over".equals(line)){
break;
}
String[] info = line.split(",");
Student stu = new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[2]));
stus.add(stu);
}
bufr.close();
return stus;
}
public static void writeToFile(Set<Student> stus) throws Exception{
BufferedWriter bufw = new BufferedWriter(new FileWriter("demo.txt"));
for(Student stu : stus){
bufw.write(stu.toString());
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
public class Demo{
public static void main(String[] args) throws Exception{
Comparator<Student> cmp = Collections.reverseOrder();
Set<Student> stus = StudentInfoTool.getStudents(cmp);
StudentInfoTool.writeToFile(stus);
}
public static void sop(Object obj){
System.out.println(obj);
}
}