天天看點

java-I/O

IO

IO(Input/Output)是計算機輸入/輸出的接口。java的核心庫java.io提供了全方面的IO接口,包括:檔案系統的操作,檔案讀寫,标準裝置輸出等等

java-I/O

File類及使用 

File對象封裝了檔案或路徑屬性,但不包含對檔案讀寫資料的方法

部分File類常用方法 

public String getName() 擷取檔案或目錄的名字

public String getParent() 擷取父目錄的路徑字元串

public File getParentFile() 擷取父目錄路徑的File對象

public String getAbsolutePath() 擷取檔案或目錄的絕對路徑

public boolean exists() 判斷檔案或目錄是否存在

Public File[] listFiles() 獲得目錄裡的檔案和目錄封裝成File對象放到File數組裡

public boolean isDirectory() 判斷是不是檔案夾或者目錄

public boolean isFile() 判斷是不是檔案

public long length() 擷取檔案的大小

boolean delete() 删除檔案或檔案夾

boolean mkdir() 建立檔案夾

package my;
	
	import java.io.*;
	
	public class IO {
		public static void main(String[] args)
		{
		File file1 = new File("c:\\test");
		System.out.println(file1.getAbsolutePath());
		System.out.println(file1.getParent());    //test的父目錄
		System.out.println(file1.isDirectory());   //是否存在test檔案夾
		System.out.println(file1.isFile());        //是否存在test檔案
		System.out.println(file1.exists());        //是否存在
		System.out.println(file1.length());
		System.out.println(file1.delete());//存在直接删除test檔案夾
        //隻能删除空檔案夾,若裡面有檔案則需要遞歸删除
		File file2 = new File("c:\\apple");
		System.out.println("apple " + file2.mkdir());
		 //建立成功傳回true,若原來有此檔案夾則傳回false
		File file3 = new File("c:\\apple\\1.txt");
		try {
			System.out.println("1.txt " + file3.createNewFile());
		     //建立檔案,成功true,原來有傳回false
		    //使用creatNewFile的時候會抛出異常,需要捕獲
		}
		catch(IOException e){
			e.printStackTrace();
		}
		
		String[] files1 = file2.list();
		for(String f:files1) {
			System.out.println("files1 " + f);
		}
		//擷取一個檔案裡面的所有檔案名和目錄名
		//傳回一個字元串數組,這些字元串指定此抽象路徑名表示的目錄中的檔案和目錄
		
		String[] files2 = file2.list(new FilenameFilter() {
			public boolean accept(File dir, String name) { 
				//dir : 被找到的檔案所在的目錄
				//name:檔案的名稱
				return name.endsWith(".txt");
			}
		});
		for(String f:files2) {
			System.out.println("files2 " + f);
		}
		//傳回檔案裡面指定值的檔案名和目錄名
		//傳回一個字元串數組,這些字元串指定此抽象路徑名表示的目錄中的檔案和目錄
		
		
		File[] files3 = file2.listFiles();
		for(File f:files3) {
			System.out.println("files3 " + f.getName() + "--" + f.length());
		}
		//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名表示的目錄中的檔案
		//包括一些檔案屬性:檔案大小等
		
		File[] files4 = file2.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.endsWith(".txt");
				}
		});
		for(File f:files4) {
			System.out.println("files4 " + f.getName() + "--" + f.length());
		}
		//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名滿足指定過濾器的檔案和目錄
		//包括一些檔案屬性:檔案大小等
		
		File[] files5 = file2.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return pathname.getName().endsWith(".txt");
			}
		});
		for(File f:files5) {
			System.out.println("files5: " + f.getName() + "--" + f.length());
		}
		//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名滿足指定過濾器的檔案和目錄
		//包括一些檔案屬性:檔案大小等
		}
	}

Console:
//c:\test
//c:\
//false
//false
//false
//0
//false
//apple false
//1.txt false
//files1 1.doc
//files1 1.mpp
//files1 1.txt
//files1 2.txt
//files2 1.txt
//files2 2.txt
//files3 1.doc--9216
//files3 1.mpp--178688
//files3 1.txt--0
//files3 2.txt--0
//files4 1.txt--0
//files4 2.txt--0
//files5: 1.txt--0
//files5: 2.txt--0

           

