黑馬程式設計師-JAVA高階(IO輸入與輸出)PART4
---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------
這部分內容的知識點為:
1.IO包中的其他幾個類;
2.字元編碼;
3.練習。
一、IO包中的其他幾個類
1.物件的序列化:ObjectInputStream和ObjectOutputStream
import java.io.*; /* 只有實現了Serializable介面的類才可以被序列化 Serializable介面沒有任何方法,稱為標記介面 */ class Person implements Serializable { private static final long serialVersionUID = 42L; private String name; transient int age;//在堆記憶體中,但是不被序列化 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; } } 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("zhangsan2",39,"kr")); oos.close(); } }
2.管道流:PipedInputStream和PipedOutputStream
輸入輸出可以直接進行連線,通過結合線程使用。不要對這兩個物件使用單執行緒,因為這樣可能死鎖執行緒。
import java.io.*; class Read implements Runnable { private PipedInputStream in; Read(PipedInputStream in) { this.in = in; } public void run() { BufferedReader bufr = null; try { bufr = new BufferedReader(new InputStreamReader(in)); //byte[] buf = new byte[10]; System.out.println("讀取前。。。沒有阻塞"); //int len = 0; String line = null; while((line=bufr.readLine())!=null) { //String s = new String(buf,0,len); System.out.println(line); } System.out.println("讀到資料。。。阻塞"); } catch (IOException e) { throw new RuntimeException("管道流讀取失敗"); } finally { if(bufr!=null) try { bufr.close(); } catch (IOException e) { throw new RuntimeException("流關閉異常"); } } } } class Write implements Runnable { private PipedOutputStream out; Write(PipedOutputStream out) { this.out = out; } public void run() { try { System.out.println("開始寫入資料,等待6秒"); Thread.sleep(6000); out.write("nima le ge dadada osdopao oepwoe woeiupoa".getBytes()); //out.close(); } catch (Exception e) { throw new RuntimeException("管道流寫入失敗"); } finally { try { out.close(); } catch (IOException e) { throw new RuntimeException("管道輸出流關閉異常"); } } } } 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(); } }
3.RandomAccessFile
隨機訪問檔案,自身具備讀寫的方法。
該類直接繼承自Object,不算是IO體系中的子類,但因為讀和寫功能,它是IO包中成員。其內部封裝了一個數組,通過指標對陣列元素進行操作。
其實讀寫的原理就是內部封裝了位元組輸入流和輸出流。
通過建構函式可以看出,該類只能操作檔案,包含模式:只讀r,讀寫rw。
如果模式為只讀r,只能去讀取一個已經存在的檔案,如果檔案不存在,會出現異常而不會建立;如果模式為讀寫rw,如果要操作的檔案不存在會自動建立,如果存在不會覆蓋。
4.操作基本資料型別的流物件:DataInputStream和DataOutputStreamimport java.io.*; class RandomAccessFileDemo { public static void main(String[] args) throws IOException { //writeFile(); //readFile(); //writeFile_2(); RandomAccessFile raf = new RandomAccessFile("ran1.txt","rw"); } public static void readFile() throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //調整物件中指標 //raf.seek(8); //跳過指定的位元組數 raf.skipBytes(8); byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf); int age = raf.readInt(); System.out.println(name+":"+age); raf.close(); } public static void writeFile_2() throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.seek(8*3); 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(98); raf.write("王五".getBytes()); raf.writeInt(93); raf.close(); } }
/*
用於操作基本資料型別資料的流物件
*/
import java.io.*;
class DataStreamDemo
{
public static void main(String[] args) throws IOException
{
//writeData();
//readData();
//writeUTFDemo();
readUTFDemo();
}
public static void readUTFDemo() throws IOException
{
DataInputStream dis = new DataInputStream(
new FileInputStream("utfdata.txt"));
String s = dis.readUTF();
System.out.println("s::"+s);
dis.close();
}
public static void writeUTFDemo() throws IOException
{
DataOutputStream dos = new DataOutputStream(
new FileOutputStream("utfdata.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readData() throws IOException
{
DataInputStream dis = new DataInputStream(
new FileInputStream("data.txt"));
int a = dis.readInt();
boolean b = dis.readBoolean();
double c = dis.readDouble();
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("c="+c);
}
public static void writeData() throws IOException
{
DataOutputStream dos = new DataOutputStream(
new FileOutputStream("data.txt"));
dos.writeInt(124);
dos.writeBoolean(true);
dos.writeDouble(1234.453);
dos.close();
}
}
5.操作位元組陣列的流物件:ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream在構造的時候,需要接收資料來源,而且資料來源是一個位元組陣列。
ByteArrayOutputStream在構造的時候,不用定義資料目的,因為該物件內部已經封裝了可變長度的位元組陣列,這就是資料目的。
因為這兩個流物件操作的都是陣列,沒有使用系統資源,所以不用進行關閉操作。
/*
操作位元組陣列的流物件
*/
import java.io.*;
class ByteArrayStreamDemo
{
public static void main(String[] args) throws IOException
{
ByteArrayInputStream bais = new ByteArrayInputStream("你好嗎".getBytes());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while((b=bais.read())!=-1)
baos.write(b);
System.out.println(baos.size());
System.out.println(baos.toString());
//將此位元組陣列輸出流的全部內容寫入到指定的輸出流中
baos.writeTo(new FileOutputStream("bytearr.txt"));
}
}
二、編碼
常見的編碼表:
ASCII:美國標準資訊交換碼,用一個位元組的7位表示;
ISO8859-1:拉丁碼錶(歐洲碼錶),用一個位元組的8位表示;
GB2312:中國的中文編碼表;
GBK:升級的中文編碼表,融合更多中文字元;
Unicode:國際標準碼錶,融合多種文字。所有字元都用兩個位元組來表示,Java語言使用的就是Unicode。
UTF-8:最多用三個位元組表示一個字元,可以是一個或兩個位元組。
1.轉換流的字元編碼
import java.io.*;
class EncodeStreamDemo
{
public static void main(String[] args) throws IOException
{
//writeText();
readText();
}
public static void readText() throws IOException
{
InputStreamReader isr = new InputStreamReader(
new FileInputStream("utf.txt"),"utf-8");
char[] arr = new char[10];
int len = isr.read(arr);
System.out.println(new String(arr,0,len));
isr.close();
}
public static void writeText() throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("utf.txt"),"utf-8");
osw.write("你好");
osw.close();
}
}
2.字元編碼
編碼:字串變成位元組陣列
解碼:位元組陣列變成字串
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
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);
}
}
以上程式碼編碼解碼的過程類似tomcat伺服器中的編解碼過程。tomcat伺服器預設編碼是iso8859-1,如果瀏覽器提交的資料是gbk編碼的漢字,伺服器收到後就是亂碼,所以必須再次通過iso8859-1編碼,然後再通過gbk解碼才可以。但如果伺服器端的編碼預設是utf-8,就不可以這樣做。
3.字元編碼-聯通
現象:在一個文字檔案中僅僅輸入“聯通”兩個字,儲存之後再次開啟的時候顯示的是亂碼。
解釋:文字檔案的預設編碼是gbk,“聯通”兩個字通過gbk編碼後是11000001 10101010 11001101 10101000,正好符合utf-8編碼的形式,所以再次開啟文字檔案的時候會被誤認為是utf-8編碼而用utf-8解碼,自然就顯示亂碼。
三、練習
需求:每個學生有三門課的成績,從鍵盤按一定的格式輸入學生的姓名和三門成績(如zhangsan,38,89,98),計算出總成績,並按總成績的高低順序把每個學生的資訊存放在磁碟檔案“stud.txt”中。
1.描述學生物件;
2.定義一個可操作學生物件的工具類。
思想:
1.獲取鍵盤錄入的一行資料,提取資訊封裝成學生物件;
2.因為要儲存學生資訊,所以使用集合,又因為要排序,所以用TreeSet物件;
3.將集合的資訊寫入檔案中。
import java.io.*;
import java.util.*;
class Student implements Comparable
{
private String name;
private int mt,cn,en;
private int sum;
Student(String name,int mt,int cn,int en)
{
this.name = name;
this.mt = mt;
this.cn = cn;
this.en = en;
this.sum = mt + cn + en;
}
public String getName()
{
return this.name;
}
public int getSum()
{
return this.sum;
}
public int hashCode()
{
return this.name.hashCode()+this.sum*78;
}
public boolean equlas(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 "studnt["+this.name+","+this.mt+","+this.cn+","+this.en+"]";
}
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 getStudents()
{
return getStudents(null);
}
public static Set getStudents(Comparator cmp)
{
Set stus = null;
if(cmp==null)
stus = new TreeSet();
else
stus = new TreeSet(cmp);
BufferedReader bufr = null;
try
{
bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
String[] info = line.split(",");
Student s = new Student(info[0],Integer.parseInt(info[1]),
Integer.parseInt(info[2]),Integer.parseInt(info[3]));
stus.add(s);
}
return stus;
}
catch (IOException e)
{
throw new RuntimeException("學生資訊錄入失敗");
}
finally
{
if(bufr!=null)
try
{
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("讀取流關閉異常");
}
}
}
public static void write2File(Set stus)
{
BufferedWriter bufw = null;
try
{
bufw = new BufferedWriter(new FileWriter("stud.txt"));
for(Student s:stus)
{
bufw.write(s.toString()+"\t");
bufw.write(s.getSum()+"");
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("學生資訊寫入檔案失敗");
}
finally
{
if(bufw!=null)
try
{
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("檔案寫入流關閉失敗");
}
}
}
}
class StudentInfoTest
{
public static void main(String[] args)
{
Comparator cmp = Collections.reverseOrder();
Set stus = StudentInfoTool.getStudents(cmp);
StudentInfoTool.write2File(stus);
}
}
---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------