1. 程式人生 > >黑馬程式設計師-JAVA高階(IO輸入與輸出)PART4

黑馬程式設計師-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,如果要操作的檔案不存在會自動建立,如果存在不會覆蓋。

import 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();
	}
}
4.操作基本資料型別的流物件:DataInputStream和DataOutputStream
/*
用於操作基本資料型別資料的流物件
*/
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培訓、期待與您交流! ----------------------