IO的核心組成就是五個類(File
、 OutputStream
、InputStream
、Reader
、Writer
) 一個接口(Serializable
)
File文件操作類
在Java.io包之中,File類是唯一一個與文件本身操作(創建、刪除、取得信息…)有關,與文件內容無關的的程序類。
File類即可以描述真實文件,也可以是個文件夾
File類使用
- File類的兩種實例化方式:
public File(String pathname)
public File(String parent, String child)
- 創建新文件
public boolean createNewFile() throws IOException
- 判斷文件是否存在
public boolean exits()
- 刪除文件
public boolean delete()
範例:編寫文件的基本操作(如果文件不存在則進行創建;存在則刪除)
package www.bit.FileTest;
import java.io.File;
import java.io.IOException;
public class MyFile {
public static void main(String[] args) {
// 定義要操作的文件路徑
// 路徑分隔符:File.separator
File file = new File("C:"+File.separator+"Users"+File.separator
+"DELL"+File.separator+"Desktop"+File.separator+"TestIO.java");
if (file.exists()){
file.delete();
}else{
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
有關目錄的操作
- 取得父路徑與父File對象
public String getParent()
public File getParentFile()
- 創建目錄(無論有多少級父目錄,都會一次性創建)
public boolean mkdirs()
範例:Java文件目錄操作
import java.io.File;
import java.io.IOException;
public class MyFile {
public static void main(String[] args) throws IOException{
File file = new File("C:"+File.separator+"Users"+File.separator
+"DELL"+File.separator+"Desktop"+File.separator+"Test"+
File.separator+"Java IO"+File.separator+"TestIO.java");
if (!file.getParentFile().exists()){ // 創建父目錄
file.getParentFile().mkdirs(); // 有多少級父目錄就創建多少級
}
if (file.exists()){
// 文件存在,進行刪除
file.delete();
}else {
file.createNewFile();
}
}
}
文件信息
- 判斷File對象是否是文件
public boolean isFile()
- 判斷File對象是否是路徑
public boolean isDirectory()
- 取得文件大小
public long length()
- 取得最後修改日期
public long lastModified()
範例:取得文件信息
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class MyFile {
public static void main(String[] args) throws IOException{
File file = new File("C:"+File.separator+"Users"+File.separator
+"DELL"+File.separator+"Desktop"+File.separator+"sifanchao.jpg");
if (file.exists() && file.isFile()){
System.out.println("文件大小:" + file.length()/1024 + "Kb");
System.out.println("最後一次修改日期: " + new Date(file.lastModified()));
}
}
}
- 列出一個目錄的全部組成:
public File[] listFiles()
範例:列出C盤目錄中的全部組成
import java.io.File;
public class MyFile {
public static void main(String[] args){
new Thread(()-> {
File file = new File("C:");
// 列出桌面目錄中的全部組成
// +File.separator+"Users"+File.separator+"DELL"+File.separator+"Desktop"
System.out.println("遍歷文件開始...");
long start = System.currentTimeMillis();
listAllFiles(file);
long end = System.currentTimeMillis();
System.out.println("遍歷文件結束。共耗時:" + (end-start) + "毫秒");
}).start();
}
public static void listAllFiles(File file){
if (file.exists() && file.isFile()){
System.out.println(file);
}else {
File[] files = file.listFiles();
if (files != null){
for (File file1 : files){
listAllFiles(file1);
}
}
}
}
}
IO相關處理屬於阻塞式耗時操作,一般放在子線程中進行
字節流與字符流
File類不支持文件內容處理,如果要處理文件內容,必須要通過流的操作模式來完成。流分爲輸入流和輸出流。 在java.io包中,流分爲兩種:字節流與字符流
- 字節流:InputStream、OutputStream
- 字符流:Reader、Writer
字節流與字符流操作的本質區別只有一個:字節流是原生的操作,而字符流是經過處理後的操作。
一般使用字節流(無論是網絡傳輸還是磁盤數據保存均以字節爲單位)。
而所有磁盤中的數據必須先讀取到內存後才能進行操作,內存中會幫助我們把字節變爲字符。所以,只有處理中文文本時纔會用到字符流。
流操作流程
無論是字節流還是字符流,操作流程幾乎一樣,以文件操作爲例:
- 取得File對象
- 取得File對象的輸入、輸出流
- 進行數據的讀取或寫入
- 關閉流(close)
對於IO操作屬於資源處理,所有的資源處理操作(IO操作、數據庫操作、網絡)後必須要進行關閉。
字節輸出流(OutputStream)
如果要想通過程序進行內容輸出,則可以使用java.io.OutputStream
。
public abstract class OutputStream implements Closeable, Flushable
OutputStream類實現了Closeable,Flushable兩個接口,這兩個接口中的方法:
- Closeable:
public void close() throws IOException
; - Flushable:
public void flush() throws IOException
;
在OutputStream類中還定義有其他方法:
- 將指定的字節數組全部輸出
public void write(byte[] b)throws IOException
- 將部分字節數組輸出
public void write(byte[] b,int offset,int len)throws IOException
- 輸出單個字節
public abstract void write(int b)throws IOException
由於OutputStream是一個抽象類,所以要想爲父類實例化,就必須要使用子類。由於方法名稱都由父類聲明好 了,所以我們在此處只需要關心子類的構造方法。如果要進行文件的操作,可以使用FileOutputStream類來處理, 這個類的構造方法如下:
- 文件內容覆蓋
public FileOutputStream(File file) throws FileNotFoundException
- 文件內容追加
public FileOutputStream(File file, boolean append) throws FileNotFoundException
範例:實現文件的內容輸出
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class MyFile {
public static void main(String[] args) throws Exception{
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){ // 必須保證父目錄存在
file.getParentFile().mkdirs(); // 創建多級父目錄
}
// OutputStream是一個抽象類,所以需要通過子類進行實例化,
// 此時只能操作File類
OutputStream outputStream = new FileOutputStream(file);
// 要求輸出到文件的內容
String msg = "你好,中國!";
outputStream.write(msg.getBytes());
outputStream.close();
}
}
當使用FileOutputStream
進行文件內容輸出時時候,只要文件的父路徑存在,所有的文件會自動幫助用戶創建,不在需要調用createFile()
方法手工創建。
這個時候程序如果重複執行,並不會出現內容追加的情況而是一直在覆蓋。如果需要文件內容追加,則需要調用 FileOutputStream提供的另外一種構造方法。
範例:文件內容追加
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class MyFile {
public static void main(String[] args) throws Exception{
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
// true表示允許內容的追加操作
OutputStream outputStream = new FileOutputStream(file,true);
String msg = "我愛你\r\n";
outputStream.write(msg.getBytes());
outputStream.close();
}
}
AutoCloseable自動關閉支持
從JDk1.7開始追加了一個AutoCloseable接口,這個接口的主要目的是自動進行關閉處理,但是這種處理一般不好用,因爲使用自動關閉接口有一個前提,需要結合try…catch…代碼塊。
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class MyFile {
public static void main(String[] args) throws Exception{
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
try (OutputStream outputStream = new
FileOutputStream(file,true)){
String msg = "改革開放40週年\r\n";
outputStream.write(msg.getBytes());
}catch (Exception e) {
e.printStackTrace();
}
}
}
字節輸入流:InputStream
利用了OutputStream實現了程序輸出內容到文件的處理,下面使用InputStream類在程序中讀取文件內容。 InputStream類的定義如下:
public abstract class InputStream implements Closeable
- 讀取數據到字節數組b中
public int read(byte b[]) throws IOException
返回值三種情況:
- 返回b長度:當讀取的數據大小>字節數組大小,返回字節數組大小
- 返回大於0但是小於b長度:當讀取的數據大小<字節數組大小,返回真正讀取大小
- 返回-1:數據讀取完畢
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyFile {
public static void main(String[] args) throws Exception{
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (file.exists()){
InputStream inputStream = new FileInputStream(file);
// 每次可以讀取的大數量
byte[] data = new byte[1024];
// 此時的數據讀取到了數組之中
int len = inputStream.read(data);
System.out.println(new String(data,0,len));
inputStream.close();
}
}
- 讀取單個字節
public int read() throws IOException
字符輸出流Writer
字符適合於處理中文數據,Writer是字符輸出流的處理類,這個類的定義如下:
public abstract class Writer implements Appendable, Closeable, Flushable
與OutputStream
相比多了一個Appendable
接口。 在Writer類裏面也提供write()方法,而且該方法接收的類提供了一個直接輸出字符串的方法:
public void write(String str) throws IOException
範例:通過Writer實現輸出
import java.io.*;
public class MyFile {
public static void main(String[] args) throws Exception {
// 取得File對象
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
// 取得輸出流
Writer out = new FileWriter(file);
// 寫入數據
String msg = "你好,世界!" ;
out.write(msg);
// 關閉
out.close();
}
}
Writer
類的結構與方法的使用與OutputStream
非常相似,只是Writer類對於中文的支持很好並且提供了直接寫入 String的方法而已。
字節的輸入流Reader
Reader依然也是一個抽象類。如果要進行文件讀取,同樣的,使用FileReader。
在上面講到的Writer類中提供有方法直接向目標源寫入字符串,Reader類中沒有方法可以直接讀取字符串,只能通過字符數組來讀取。
import java.io.*;
public class MyFile {
public static void main(String[] args) throws Exception {
// 取得File對象
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
// 取得輸入流
Reader reader = new FileReader(file);
// 讀入數據
char[] data = new char[1024];
int len = reader.read(data);
System.out.println(len);
System.out.println(new String(data,0,len));
reader.close();
}
}
字符流適合處理中文,字節流適合處理一切數據類型(對中文支持不好)
字符流VS字節流
- 從實際開發來講,字節流優先考慮,只有處理中文時纔會考慮使用字符流
- 所有字符流操作,無論是寫入還是輸出,數據都先保存在緩存中
如果字符流不關閉,數據就有可能保存在緩存中並沒有輸出到目標源。這種情況下就必須強制刷新才能夠得到完整數據。
import java.io.*;
public class MyFile {
public static void main(String[] args) throws Exception {
// 取得File對象
File file = new File("C:" + File.separator + "Users" + File.separator
+ "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
// 取得輸出流
Writer out = new FileWriter(file);
// 寫入數據
String msg = "你好,世界!" ;
out.write(msg);
out.flush();
}
}