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