Java基础21:IO

关键字:对象的序列化;管道流;RandomAccessFile;编码

一、IO流(对象的序列化)

操作对象

ObjectInputStream与ObjectOutputStream

    被操作的对象需要实现Serializable(标记接口)

    标记接口:没有方法的接口。
想要序列化必须实现,java.io.Serializable 接口。Serializable没有方法,只要实现这个接口就行,仅仅起标记作用
void writeObject(Object obj) 
          将对象写入底层存储或流。 
每个类都有 自己的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);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值