Java 的I/O中的類和方法講解
Java 的FILE類,以及常用方法
- 檔案和資料夾都是用File代表
-
建立一個檔案物件
使用絕對路徑或者相對路徑建立File物件
// 絕對路徑 File f1 = new File("d:/LOLFolder"); System.out.println("f1的絕對路徑:" + f1.getAbsolutePath()); // 相對路徑,相對於工作目錄,如果在eclipse中,就是專案目錄 File f2 = new File("LOL.exe"); System.out.println("f2的絕對路徑:" + f2.getAbsolutePath()); // 把f1作為父目錄建立檔案物件 File f3 = new File(f1, "LOL.exe"); System.out.println("f3的絕對路徑:" + f3.getAbsolutePath());
2.檔案常用方法
File f = new File("d:/LOLFolder/LOL.exe"); System.out.println("當前檔案是:" +f); //檔案是否存在 System.out.println("判斷是否存在:"+f.exists()); //是否是資料夾 System.out.println("判斷是否是資料夾:"+f.isDirectory()); //是否是檔案(非資料夾) System.out.println("判斷是否是檔案:"+f.isFile()); //檔案長度 System.out.println("獲取檔案的長度:"+f.length()); //檔案最後修改時間 long time = f.lastModified(); Date d = new Date(time); System.out.println("獲取檔案的最後修改時間:"+d); //設定檔案修改時間為1970.1.1 08:00:00 f.setLastModified(0); //檔案重新命名 File f2 =new File("d:/LOLFolder/DOTA.exe"); f.renameTo(f2); System.out.println("把LOL.exe改名成了DOTA.exe"); System.out.println("注意: 需要在D:\\LOLFolder確實存在一個LOL.exe,\r\n才可以看到對應的檔案長度、修改時間等資訊");
// 以字串陣列的形式,返回當前資料夾下的所有檔案(不包含子檔案及子資料夾) f.list(); // 以檔案陣列的形式,返回當前資料夾下的所有檔案(不包含子檔案及子資料夾) File[]fs= f.listFiles(); // 以字串形式返回獲取所在資料夾 f.getParent(); // 以檔案形式返回獲取所在資料夾 f.getParentFile(); // 建立資料夾,如果父資料夾skin不存在,建立就無效 f.mkdir(); // 建立資料夾,如果父資料夾skin不存在,就會建立父資料夾 f.mkdirs(); // 建立一個空檔案,如果父資料夾skin不存在,就會丟擲異常 f.createNewFile(); // 所以建立一個空檔案之前,通常都會建立父目錄 f.getParentFile().mkdirs(); // 列出所有的碟符c: d: e: 等等 f.listRoots(); // 刪除檔案 f.delete(); // JVM結束的時候,刪除檔案,常用於臨時檔案的刪除 f.deleteOnExit();
位元組流
- InputStream位元組輸入流
- OutputStream位元組輸出流
- 用於以位元組的形式讀取和寫入資料
所有的資料存放在計算機中都是以數字的形式存放的。 所以字母就需要轉換為數字才能夠存放。 比如A就對應的數字65,a對應的數字97. 不同的字母和符號對應不同的數字,就是一張碼錶。
以位元組流的形式讀取檔案內容
- InputStream是位元組輸入流,同時也是抽象類,只提供方法宣告,不提供方法的具體實現。
- FileInputStream 是InputStream子類,以FileInputStream 為例進行檔案讀取
try {
//準備檔案lol.txt其中的內容是AB,對應的ASCII分別是65 66
File f =new File("d:/lol.txt");
//建立基於檔案的輸入流
FileInputStream fis =new FileInputStream(f);
//建立位元組陣列,其長度就是檔案的長度
byte[] all =new byte[(int) f.length()];
//以位元組流的形式讀取檔案所有內容
fis.read(all);
for (byte b : all) {
//打印出來是65 66
System.out.println(b);
}
//每次使用完流,都應該進行關閉
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
以位元組流的形式向檔案寫入資料
try {
// 準備檔案lol2.txt其中的內容是空的
File f = new File("d:/lol2.txt");
// 準備長度是2的位元組陣列,用88,89初始化,其對應的字元分別是X,Y
byte data[] = { 88, 89 };
// 建立基於檔案的輸出流
FileOutputStream fos = new FileOutputStream(f);
// 把資料寫入到輸出流
fos.write(data);
// 關閉輸出流
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
字元流
- Reader字元輸入流
- Writer字元輸出流
- 專門用於字元的形式讀取和寫入資料
使用字元流讀取檔案
FileReader 是Reader子類,以FileReader 為例進行檔案讀取
File f = new File("d:/lol.txt");
// 建立基於檔案的Reader
try (FileReader fr = new FileReader(f)) {
// 建立字元陣列,其長度就是檔案的長度
char[] all = new char[(int) f.length()];
// 以字元流的形式讀取檔案所有內容
fr.read(all);
for (char b : all) {
// 打印出來是A B
System.out.println(b);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
使用字元流把字串寫入到檔案
FileWriter 是Writer的子類,以FileWriter 為例把字串寫入到檔案
File f = new File("d:/lol2.txt");
// 建立基於檔案的Writer
try (FileWriter fr = new FileWriter(f)) {
// 以字元流的形式把資料寫入到檔案中
String data="abcdefg1234567890";
char[] cs = data.toCharArray();
fr.write(cs);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
快取流
以介質是硬碟為例,位元組流和字元流的弊端: 在每一次讀寫的時候,都會訪問硬碟。 如果讀寫的頻率比較高的時候,其效能表現不佳。 為了解決以上弊端,採用快取流。 快取流在讀取的時候,會一次性讀較多的資料到快取中,以後每一次的讀取,都是在快取中訪問,直到快取中的資料讀取完畢,再到硬碟中讀取。 就好比吃飯,不用快取就是每吃一口都到鍋裡去鏟。用快取就是先把飯盛到碗裡,碗裡的吃完了,再到鍋裡去鏟 快取流在寫入資料的時候,會先把資料寫入到快取區,直到快取區達到一定的量,才把這些資料,一起寫入到硬碟中去。按照這種操作模式,就不會像位元組流,字元流那樣每寫一個位元組都訪問硬碟,從而減少了IO操作。
使用快取流讀取資料
快取字元輸入流 BufferedReader 可以一次讀取一行資料
File f = new File("d:/lol.txt");
// 建立檔案字元流
// 快取流必須建立在一個存在的流的基礎上
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
)
{
while (true) {
// 一次讀一行
String line = br.readLine();
if (null == line)
break;
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
使用快取流寫出資料
PrintWriter 快取字元輸出流, 可以一次寫出一行資料
File f = new File("d:/lol2.txt");
try (
// 建立檔案字元流
FileWriter fw = new FileWriter(f);
// 快取流必須建立在一個存在的流的基礎上
PrintWriter pw = new PrintWriter(fw);
) {
pw.println("garen kill teemo");
pw.println("teemo revive after 1 minutes");
pw.println("teemo try to garen, but killed again");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
flush
有的時候,需要立即把資料寫入到硬碟,而不是等快取滿了才寫出去。 這時候就需要用到flush
File f =new File("d:/lol2.txt");
//建立檔案字元流
//快取流必須建立在一個存在的流的基礎上
try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
pw.println("garen kill teemo");
//強制把快取中的資料寫入硬碟,無論快取是否已滿
pw.flush();
pw.println("teemo revive after 1 minutes");
pw.flush();
pw.println("teemo try to garen, but killed again");
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
資料流
- DataInputStream 資料輸入流
- DataOutputStream 資料輸出流
直接進行字串的讀寫
驟 1 :
直接進行字串的讀寫
使用資料流的writeUTF()和readUTF() 可以進行資料的格式化順序讀寫 如本例,通過DataOutputStream 向檔案順序寫出 布林值,整數和字串。 然後再通過DataInputStream 順序讀入這些資料。 注: 要用DataInputStream 讀取一個檔案,這個檔案必須是由DataOutputStream 寫出的,否則會出現EOFException,因為DataOutputStream 在寫出的時候會做一些特殊標記,只有DataInputStream 才能成功的讀取。
private static void read() {
File f =new File("d:/lol.txt");
try (
FileInputStream fis = new FileInputStream(f);
DataInputStream dis =new DataInputStream(fis);
){
boolean b= dis.readBoolean();
int i = dis.readInt();
String str = dis.readUTF();
System.out.println("讀取到布林值:"+b);
System.out.println("讀取到整數:"+i);
System.out.println("讀取到字串:"+str);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void write() {
File f =new File("d:/lol.txt");
try (
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos =new DataOutputStream(fos);
){
dos.writeBoolean(true);
dos.writeInt(300);
dos.writeUTF("123 this is gareen");
} catch (IOException e) {
e.printStackTrace();
}
}
物件流
物件流指的是可以直接把一個物件以流的形式傳輸給其他的介質,比如硬碟 一個物件以流的形式進行傳輸,叫做序列化。 該物件所對應的類,必須是實現Serializable介面
序列化一個物件
- 建立一個Hero物件,設定其名稱為garen。
- 把該物件序列化到一個檔案garen.lol。
- 然後再通過序列化把該檔案轉換為一個Hero物件
- 注:把一個物件序列化有一個前提是:這個物件的類,必須實現了Serializable介面
- Hero.java:
public class Hero implements Serializable {
//表示這個類當前的版本,如果有了變化,比如新設計了屬性,就應該修改這個版本號
private static final long serialVersionUID = 1L;
public String name;
public float hp;
}
Hero h = new Hero();
h.name = "garen";
h.hp = 616;
//準備一個檔案用於儲存該物件
File f =new File("d:/garen.lol");
try(
//建立物件輸出流
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos =new ObjectOutputStream(fos);
//建立物件輸入流
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois =new ObjectInputStream(fis);
) {
oos.writeObject(h);
Hero h2 = (Hero) ois.readObject();
System.out.println(h2.name);
System.out.println(h2.hp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
關閉流的方式:
所有的流,無論是輸入流還是輸出流,使用完畢之後,都應該關閉。 如果不關閉,會產生對資源佔用的浪費。 當量比較大的時候,會影響到業務的正常開展。
在try中關閉
在try的作用域裡關閉檔案輸入流,在前面的示例中都是使用這種方式,這樣做有一個弊端; 如果檔案不存在,或者讀取的時候出現問題而丟擲異常,那麼就不會執行這一行關閉流的程式碼,存在巨大的資源佔用隱患。 不推薦使用。
try {
File f = new File("d:/lol.txt");
FileInputStream fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
// 在try 裡關閉流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
在finally中關閉
這是標準的關閉流的方式 1. 首先把流的引用宣告在try的外面,如果宣告在try裡面,其作用域無法抵達finally. 2. 在finally關閉之前,要先判斷該引用是否為空 3. 關閉的時候,需要再一次進行try catch處理 這是標準的嚴謹的關閉流的方式,但是看上去很繁瑣,所以寫不重要的或者測試程式碼的時候,都會採用上面的有隱患try的方式,因為不麻煩~
File f = new File("d:/lol.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally 裡關閉流
if (null != fis)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
使用try()的方式
把流定義在try()裡,try,catch或者finally結束的時候,會自動關閉 這種編寫程式碼的方式叫做 try-with-resources, 這是從JDK7開始支援的技術 所有的流,都實現了一個介面叫做 AutoCloseable,任何類實現了這個介面,都可以在try()中進行例項化。 並且在try, catch, finally結束的時候自動關閉,回收相關資源。
File f = new File("d:/lol.txt");
//把流定義在try()裡,try,catch或者finally結束的時候,會自動關閉
try (FileInputStream fis = new FileInputStream(f)) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}