java之IO處理

File文件基礎

文件與目錄抽象路徑名稱的表示,其構造方法有四個

File(File parent,String child):從抽象父目錄下創建一個File實例。

File(String parent,String child):從父目錄下創建一個File實例。

File(String pathname):從指定路徑下創建一個File實例。

File(URI path):從URI轉換成抽象路徑下創建一個File實例。


listFiles()方法:返回一個抽象路徑名數組,這些抽象路徑名錶示目錄中的子項(文件或目錄)

File file = new File("/home/colin");
File[] childs = file.listFiles();

listFiles(FileFilter filter):FileFilter是抽象路徑名的過濾器,可以用於返回過濾器要求的子目錄
File file = new File("/home/colin");
		//有沒有考慮過,java中不允許實現接口實例,但是在匿名內部類中卻實現了接口,比如這個FileFilter接口
		//實際上如果查看編譯後的代碼(會發現編譯後的代碼中有一個class文件,這個class實現了這個接口,並重寫了這個接口的方法)
		//所以這是一種虛擬實例化接口,或者理解爲間接實例化接口。
		File[] childs = file.listFiles(new FileFilter() {			
			@Override
			public boolean accept(File pathname) {
				return pathname.getName().startsWith(".");
			}
		});

還有一個listFiles(FilenameFileter filter):FilenameFile用於檢測指定文件是否包含在特定目錄下

其他API相對簡單了,獲取文件狀態、創建刪除文件


RandomAccessFile隨機讀寫文件

File 實例只涉及到對文件的操作,java提供了可以對文件隨機訪問的操作,訪問包括讀和寫操作,這種實現是基於指針的操作。

兩個構造方法:

RandomAccessFile(File name,String model)

RandomAccessFile(String name,String model)

model指定的是對文件隨機訪問操作模式,有兩種模式分別是隻讀模式和讀寫模式,"r"表示文件的訪問是隻讀的,"rw"表示讀和寫模式。


RandomAccessFile file = new RandomAccessFile("/home/colin","rw");
			

寫數據:

write(byte[] b):將指定自己數組b寫到隨機讀寫文件中,寫到指針的位置

write(byte[] b,int off,int len):指定了起始位置和長度

write(int n):將n的低八位寫到文件中去

他還有寫入特定特性的方法:writeBoolean(boolean b)、writeInt(int n)、writeDouble(double v)、writeChart(chart c)、writeCharts(String s)、writeByte(int n)、writeBytes(String s)、writeFloat(Float t)等

讀數據:

int read():讀取1byte(8位)放到int的低八位中,高24爲爲0。如果讀到-1,說明讀到了文件的末尾

int read(byte[] b):最多讀取b.length個字節到數組中,返回值爲實際讀取到的字節量

int read(byte[] b,int off, int length):指定讀取數組的起始位置和讀取長度

相應的還有讀取特定類型數據的read

readBoolean()、readFloat()等等,特別還有一個readLine()讀取當前位置的一行

這些都是從當前指針位置開始讀取的

釋放關聯的資源:void close()

獲取當前RandomAccessFile的指針:long getFilePoint(),以字節爲單位,比如如果一個Int是4位

移動當前指針位置:void seek(long pos)

跳過n個字節:int sikpBytes(int n):返回跳過的實際字節數,n爲負數不跳過任何字節

