Java IO 流體系

文件類File

1、java.io.File類:文件和目錄路徑名的抽象表示方式與平臺無關。

2、File能新建、刪除、重命名文件和目錄,但是不能訪問文件本身的內容;File類關心的是磁盤上文件的存儲,而流類關心的是文件的內容。

3、File 類可以作爲參數傳遞流的構造函數。

相對路徑:在當前文件(工程)目錄下文件的路徑。

絕對路徑:包括盤符在內的完整文件路徑。

4、File類的使用的方法

package com.io;
import java.io.File;
/*文件類的一些常用 方法*/
public class FileMethod {
	public static void main(String[] args) {
		File file=new File("E:\\wjq.txt");//使用絕對路徑構造一個File
		String fileName=file.getName();//獲取文件名,包括後綴
		String filePath=file.getParent();//獲取文件路徑,其中file.getAbsolutePath()方法可以獲取絕對路徑 
		long length=file.length();//得到文件的大小 
		long lastModify=file.lastModified();//文件最後更改時間
		boolean IsExist=file.exists();//文件是否存在
		boolean IsHidden=file.isHidden();//文件是否隱藏
		boolean IsFile=file.isFile();//判斷是一個具體的文件不是一個文件夾
		boolean Canread=file.canRead();//文件是否可讀
		boolean IsDirectory=file.isDirectory();//判斷文件是否是一個文件夾
		File [] files=file.listFiles();//表示列出某個文件夾下面的所有文件
		boolean Success=file.renameTo(new File("E:\\wjq_copy.txt"));//爲文件夾更改名字
	}
}
當我們在統計一個文件夾大小時需要遍歷整個文件夾中的文件做一個統計,才能獲取這個文件夾的大小。下面使用遞歸來統計文件夾大小:

package com.io;
import java.io.File;
import java.text.DecimalFormat;
public class ReadFileSize {
	//使用遞歸統計一個文件夾下面所有的文件大小
	public static long getFileSize(File file){
		long size=0;
		File [] files=file.listFiles();
		for(int i=0;i<files.length;i++){
			if(files[i].isDirectory()){
				size=size+getFileSize(files[i]);
			}else{
				size=size+files[i].length();
			}
		}
		return size;
	 }
	  //格式化長度表示
	  public static String formatFileSize(File file){
		  String fileSize="";
		  DecimalFormat df=new DecimalFormat("#.00");
		  long size=getFileSize(file);
		  if(size<1024){
			  fileSize=df.format((double)size)+"B";
		  }else if(size<1048576){
			  fileSize=df.format((double)size/1024)+"KB";
		  }else if(size<1073741824){
			  fileSize=df.format((double)size/1048576)+"MB";
		  }else{
			  fileSize=df.format((double)size/1073741824)+"G";
		  }
		  return fileSize;
	  }
	    //測試
		public static void main(String[] args) {
			File file=new File("E:\\tomcat7");
			String size=ReadFileSize.formatFileSize(file);
			System.out.println(size);
			
		}
}

Java IO 流原理

1、IO流用來處理設備之間的數據傳輸。
2、Java程序中,對於數據輸入/輸出操作以"流(Stream)"的方式進行。
3、輸入:input讀取外部數據(磁盤、光盤等存儲設備的數據)到程序(內存);輸出:output將程序(內存中)數據輸出到磁盤,等外部存儲設備中。
4、原理圖

IO 流的分類

1、IO流的抽象基類 InputStream、OutputStream、Reader、Writer。這四個類是IO流的源頭,這四個類都不能被實例化,所有的子類都是繼承這四個抽象基類。
2、IO流可以根據流向、數據單位、角色進行分類

流向
  • 輸入流       InputStream(字節流,只能讀取英文)                            Reader(字符流,可以讀取所有的字符)
  • 輸出流       OutStream(字節流,只能讀取英文)                              Writer(字符流,可以讀取所有的字符)
數據單位
  • 字節流   讀取視屏、音頻、圖片、二進制文件
  • 字符流   讀取文本文件
 角色
  • 節點流      直接作用在文本文件上(FileInputStream、FileOutputStream、FileReader、FileWriter)
  • 處理流      又稱節緩存流,可以加快節點流的速度,一般作用在節點流上。
2、IO流體系結構