FileInputStream和FileOutputStream

FileInputStream類和FileOutputStream類用于從檔案讀取/寫入位元組,他們所有的方法都是從InputTream類和OutputStream類中繼承的,沒有引進新方法

I/O類中幾乎所有的方法都會抛出異常IOExecption,是以必須在方法中聲明抛出IOException異常,或者将代碼放到tyr-catch塊這種

對檔案的讀寫操作使用緩沖區會大大提高檔案讀寫效率

FileInputStream能從檔案讀取位元組的InputStream類

FileOutputStream表示能向檔案寫入位元組的OutputStream類

package my;

import java.io.*;
public class FileInputStreamOutputStream {
	public static void main(String[] args) {
		try {
			FileCopyUtil.copyFile(new File("c:\\picture\\1.png"), new File("c:\\test\\1.png"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class FileCopyUtil{ 
	public static void copyFile(File src, File dst) throws IOException{
		FileInputStream fis = new FileInputStream(src); //從原檔案讀取檔案
		FileOutputStream fos = new FileOutputStream(dst);  //寫到指定檔案當中
	 	//直接從輸入流中讀到輸出流中
		long time1 = System.currentTimeMillis();
		int data = -1;
		while((data = fis.read()) != -1){
			fos.write(data);
		}
		fis.close();
		fos.close();
		long time2 = System.currentTimeMillis();
		
		//将輸入流中的資料存到緩沖區中最後一起讀到輸出流
		byte [] buf = new byte[1024*1024];//建立一個1M大小的緩沖區,用來存放輸入流中的位元組數
		int len = 0;
		long time1 = System.currentTimeMillis();
		while((fis.read(buf)) != -1) {
			fos.write(buf,0,len);
		}
		fis.close();
	    fos.close();
    	long time2 = System.currentTimeMillis();
		System.out.println("finished : " + (time2 - time1));
	}
}
           

ByteArrayInput/OutputStream

ByteArrayInputStream是把位元組數組當成源的輸入流

ByteArrayOutputStream是把位元組數組當做目标的輸出流

package my;

import java.io.*;

public class ByteArrayInputStreamByteArrayOutputStream {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
        //把字元串轉換成位元組數組,再從這個位元組數組裡讀出來一個個列印輸出
		String str = "hello,world";
		ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
		int data = -1;
		while((data = bis.read()) != -1) {
			System.out.print((char)data);
		}
		bis.close();
		
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		bos.write(97);
		bos.write(65);
		bos.write("hello".getBytes());
		byte[] buff = bos.toByteArray();
		for(byte data : buff) {
			System.out.print((char)data);
		}
		FileOutputStream fos = new FileOutputStream("c:\\test\\1.txt", true);
        //隻會追加不會覆寫源檔案内容
		bos.writeTo(fos);
        //把ByteArrayOutputStream内部緩沖區的資料寫到對應的檔案輸出流中
		fos.close();
	}

}
           

FilterInputStream和FilterOutputStream(過濾流)

是為某種目的過濾位元組的資料流,基本位元組輸入流提供的讀取方法隻能用來讀取位元組,如果要讀取整數值、雙精度值或字元串,需要一個過濾器類來包裝位元組輸入流

常用的過濾流 BufferedInputStream和BufferedOutputStream, DataInputStream和DataOutputStream

DataInputStream從資料流中讀取位元組并轉化為适當的基本類型值或字元串,DataOutputStream将基本類型的值或字元串轉化為位元組,并輸出到輸出資料流

BufferedInputStream和BufferedOutputStream可以通過減少讀寫次數來提高輸入輸出速度,BufferedOutputStream類為存儲位元組在流中添加一個緩沖區,以提高處理效率

BufferedInputStream類和BufferedOutputStream類

import java.io.*;
public class BufferedInputStreamOutputStream {
	public static void main(String[] args) {
		try {
			FileUtil.copyFile(new File("c:\\picture\\1.png"), new File("c:\\test\\1.png"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class FileUtil{ 
	public static void copyFile(File src, File dst) throws IOException{
		FileInputStream fis = new FileInputStream(src); //從原檔案讀取檔案
		FileOutputStream fos = new FileOutputStream(dst);  //寫到指定檔案當中
		BufferedInputStream bis = new BufferedInputStream(fis);
        //對fis這個檔案增加緩沖區的功能
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int data = 0;
		long time1 = System.currentTimeMillis();
		while((data = bis.read()) != -1) {
			bos.write(data);
		}
		//關閉包裝類就可以
		bis.close();
		bos.close();
		long time2 = System.currentTimeMillis();
		System.out.println("finished : " + (time2 - time1) + "毫秒");
	}
}
           

DataInputStream類和DataOuputStream類

package my;

import java.io.*;

public class DataInputStreamOutputStream {
	public static void main(String[] args) throws IOException {
		String name = "zhangsan";
		int age = 10;
		boolean flag = true;
		char sex = 'm';
		double money = 100.2;
		
        //寫入檔案操作
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("c:\\test\\b.txt"));
		//建立一個檔案并将它執行個體化
		dos.writeUTF(name);
		dos.writeInt(age);
		dos.writeBoolean(flag);
		dos.writeChar(sex);
		dos.writeDouble(money);
		dos.close(); //關閉檔案
		
        //将檔案資訊讀取出來
        DataInputStream dis = new DataInputStream(new FileInputStream("c:\\test\\b.txt"));
		//讀的必須和寫的順序一緻
		System.out.println(dis.readUTF());
		System.out.println(dis.readInt());
		System.out.println(dis.readBoolean());
		System.out.println(dis.readChar());
		System.out.println(dis.readDouble());
		dis.close();
	}
}
           

BufferedInputStream和BufferedOutputStream:需要使用已經存在的節點流來構造,提供帶緩沖的讀寫,提高了讀寫的效率

DataInputStream和DataOutputStream:資料輸入輸出流允許應用程式讀寫基本java資料類型。應用程式可以使用資料輸出流寫入稍後有資料輸入流讀取。讀寫順序要保持與一緻

裝飾模式

裝飾模式可以在不使用創造更多子類的情況下,将對象的功能加以擴充

裝飾模式中的角色有

抽象構件(Component)角色:給出一個抽象接口,以規範準備接受附加責任的對象

具體構件(ConcreteComponent)角色:定義一個将要接受附加責任的類

裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,并定義一個與抽象構件方法一緻的方法

具體裝飾(ConcreteDecorator)角色:負責給構件對象“貼上”附加的責任

Component為統一接口,也是裝飾類和被裝飾類的基本類型。

ConcreteComponent為具體實作類,也是被裝飾類,他本身是個具有一些功能的完整的類。

Decorator是裝飾類,實作了Component接口的同時還在内部維護了一個ConcreteComponent的執行個體,并可以通過構造函數初始化。而Decorator本身,通常采用預設實作,他的存在僅僅是一個聲明:我要生産出一些用于裝飾的子類了。而其子類才是賦有具體裝飾效果的裝飾産品類。

ConcreteDecorator是具體的裝飾産品類,每一種裝飾産品都具有特定的裝飾效果。可以通過構造器聲明裝飾哪種類型的ConcreteComponent,進而對其進行裝飾

public interface Component {    //接口
	public void doThingA();
}


public class Decorator implements Component {
	private Component component = null;
	
	public Decorator(Component component) {
		this.component = component;
	}
	@Override
	public void doThingA() {
		// TODO Auto-generated method stub
		component.doThingA();//調用被裝飾對象的方法
	}

}


public class ConcreteDecorator extends Decorator {

	public ConcreteDecorator(Component component) {
		super(component);
		// TODO Auto-generated constructor stub
	}
	@Override
	public void doThingA() {
		// TODO Auto-generated method stub
		super.doThingA();//調用被包裝類的方法
		doThingB();
	}
	//擴充的功能
	private void doThingB() {
		System.out.println("do B thing");
	}
}


public class ConcreteDecorator2 extends Decorator {

	public ConcreteDecorator2(Component component) {
		super(component);
		// TODO Auto-generated constructor stub
	}
	@Override
	public void doThingA() {
		// TODO Auto-generated method stub
		super.doThingA();//調用被包裝類的方法
		doThingC();
	}
	//擴充的功能
	private void doThingC() {
		System.out.println("do C thing");
	}
}


public class Test {
	public static void main(String[] args) {
		ConcreteComponent component = new ConcreteComponent();
		//component.doThingA();
		ConcreteDecorator decorator1 = new ConcreteDecorator(component);
		//decorator1.doThingA();
		ConcreteDecorator2 decorator2 = new ConcreteDecorator2(decorator1);
		decorator2.doThingA();
	}
}
           

字元流

位元組流提供處理任何類型輸入/輸出操作的足夠功能,但不能直接操作Unicode字元,因而需要字元流

字元流層次結構額頂層是Reader和Writer抽象類

Reader是定義java的流式字元輸入模式的抽象類

Writer是定義流式字元輸出的抽象類,該類方法都傳回void值并在出錯條件下抛IOException

FileReader和FileWriter

FileReader類表示可以讀取檔案内容的Reader類

FileWriter表示可以寫檔案的Writer類

import java.io.*;

public class FileReaderWriter {
	public static void main(String[] args) throws IOException {
        //将一個檔案的字元讀取出來寫到另一個檔案裡去
		FileReader fr = new FileReader("c:\\test\\1.txt");
		FileWriter fw = new FileWriter("c:\\test\\4.txt");
		 char [] buff = new char[100];
		int len = 0; //實際讀到的字元個數
		while((len = fr.read(buff)) != -1) {
			fw.write(buff, 0, len);
		}
		fr.close();
		fw.close();
	}
}
           

BufferedReader和BufferedWriter

BufferedReader通過緩沖輸入提高性能

BufferedWriter通過緩沖輸出提高性能

其他流

ObjectInputStream/OutputStream

InputStreamReader/OutputStreamWriter

RandomAccessFile

ObjectInputStream/OutputStream

ObjectInputStream和ObjectOutputStream分别與FileOutputStream和FileInputStream一起使用時,可以為應用程式提供對對象的持久存儲。我們把對象以某種特定的編碼格式寫入稱之為“序列化”。把寫入的編碼格式内容還原成對象稱之為“反序列化”

被序列化的對象必須實作Serializable接口

ObjectOutputStream将java對象的基本資料類型和圖形寫入OutputStream

writeObject(Object obj):将指定的對象寫入ObjectOutputStream

ObjectInputStream對以前使用ObjectOutputStream寫入的基本資料和對象進行反序列化

readObject():從ObjectInputStream讀取對象

package otherio;

import java.io.*;

public class ObjectInputOutStream {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		//向檔案裡輸入對象,序列化
		Student stu = new Student("zhangsan", 30);
		//FileOutputStream fos = new FileOutputStream("c:\\test\\10.txt");
		//ObjectOutputStream oos = new ObjectOutputStream(fos);
		//與上面的等價
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:\\test\\10.txt"));
		oos.writeObject(stu);//把對象序列化到指定的檔案輸出流中
		oos.close();//釋放資源
		
		//反序列化
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:\\test\\10.txt"));
		try {
			Student stu = (Student)ois.readObject();
			System.out.println(stu);
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
	
	}

}

class Student implements Serializable{
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	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 String toString() {    //覆寫原有類裡的toString方法
		return "Student [name = " + name + ", age =" + age + "]";
	}
	
}

eg:Student [name = zhangsan, age =30]
           

InputStreamReader/OutputStreamWriter

轉換流是指将位元組流與字元流之間的轉換

轉換流的出現友善了對檔案的讀寫, 它在字元流與位元組流之間架起了一座橋梁,使原本毫無關聯的兩種流操作能夠進行轉化,提高了程式的靈活性

位元組流中的資料都是字元時,轉成字元流操作更高效

如果使用非預設編碼儲存檔案或者讀取檔案時,需要用到轉換流,因為位元組流的重載構造方法中有指定編碼格式的參數,而FileReader與FileWriter是預設編碼的文本檔案

常見的編碼表

ASCII:美國标準資訊交換碼,用一個位元組的7位可以表示

ISO8859-1:拉丁碼表,歐洲碼,表示用一個位元組的8位表示

GB2312:中國的中文編碼表

GBK:中國的中文編碼表更新

Unicode:國際标準碼,融合了多種文字,所有文字都用兩個位元組來表示

UTF-8:最多用三個位元組來表示一個字元

InputStreamReader是位元組流通向字元流的橋梁

OutputSteamWriter是字元流通向位元組流的橋梁

package otherio;

import java.io.*;

public class InputStreamWriterReader {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
        //寫入檔案操作
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c:\\test\\10a.txt"), "utf-8");
		BufferedWriter bw = new BufferedWriter(osw);//加了緩沖區
		bw.write("你好");
		bw.close();
		
        //從檔案讀取操作,運用緩沖區
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("c:\\test\\10a.txt"),"utf-8"));
		String line = null;
		while((line = br.readLine())!= null) {
			System.out.println(line);
		}
	}

}

eg:你好
           

RandomAccesFile(随機通路檔案)

支援對随機通路檔案的讀取和寫入

随機通路檔案的行為類似存儲在檔案系統中的一個大型byte數組存在指向該隐含數組的光标或索引,稱為檔案指針

輸入操作從檔案指針開始讀取位元組,随着對位元組的讀取而遷移此檔案指針

如果随機通路檔案以讀取/寫入模式建立,則輸出操作也可用;輸出操作從檔案指針開始寫入位元組,随着對位元組的寫入而前移此檔案指針

寫入隐含數組末尾之後的輸出操作導緻該數組擴充

該檔案指針可以通過getFilePointer方法讀取,通過seek方法設定

package otherio;

import java.io.*;
import java.util.Scanner;

public class RandomAccessFileio {
	public static void main(String[] args) throws IOException{
		Person[] persons = {new Person("lisi",90), new Person("justin",24), new Person("zhangsan",18), new Person("wangwu", 39)};
        //初始化對象
		java.io.RandomAccessFile raf = new java.io.RandomAccessFile("c:\\test\\io.txt", "rw");
		//寫入資料到RandomAccessFile對象中去
		for(int i = 0; i < persons.length; i++) {
			raf.writeChars(persons[i].getName());
			raf.writeInt(persons[i].getAge());
		}
		//讀取指定位置上的的Person對象
		Scanner scanner = new Scanner(System.in);
		int num = scanner.nextInt();    //輸入一個數,取第num個人的姓名和年齡
		//使用seek方法來操作存取位置,從第0個開始,是以要seek-1
		raf.seek((num-1) * Person.size());
		Person person = new Person();
		person.setName(readName(raf));
		person.setAge(raf.readInt());
		System.out.println("姓名" + person.getName());
		System.out.println("年齡" + person.getAge());
		raf.close();
	}
	private static String readName(RandomAccessFile raf) throws IOException {
		char[] name = new char[15];
		for(int i = 0; i < name.length; i++) {
			name[i] = raf.readChar();
		}
		return new String(name).replace('\u0000', ' ');
	}
}
class Person{
	private String name;    //2個位元組,unicode編碼,将名字長度固定為15個字元
	private int age; //4個位元組
	//person一共有34個位元組
    public Person() {
		
	}
	public Person(String name, int age) {
		StringBuilder builder = null;    
        //動态字元串,Stringbuilder預設大小:傳進去字元串+16
		if(name != null) {
			builder = new StringBuilder(name);    //傳過來名字不為空,就等于其名字
		}else {
			builder = new StringBuilder(15);    //為空就等于15
		}
		builder.setLength(15);//設定固定長度為15個,空字元'\u0000'
		this.name = builder.toString() ;
		this.age = age;
	}
	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 static int size() {
		return 34;
	}
}