其他對象和IO流(四)

第九章 其他對象和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);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章