• Java IO(四)


       对象序列化

       对象序列化又叫对象的持久化,对象的串行化(或反串行化)

       当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化,则可以使用transient关键字进行声明。

     static修饰的静态属性也不能被序列化,序列化的只是堆内存中对象的属性。

    ANY-ACCESS-MODIFIER(任意的访问修饰符) static final long serialVersionUID = 42L;

       语句的作用:给类定义一个固定标识,为了序列化方便,新的类还能操作曾经被序列化的对象。

       举例说之,示例代码如下:

       序列化的Person类:

    import java.io.Serializable;
    
    public class Person implements Serializable {
        /*
         * 给类定义一个固定标识,为了序列化方便,新的类还能操作曾经被序列化的对象。
         */
        public static final long serialVersionUID = 42L;
        private String name;
        transient int age;//transient保证其值在堆内存中存在,不被序列化到文件。
        static String country = "cn";//静态不能序列化
        public Person(String name, int age, String country) {
            this.name = name;
            this.age = age;
            this.country = country;
        }
        public String toString() {
            return name + "::" + age+":" + country;
        }
        
    }

       序列化Person类的代码:

    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 IOException, ClassNotFoundException {
            //writeObj();
            readObj();
        }
        
        public static void readObj() throws IOException, ClassNotFoundException {
            ObjectInputStream ois = new ObjectInputStream(
                    new FileInputStream("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("obj.txt"));
            oos.writeObject(new Person("lisi0", 399, "kr"));
            oos.close();
        }
    
    }

       

       管道流

       管道流的主要作用是可以进行两个线程间的通信。反正管道流结合的是多线程技术,可以查看JDK帮助文档。

       示例代码如下:

    import java.io.IOException;
    import java.io.PipedInputStream;
    import java.io.PipedOutputStream;
    
    class Read implements Runnable {
        private PipedInputStream in;
        
        Read(PipedInputStream in) {
            this.in = in;
        }
        @Override
        public void run() {
            try {
                byte[] buf = new byte[1024];
                System.out.println("读取前。。。没有数据,就阻塞");
                int len = in.read(buf);
                System.out.println("读到数据。。。阻塞结束");
                String s = new String(buf, 0, len);
                System.out.println(s);
                in.close();
            } catch (IOException e) {
                throw new RuntimeException("管道读取流失败");
            }
        }
        
    }
    class Write implements Runnable {
        private PipedOutputStream out;
        
        Write(PipedOutputStream out) {
            this.out = out;
        }
        @Override
        public void run() {
            try {
                System.out.println("开始写入数据,等待6秒后.");
                Thread.sleep(6000);
                
                out.write("piped lai la".getBytes());
                out.close();
            } catch (Exception e) {
                throw new RuntimeException("管道输出流失败");
            }
        }
        
        
    }
    public class PipedStreamDemo {
    
        public static void main(String[] args) throws IOException {
            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();
        }
    
    }

       RandomAccessFile

       该类不算是IO体系中子类,而是直接继承自Object。但是它是IO包中的成员,因为它具备读和写的功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取指针的位置。同时可以通过seek改变指针的位置。其实完成读写的原理就是内部封装了字节流输入流和输出流

       通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式:只读r,读写rw等。

    • 如果模式为只读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
    • 如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖(会修改文件)。

       示例代码如下:

    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    public class RandomAccessFileDemo {
    
        public static void main(String[] args) throws IOException {
            //writeFile();
            writeFile_2();
            //readFile();
            //System.out.println(Integer.toBinaryString(258));
        }
        
        public static void readFile() throws IOException {
            RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
            //raf.write("haha".getBytes());
            
            /*
             * 调整对象中的指针
             */
            //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();
        }
    
    }

       图解原理:

       DataOutputStream与DataInputStream

       可以用于操作基本数据类型的数据的流对象。

       示例代码:

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    
    public class DataStreamDemo {
    
        public static void main(String[] args) throws IOException {
            //writeData();
            //readData();
            //writeUTFDemo();
            /*
            OutputStreamWriter osw = new OutputStreamWriter(
                    new FileOutputStream("D:\java\lib\wo\gbk.txt"), "gbk");
            osw.write("你好");
            osw.close();
            */
            readUTFDemo();
        }
        
        public static void readUTFDemo() throws IOException {
            DataInputStream dis = new DataInputStream(
                    new FileInputStream("D:\java\lib\wo\utf.txt"));
            String s = dis.readUTF();
            System.out.println(s);
            dis.close();
        }
        
        public static void writeUTFDemo() throws IOException {
            DataOutputStream dos = new DataOutputStream(
                    new FileOutputStream("D:\java\lib\wo\utfdata.txt"));
            dos.writeUTF("你好");
            dos.close();
        }
        
        public static void readData() throws IOException {
            DataInputStream dis = new DataInputStream(new FileInputStream("D:\java\lib\wo\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.println("d="+d);
            
            dis.close();
        }
        
        public static void writeData() throws IOException {
            DataOutputStream dos = new DataOutputStream(
                    new FileOutputStream("D:\java\lib\wo\data.txt"));
            dos.writeInt(234);
            dos.writeBoolean(true);
            dos.writeDouble(9887.543);
            dos.close();
        }
    
    }

       内存操作流

       ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组。

       ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该数据对象已经内部封装了可变长度的字节数组。这就是数据目的地。

       在流操作规律讲解时:

       源设备:

    1. 键盘:System.in
    2. 硬盘:FileStream
    3. 内存:ArrayStream

       目的设备:

    1. 控制台:System.out
    2. 硬盘:FileStream
    3. 内存:ArrayStream

       用流的读写思想来操作数组。

       示例代码如下:

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.FileOutputStream;
    
    public class ByteArrayDemo {
    
        public static void main(String[] args) {
            //数据源
            ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEF".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"));
        }
    
    }

       字符编码

       示例代码如下:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    
    public class EncodeStream {
    
        public static void main(String[] args) throws IOException {
            //writeText();
            readText();
        }
        public static void readText() throws IOException {
            InputStreamReader isr = new InputStreamReader(
                    new FileInputStream("utf-8.txt"), "GBK");
            char[] buf = new char[10];
            int len = isr.read(buf);
            String str = new String(buf, 0, len);
            System.out.println(str);
            isr.close();
        }
        
        public static void writeText() throws IOException {
            OutputStreamWriter osw = new OutputStreamWriter(
                    new FileOutputStream("utf-8.txt"), "UTF-8");
            osw.write("你好");
            osw.close();
        }
    
    }

       图解原理:

       编码:字符串变成字节数组。String--->byte[];   str.getBytes(charsetName);

       解码:字节数组变成字符串。byte[]--->String;   new String(byte[], charsetName);

       示例代码如下:

    import java.io.UnsupportedEncodingException;
    import java.util.Arrays;
    
    public class EncodeStream1 {
    
        public static void main(String[] args) throws UnsupportedEncodingException {
            /*
            String s = "你好";
            byte[] b1 = s.getBytes("gbk");
            System.out.println(Arrays.toString(b1));
            String s1 = new String(b1, "iso8859-1");
            System.out.println("s1="+s1);
            
            // 对s1进行iso8859-1编码
            byte[] b2 = s1.getBytes("iso8859-1");
            System.out.println(Arrays.toString(b2));
            String s2 = new String(b2, "gbk");
            System.out.println("s2="+s2);
            */
            
            String s = "你好";
            byte[] b1 = s.getBytes("gbk");
            System.out.println(Arrays.toString(b1));
            String s1 = new String(b1, "utf-8");
            System.out.println("s1="+s1);
            /*
             * 对s1进行utf-8编码
             */
            byte[] b2 = s1.getBytes("utf-8");
            System.out.println(Arrays.toString(b2));
            String s2 = new String(b2, "gbk");
            System.out.println("s2="+s2);
            
        }
    }

       图解原理1:

    图解原理2:

       应用:

       

       一个非常特殊的例子:新建一个文本文档,输入"联通"二字,保存并退出,再次打开此文本文档时,会显示乱码!!!

       分析:

       

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

       分析:

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

       思路:

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

       代码:

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.Set;
    import java.util.TreeSet;
    
    class Student implements Comparable<Student> {
        private String name;
        private int ma, cn, en;
        private int sum;
        
        public 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 void setName(String name) {
            this.name = name;
        }
    
        public int getMa() {
            return ma;
        }
    
        public void setMa(int ma) {
            this.ma = ma;
        }
    
        public int getCn() {
            return cn;
        }
    
        public void setCn(int cn) {
            this.cn = cn;
        }
    
        public int getEn() {
            return en;
        }
    
        public void setEn(int en) {
            this.en = en;
        }
    
        public int getSum() {
            return sum;
        }
    
        public void setSum(int sum) {
            this.sum = sum;
        }
        
        public int hashCode() {
            return name.hashCode() + sum * 78;
        } 
        
        public boolean equals(Object obj) {
            if(!(obj instanceof Student))
                throw new ClassCastException("类型不匹配");
            Student s = (Student) obj;
            return this.name.equals(s.name) && this.sum == s.sum;
        }
        
        public String toString() {
            return "student["+name+", "+ma+", "+cn+", "+en+"]";
        }
    
        @Override
        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;
        }
    }
    class StudentInfoTool {
        
        public static Set<Student> getStudents() throws IOException {
            return getStudents(null);
        }
        
        public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException {
            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[3]));
                stus.add(stu);
            }
            bufr.close();
            return stus;
        }
        
        public static void write2File(Set<Student> stus) throws IOException {
            BufferedWriter bufw = new BufferedWriter(
                    new FileWriter("stuinfo.txt"));
            for(Student stu : stus) {
                bufw.write(stu.toString() + "	");
                bufw.write(stu.getSum() + "");//分数变为字符串再写进去,因为写入int值,只是写入的最后1个字节
                bufw.newLine();
                bufw.flush();
            }
            bufw.close();
        }
    }
    
    public class Test {
    
        public static void main(String[] args) throws IOException {
            
            Comparator<Student> cmp = Collections.reverseOrder();//反转Student类中的默认排序
            
            Set<Student> stus = StudentInfoTool.getStudents(cmp);
            StudentInfoTool.write2File(stus);
        }
    
    }
    View Code

      

  • 相关阅读:
    HUST第八届程序设计竞赛-G小乐乐打游戏(双bfs)
    HDU-1575-Tr A(矩阵快速幂模板)
    HDU-1061-Rightmost Digit (快速幂模板)
    HihoCoder 1142-三分求极值(三分模板)
    Aizu ITP2_6_A(二分模板)
    Codeforces-938D-Buy a Ticket(最短路设虚拟节点+Dijk优先队列优化)
    POJ-1797-Heavy Transportation(最短路变形)
    HDU-5137-How Many Maos Does the Guanxi Worth(最短路删点)
    POJ-1094-Sorting It All Out (拓扑排序)(判断环和排名是否唯一)
    HDU-1869-六度分离(多源到多源最短路)
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5276909.html
Copyright © 2020-2023  润新知