RandomAccessFile file = null;
		try {
			file = new RandomAccessFile("/home/colin/test.txt","rw");
			//byte[] b = "this is sample RandomAccessFile".getBytes();
			//file.read(b);
			byte[] b = new byte[10];
			while(file.read(b) >0){
				System.out.println(new String(b));
				System.out.println(file.getFilePointer());		//獲取文件指針
				file.skipBytes(1);		//每次讀取跳過一個字節
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}finally{
			if(file != null)
				file.close();
		}


基本IO

輸入是指從外界進入程序方向,即當我們需要讀取數據的時候,使用輸入。

輸出是指從程序發送到外界方向,通常我們需要寫出數據到外界,所以輸出是用來寫數據的。

流的分類

根據單位:字節流(8bit,圖片視頻等)和字符流(16bit,文本)

根據角色:節點流(直接作用在文本上的流,直接與特定的地方(磁盤、內存)相連)和處理流(在節點流外層的流,是對一個已經存在流的連接和封裝,在所封裝的流的功能上實現數據的讀寫)

java中40多種流都是從4個基類派生出來的

            字節流               字符流

輸入:InputStream     Reader

輸出:OutputStream  Writer


InputStream和OutputStream

二者都是字節流的抽象基類,定義了基本的read和write方法,read()、read(byte[] a,int off,int length)、read(byte[] b)、write(int b)、write(byte[] b)、write(byte[] b,int off ,int len)

Reader和Writer

reader和writer都是字符流的抽象基類,定義了讀取字符的read和write。read()、read(char[] cbuf)、read(char[] cbuf,int off, int len)、write(char c)、write(char[] cbuf)、cbuf(cbuf,int off ,int len)

文件流

文件字節流:

FileOutputStream可以使用以下幾種方法構造:

FileOUtputStream(File file)     

FileOutputStream(String name)

指定寫入的文件,如果該文件存在的化會清除該文件上面的內容
FileOutputStream(File file,boolean append)

FileOutputStream(String name,boolean append)

如果指定append參數爲true,則如果寫入的文件存在,是以追加的方式進行寫入的

FileInputStream可以使用以下方法構造:

FileInputStream(File file)

FileOutputStream(String name)

文件字節流實現了inputStream和outputStream的基本read和write

注意如果讀取的時候返回-1,則說明讀取到了EOF


利用文件流實現文件的複製:

		
		File file1 = new File("/home/colin/hello.py");
		File file2 = new File("/home/colin/hello2.py");
	
		FileInputStream input = null;
		FileOutputStream output = null;
		try {
			input = new FileInputStream(file1);
			output = new FileOutputStream(file2);
			byte[] b = new byte[10];
			int len = -1;
			while((len=input.read(b))!=-1){
				output.write(b, 0, len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
                               //先關輸入流,再關輸出流
                                 if(inputput != null)
					inputput.close();
				if(output != null)
					output.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	

FileReader和FileWriter與FileInputStream和FileOutputStream使用情況一樣。

緩衝流

BufferedInputStream原理:緩衝字節輸入流,內部維護一個緩衝區,該流會儘可能一次性讀取若干字節到緩衝區,然後逐一返回知道緩衝區中的數據被全部讀取完畢,從而減少讀取次數,提高讀取效率,BIS就是一個處理流,該流提供了緩衝功能。他還提供了mark、reset和skip方法

提供的構造方法:

BufferedInputStream(InputStream input)

BufferedInputStream(InputStream input,int size):size指定緩衝區大小


BufferedOutputStream原理:緩衝輸出流,內部維護一個緩衝區,每當向該流寫入數據的時候,都會現將數據存儲緩衝區中,當緩衝區已滿的時候,緩衝流會將數據一次性全部寫出。

提供的構造方法:

BufferedOutputStream(OutputStream out)

BufferedOutputStream(OutputStream out,int size):指定緩衝區大小

BufferedOutputStream只提供了write和flush()方法,flush()清空緩衝區,將緩衝區中的數據強制寫入。


利用緩衝流實現文件複製:

		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(new File("/home/colin/hello.py")));
			bos = new BufferedOutputStream(new FileOutputStream(new File("/home/colin/hello3.py")));
			int len = -1;
			byte[] b = new byte[10];
			while((len=bis.read(b)) !=-1){
				bos.write(b, 0, len);
			}
			bos.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				//先關輸入流,再關輸出流
				if(bis != null)
					bis.close();
				if(bos != null)
					bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	

BufferedReader和BufferedWriter與BufferedInputStream和BufferedOutputStream實現原理是一樣的,但是BufferedWriter提供了newLine(),寫入換行符的方法

對象流

對象序列化:對象存在內存中,有時候需要將對象保存到磁盤上,或者將對象進行傳輸等這樣的操作。這時候需要將對象轉化爲一個字節序列,這個過程稱爲對象序列化。

對象反序列化:有時候需要將字節序列轉化成爲對應的對象,這個過程成爲對象的反序列化。

ObjectOutputStream:用來將對象進行序列化的輸出流

提供的構造方法:

ObjectOutputStream()

ObjectOutputStream(OutputStream out)

使用其write方法,將對象轉化成爲一個字節序列後寫出,write方法提供了諸如writeInt()等此類方法。

ObjectInputStream:用來將對象反序列化

提供的構造方法:

ObjectInputstream()

ObjectInputStream(InputStream input)

使用其提供的readObject()方法,讀取字節並轉化爲對應的對象


這個整體思路是要對對象進行傳遞,需要將對象轉換成爲字節流以便傳輸,所以首先通過ObjectOutputStream進行寫入,將對象寫成字節進行傳輸。傳遞到目標位置後需要讀取,這時候將傳輸的字節轉換成爲對象。

如果使用ObjectOutputStream進行序列化寫入,需要序列化對象實現Serializable接口,該接口並沒有任何方法只是序列化標誌。通常實現該接口需要給出一個serialVersionUID,表明該類版本,若不顯示聲明編譯器也會經過計算給出一個serialVersionUID,但是不同編譯器實現有所不同,所以如果想要跨平臺,都應該顯示聲明版本號。當類的對象序列化到磁盤上面,之後隨之需求改變,改變了類的屬性,那麼反序列化就會出現InvalidClassException,這樣就會造成不兼容問題。但當serialVersionUID相同時,會將不一樣的Field以type的預設值反序列化,可以避開不兼容問題

transient關鍵詞:當我們對對對象進行序列化後,得帶的字節序列往往比較大,有時我們在對一個對象進行序列化時可以忽略某些不必要的屬性,從而對序列化後得到的字節序列瘦身,可以將其聲明爲transient,這樣這些屬性在序列化時會被忽略。

實例:

/*
 *構造Emp類,對其對象進行序列化與反序列化
 */
public class Emp implements Serializable {

	private static final long serialVersionUID = 1L;
	private String name;
	private int age;
	private double salary;
	private transient String description;    //使用transient修飾,在反序列化時輸出null
	 
	public Emp(String name,int age,double salary,String description){
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.description = description;
		}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	
	@Override
	public String toString() {
		return "Emp [name="+name+",age="+age+",salary="+salary+",description="+description+"]";
	}
}



/*
     * 將Emp對象序列化,並且存儲
     */
    public static  void testOos(){
        ObjectOutputStream oos = null;
        try {
            FileOutputStream fos = new FileOutputStream(new File("/home/colin/oos.obj"));
            oos = new ObjectOutputStream(fos);
            Emp emp = new Emp("colin", 23, 13000, "I want you!!!");
            oos.writeObject(emp);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                if(oos != null)
                    oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /*
     * 將存儲的Emp對象反序列輸出
     */
    public static void testOis(){
        ObjectInputStream ois = null;
        try {
            FileInputStream fis = new FileInputStream(new File("/home/colin/oos.obj"));
            ois = new ObjectInputStream(fis);
            Emp emp = (Emp)ois.readObject();
            System.out.println(emp.getName()+","+emp.getAge()+","+emp.getSalary()+","+emp.getDescription());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }



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