3、不同的IO流使用方式 
a、字節輸入/輸出流  FileInputStream/FileOutputStream
FileInputStream  使用
package com.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/*字節流*/
public class FileIn_OutStreamTest {
   //測試
   public static void main(String[] args) {
	   FileIn_OutStreamTest.TestFileInputStream();
   }
   //從硬盤存在的一個文件中,讀取內容 到內存中
 	public static void TestFileInputStream(){
 		FileInputStream fis=null;
 		try{
 			//1、創建一個文件
 			File file=new File("E:\\test.txt");
 			//2、創建一個FileInputStream類的對象 
 			fis=new FileInputStream(file);
 			byte [] b=new byte[5];//一次讀取1024個字節,寫到這個字節數組裏面
 			int len;//每次讀入到byte中字節的長度
                        //3、將文件內容讀取到內存並寫出到控制檯
 			while((len=fis.read(b))!=-1){
 				String str=new String(b,0,len);
 				System.out.print(str);
 			}
 		}catch(Exception e){
 			e.printStackTrace();
 		}finally{
 				try {
 					fis.close(); //4、關閉相應的流
 				} catch (IOException e) {
 					e.printStackTrace();
 				}
 			}
 		}
 	}
FileOutputStream  使用
package com.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/*字節流*/
public class FileIn_OutStreamTest {
   //測試
   public static void main(String[] args) {
	   FileIn_OutStreamTest.TestFileOutputStream();
   }
    //從內存中將流寫出到一個文件
 	public static void TestFileOutputStream(){
 		//1、創建一個file對象
 		File file=new File("E:\\test.txt");
 		//2、創建一個FileOutputStream對象 
 		FileOutputStream fos=null;
 		try{
 			//3、寫入到目標文件中
 			fos=new FileOutputStream(file);
 			fos.write(new String("I love china").getBytes());
 		}catch(Exception e){
 			e.printStackTrace();
 		}finally{
 			try {
 				fos.close();//4、關閉資源
 			} catch (IOException e){
 				e.printStackTrace();
 			}
 		}
 	}
}
由上述代碼,可以得出使用字節輸入/輸出流的一般步驟爲:
新建一個目標文件File類----->創建一個FileInputStream或FileOutputStream對象將File類作爲形參傳入--->調用相應的方法,讀取/寫入 文件---->最後關閉相應的資源。
b、字符輸入/輸出流  FileReader/FileWriter 對於非文本文件(視頻、圖片、音頻)只能用字節流。
FileReader
package com.io;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/*字節流*/
public class FileReader_WriterTest {
   //測試
   public static void main(String[] args) {
	   FileReader_WriterTest.TestFile_Reader();
   }
	//字符流:從硬盤存在的一個文件中,讀取內容 到內存中
	public static void TestFile_Reader(){
		File file=new File("E:\\test.txt");//1、創建一個file對象
		FileReader fr=null;//2、創建一個FileReader對象
		try{
			fr=new FileReader(file);
			char [] c=new char[20];
			int len;
			while((len=fr.read(c))!=-1){//3、讀入到內存的過程 
				String str=new String(c, 0, len);
				System.out.print(str);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				fr.close();//4、關閉相應的流
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
FileWriter
package com.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/*字節流*/
public class FileReader_WriterTest {
   //測試
   public static void main(String[] args) {
	   FileReader_WriterTest.TestFile_Writer();
   }
	//字符流:從硬盤存在的一個文件中,讀取內容 到內存中
	public static void TestFile_Writer(){
		File file=new File("E:\\test.txt");//1、創建一個file對象
		FileWriter wr=null;//2、創建一個FileWriter對象
		try{//3、寫入到文件。
			wr=new FileWriter(file);
			wr.write("this is a FileWriter Test!".toCharArray());
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				wr.close();//4、關閉相應的流
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
由上述代碼,可以得出使用字符輸入/輸出流的一般步驟爲:
新建一個目標文件File類----->創建一個FileReader或FileWriter對象將File類作爲形參傳入--->調用相應的方法,讀取/寫入 文件---->最後關閉相應的資源。
c、緩存輸入/輸出流(BufferInputStream/BufferOutputStream),這是一個處理流,一般都是作用在節點流上,其作用是提高存儲效率。下面用緩存流來實現一個文件的拷貝過程:
package com.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*緩存流*/
public class FileReader_WriterTest {
   //測試
   public static void main(String[] args) {
	   FileReader_WriterTest.TestBuffered_input_output_Stream();
   }
 //緩衝流:BufferedInputStream BufferedOutputStream  實現文件的複製 
 	public static void TestBuffered_input_output_Stream() {
 		//1、提供讀入、寫出文件
 		File file_in=new File("E:\\test.txt");
 		File file_out=new File("E:\\test_copy.txt");
 		//定義兩個緩存流
 		BufferedInputStream bis=null;
 		BufferedOutputStream bos=null;
 		try{
 			//2、先創建相應的節點流FileInputStream,FileOutputStream
 			FileInputStream fis=new FileInputStream(file_in);
 			FileOutputStream fos=new FileOutputStream(file_out);
 			//3、將創建的節點流的對象作爲形參傳遞給緩衝流的構造器中
 			bis=new BufferedInputStream(fis);
 			bos=new BufferedOutputStream(fos);
 			byte [] b=new byte[1024];
 			int len;
 			while((len=bis.read(b))!=-1){
 				bos.write(b, 0, len);
 				bos.flush();//刷新清空一下
 			}
 		}catch(Exception e){
 			e.printStackTrace();
 		}finally{
 			try {
 				bos.close();//關閉資源的順序要注意
 				bis.close();
 			} catch (IOException e) {
 				e.printStackTrace();
 			}
 		}
 	}
}
d、轉換流InputStreamReader  OutputStreamWriter (處理流)
    輸入型的字節流 ----------------------->輸入型的字符流
    輸出型的字節流------------------------>輸出型的字符流
其具體實現過程,此處就不是敘述。
e、標準的輸出/輸入流(System.out  ,System.in)  
f、打印流(PrintStream,PrintWriter)都是輸出流,也屬於節點流。
g、數據流(DataInputStream,DataOutputStream),用來處理基本數據類型,String、字節數組的數據 ,數據流屬於處理流,需要套接在InputStream,OutputStream。
h、對象流(ObjectInputStream,ObjectOutputStream),它可以把java中的對象寫人到數據源中,也能把對象從數據源中還原。
  • 對象序列化機制:允許把內存中的java對象轉換成與平臺無關的二進制流,從而允許把這種二進制流持久的保存在磁盤上(序列化),通過網絡將這種二進制流傳輸到另一個網絡節點,當其它程序獲取了這種二進制流,就可以將其恢復成原來的Java對象(反序列化)。
  • 對象類,想要實現序列化的要求:要求此類是可以序列化的,即此類實現了Serializable接口;類的屬性同樣也實現了Serializable接口;不能序列化static和transient聲明的變量。
下面是用對象流來實現對對象的深度拷貝:
package com.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class CopyObject {
	public static void main(String[] args) throws IOException,ClassNotFoundException,CloneNotSupportedException{
		Student stu=new Student(1,"admin","admin");
		//deep copy
		/*將對象寫入到內存流中*/
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		ObjectOutputStream oos=new ObjectOutputStream(bos);
		oos.writeObject(stu);
		/*從內存中將對象通過流的方式讀出來*/
		ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois=new ObjectInputStream(bis);
		Object deepCopy=ois.readObject();
		System.out.println("deepCopy:"+deepCopy);
	}
}
class Student implements Serializable{
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String userName;
	private String password;
    public Student(Integer id, String userName, String password) {
		super();
		this.id = id;
		this.userName = userName;
		this.password = password;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
      @Override
    public String toString() {
    	// TODO Auto-generated method stub
    	return "Student[id:"+id+", userName:"+userName+", password:"+password+"]";
    }
}
i、RanomAccessFile類,支持隨機訪問的方式 ,程序可以直接跳到文件的任意位置來讀寫文件
  • 支持只訪問文件的部分內容
  • 支持在已經存在的文件後追加內容
  • 構造器:public RandomAccessFile(File file,String mode) 其中mode表示訪問模式,必須指定,這裏mode有四種方式:r:表示只讀方式打開文件;rw:表示寫以讀寫文件;rwd:讀寫、同步文件內容更新;rws:同步文件內容和源數據更新
下面是使用RandomAccessFile類對文件進行讀寫:
package com.io;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
/*RandomAccessFile:支持隨機訪問
 * 1、既可以充當一個輸入流,也可以充當一個輸出流
 * 2、支持從文件的開頭讀取、寫入
 * 3、支持從任意位置的讀取、寫入 
 * */
public class RandomAccessFile_Test {
	public static void main(String[] args) {
		RandomAccessFile_Test.RandomAccessFile_read_write();
	}
	public static void RandomAccessFile_read_write(){
		RandomAccessFile raf1=null;
		RandomAccessFile raf2=null;
		try{
			raf1=new RandomAccessFile(new File("person.txt"), "r");//讀取一個文件
			raf2=new RandomAccessFile(new File("person.txt"), "rw");//寫出一個文件
			byte[] b=new byte[20];
			int len;
			while((len=raf1.read(b))!=-1){
				raf2.write(b,0,len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				raf2.close();
				raf1.close();
			} catch (IOException e){
				e.printStackTrace();
			}
		}
	}
	public static void write_position(){//指定位置的寫入
		RandomAccessFile raf1=null;
		try{
			raf1=new RandomAccessFile(new File("person.txt"), "rw");
			//指定位置,實現插入的效果(默認是覆蓋)
			raf1.seek(3);
			byte [] b=new byte[10];
			int len;
			StringBuffer sb=new StringBuffer();
			while((len=raf1.read(b))!=-1){
				sb.append(new String(b,0,len));
			}
			raf1.seek(3);
			raf1.write("xy".getBytes());
			raf1.write(sb.toString().getBytes());
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				raf1.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
上面只是介紹了幾種比較常用的流,其它沒提及的流大家可以參考JDK API。






發佈了109 篇原創文章 · 獲贊 39 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章