1. 程式人生 > 其它 >java-檔案輸入輸出處理

java-檔案輸入輸出處理

---------------------------------------------------

1、File類

File類是IO包中唯一代表磁碟檔案本身的物件,File類定義了一些與平臺無關的方法來操作檔案。通過呼叫File類提供的各種方法,能夠完成建立、刪除檔案、重新命名檔案、判斷檔案的讀寫許可權許可權是否存在、設定和查詢檔案的最近修改時間等操作。

​ File類沒有無參構造方法,最常用的是使用下面的構造方法來生成File物件(注意分隔符可以使用"/"和"",但是使用""必須寫"\",因為涉及轉義的問題):

File(String pathName) pathName指的是檔案的路徑名;

File.separator

在Windows下的路徑分隔符(\)和在Linux下的路徑分隔符(/)是不一樣的,當直接使用絕對路徑時,跨平臺會報No Such file or diretory異常。

File中還有幾個與separator類似的靜態常量,與系統有關,在程式設計中應儘量使用。

//File.separator 表示不同系統下的路徑分割符
File file = new File("D:"+File.separator+"test"+File.separator+"test1");
//File file = new File("D:/test/test1.txt");

2、建立檔案

建立檔案物件 File(String pathname)

//pathname 檔案路徑
File file = new File("D:/test/test1.txt");

建立檔案 createNewFile()

File file = new File("D:/test");
//判斷檔案是否存在,不存在,建立
if(!file.exists()){
    try {
        //判斷檔案是否建立成功
        //createNewFile方法,會返回是否建立成功的結果,true成功,false失敗
        if(file.createNewFile()){
            System.out.println("建立檔案"+file.getName()+"成功");
        }else{
            System.out.println("建立檔案"+file.getName()+"失敗");
        }
    } catch (IOException e) {
        e.printStackTrace();
 }

3、建立目錄(單級,多級)

mkdir() 建立單級目錄
mkdirs() 建立多級目錄

建立單級目錄 mkdir()

File dir = new File("D:/test/test1");//目前只有text資料夾
//判斷目錄是否存在,如果不存在則建立
if(!dir.exists()){
    //mkdir方法,建立目錄,返回是否建立成功的結果
    //mkdirs方法,建立多級目錄
    if(dir.mkdir()){
    	System.out.println("建立目錄成功"); //生成test1資料夾
    }else{
    	System.out.println("刪建立目錄失敗");
    }
}else{
    System.out.println("目錄存在,不需要建立");
}

建立多級目錄 mkdirs()

File dirs = new File("D:/test/test1/text1_1"); //目前只有text資料夾
//改變引數和方法即可
if(dirs.mkdirs()){
	System.out.println("建立目錄成功"); //生成test1資料夾及子資料夾text1_1
}else{
	System.out.println("刪建立目錄失敗");
}

4、刪除檔案或目錄(只能刪除單級空目錄)

delete()

//存在則刪除,不存在,提示
File file = new File("目錄或檔案路徑"); 
if(file.exists()){
    // delete方法,刪除檔案或者目錄,並會返回是否刪除成功的結果,true-成功,false-失敗
    //注意:刪除目錄,只能刪除當前以及的目錄,並且只能是空目錄
    if(file.delete()){
   	 	System.out.println("刪除檔案或目錄成功");
    }else{
    	System.out.println("刪除檔案或目錄失敗");
    }
}else{
	System.out.println("檔案或目錄不存在");
}
JAVA 複製 全屏

5、File類中常見方法

file.getName() 檔名稱
file.length() 檔案大小
file.getPath() 檔案路徑
file.getAbsolutePath() 檔案絕對路徑

還有其他方法可以直接檢視;

--------------------------------------------------

1、FileInputStream

1.1 初始化

FileInputStream(String name)
FileInputStream(File file)
//直接通過檔案地址初始化
FileInputStream fis = new ileInputStream("D:/test/test1.txt");

//通過File物件初始化
File file = new File("D:/test/test1.txt");
FileInputStream fis = new FileInputStream(file)

1.2 獲取檔案大小

available()

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
fis.available(); //檔案大小

1.3 讀取檔案內容

read() 讀取一個位元組(返回對應位元組的ascii碼值)
read(byte b[]) 根據位元組緩衝陣列的長度,進行讀取(返回讀取的位元組數)

read()

//檔案 D:/test/test1.txt 
內容
KH96abcdefghijk
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
 while (true){
     //read() 方法:從輸入流物件中,一次讀取一個位元組(返回的是對應位元組的ascii碼值,int型別)
     int hasRead = fis.read();

     //當讀取到末尾,返回-1,代表檔案讀取結束
     if(hasRead == -1){
         break;
     }

     System.out.print((char) hasRead); 
     //列印檔案中字元的ascii值
     //轉化為字元:KH96abcdefghijk
 }

 //最後一定要關閉資源
 fis.close();

執行結果:

原始檔的大小:15
KH96abcdefghijk

read(byte b[])

帶緩衝位元組數,讀取檔案內容,一次讀取就不是一個位元組,而是根據位元組緩衝陣列的長度,進行讀取

錯誤案例

讀取時通過read()來判斷是否繼續迴圈,讀取到錯誤值

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//帶緩衝位元組數,根據位元組緩衝陣列的長度,進行讀取
byte[] bytes = new byte[5];
//容易出錯的判斷方式:read()方式執行一次,就讀取一個位元組(沒有儲存,讀完就扔,位元組丟失),不可以作為判斷條件
while(fis.read() != -1){
    //迴圈讀取內容
    //帶緩衝陣列的讀取,方法返回的是讀取的位元組數,不是讀取的內容
    //每次讀取的資料,是由緩衝位元組陣列長度決定,每次都是從上一次讀取的位置後開始繼續讀取,每次都是將讀取的內容依次放入快取陣列
    int hasRead = fis.read(bytes);
    System.out.println("讀取的位元組數:"+hasRead);
    System.out.println(new String(bytes));
    System.out.println("讀取檔案成功");
}
fis.close();

執行結果:

原始檔的大小:15
讀取的位元組數:5
H96ab       //K丟失
讀取檔案成功
讀取的位元組數:5
defgh        //c丟失
讀取檔案成功
讀取的位元組數:2
jkfgh        //i丟失,並且還多出了上一次留下 dgh,這是因為沒有讀滿緩衝位元組陣列,而造成的讀取上一次的值
讀取檔案成功

正確案例

因為帶位元組緩衝陣列返回的時讀取到的長度,所以,用讀取到的長度來判斷是否要繼續讀取,和要寫入多少個位元組;

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//帶緩衝位元組數,根據位元組緩衝陣列的長度,進行讀取
byte[] bytes = new byte[5];
//正確寫法
int hasRead = 0;
while((hasRead = fis.read(bytes)) > 0){
    //每次讀取的內容
    System.out.println(new String(bytes,0,hasRead));
}
fis.close();

執行結果:

原始檔的大小:15
KH96a
bcdef
ghijk
// 沒有丟失位元組

1.4 資源關閉

close();

​ 在使用流資源的時候一定要關閉資源,否則會造成資源浪費;

放在try( ) 裡面

​ JDK1.7以後,只需將資源初始化放在try()裡面就可以不用手動關閉流資源;

2、FileOutputStream

2.1初始化

FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)

與FileInputStream類似,不過寫入的檔案不一定要存在,如果檔案不存在,會自動建立一個空的檔案;

2.2 寫入方式 boolean append

boolean append 使用否以追加方式方式寫入;

false(預設值,覆蓋)
true(追加)

2.3 寫入檔案內容

write(byte b[])
write(byte b[], int off, int len)
String string = "KH96班,正在學習檔案輸出流,輸出檔案2";
//File file = new File("D:/test/test2.txt");

//JDK1.7以後,只需將資源初始化放在try()裡面就可以不用手動關閉流資源,推薦使用;
try(FileOutputStream fos =  new FileOutputStream("D:/test/test2.txt",true)){

    //將字串轉成位元組陣列,寫入目標檔案
    fos.write(string.getBytes());

    //手動重新整理緩衝區
    fos.flush();
    
}catch (IOException e){
    e.printStackTrace();
}

---------------------------------------------------

FileReader字元流讀取檔案,更適合用於讀取檔案,可以讀取中文;

常用字元流類關係圖

1、FileReader

1.1 初始化

FileReader(File file)
FileReader(String fileName)

1.2 讀取檔案內容

read() 按單個字元讀取
read(char cbuf[]) 按字元陣列長度讀取

案例:按字元陣列讀取

//test1.txt檔案內容:FileWriter測試內容
try(
    //初始化字元讀取流
    FileReader frd =   new FileReader("D:/test/test1.txt");
){
    //定義一個可變字串物件
    StringBuilder sbd = new StringBuilder();

    //定義緩衝字元陣列
    char[] chars = new char[5];

    int hasRead = 0; //讀取到的字元長度
    while((hasRead = frd.read(chars))>0){
        sbd.append(new String(chars,0,hasRead));
        System.out.println("每次讀取:"+sbd.toString());
    }

    //輸出檔案內容
    System.out.println("檔案全部內容:"+sbd.toString());
    System.out.println("檔案讀取成功!");

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

執行結果

每次讀取:FileW
每次讀取:FileWriter
每次讀取:FileWriter測試內容
檔案全部內容:FileWriter測試內容
檔案讀取成功!

2、FileWriter

2.1 初始化

FileReader(String fileName)
FileReader(File file)

2.2 寫入檔案內容

write(String str)
write(String str, int off, int len)
write(char cbuf[])
write(char cbuf[], int off, int len)

案例:字元流直接寫入字串

 //FileWriter 字元流寫檔案基本用法,可以直接寫字元
      
try( FileWriter fwr=  new FileWriter("D:/test/test2.txt")){

    //定義寫入檔案
    String string = "KH96,正在學習字元流寫入檔案";

    //直接寫入目標檔案
    fwr.write(string);

    //重新整理緩衝區
    fwr.flush(); //一定要重新整理緩衝區

    System.out.println("字元流寫入成功!!!");
}catch (Exception e){
    e.printStackTrace();
}
JAVA 複製 全屏

執行結果

字元流寫入成功!!!

-----------------------------------------------------

1、BufferedReader

BufferedReader高效字元流讀取檔案基本用法,自帶緩衝區,讀取檔案效率高,支援逐行讀取;

1.1 初始化

BufferedReader(Reader in) 預設緩衝字元陣列(大小8192)
BufferedReader(Reader in, int sz) 自定義緩衝字元陣列大小

1.2 讀取檔案內容

buffer1.txt檔案內容

張三,23
李四,34
王五,34

逐行讀取案例

try(BufferedReader bfrd = new BufferedReader(new FileReader("D:/test/buffer1.txt"))){
    //使用逐行讀取方式,讀取檔案
    String readLinestr = bfrd.readLine();

    //當讀取內容為null的時候跳出迴圈
    while(readLinestr != null){
        System.out.println(readLinestr);
        //繼續讀取下一行
        readLinestr = bfrd.readLine();
    }

    System.out.println("逐行讀取成功");

}catch (Exception e){
    e.printStackTrace();
}

執行結果

張三,23
李四,34
王五,34
逐行讀取成功

1.3 預設緩衝區

//預設緩衝區的大小為:8192個字元

原始碼

public BufferedReader(Reader in) {
    this(in, defaultCharBufferSize); //使用預設字元陣列容量
}

private static int defaultCharBufferSize = 8192; //預設最大值為8192

2、BufferedWriter

BufferedWriter高效字元流寫入檔案基本用法,可以直接寫整行,還可以換行(newLine());

2.1 初始化

BufferedWriter(Writer out) 預設緩衝字元陣列(大小8192)
BufferedWriter(Writer out, int sz) 自定義緩衝字元陣列大小

2.2寫入檔案內容

try(BufferedWriter bfwt = new BufferedWriter(new FileWriter("D:/test/buffer2.txt"))){
    //寫入內容
    String string = "KH96,正在學習高效字元流寫入";
    //寫入
    bfwt.write(string);
    //換行
    bfwt.newLine();
    bfwt.write(string+",新的一行");
    
    //重新整理緩衝區
    bfwt.flush();

    System.out.println("高效字元寫入完成");

}catch (Exception e){
    e.printStackTrace();
}

3、InputStreamReader

InputStreamReader(InputStream in) 預設本地字符集
InputStreamReader(InputStream in, String charsetName) 自定義字符集

BufferedReader 通過InputStreamReader可以指定字符集讀取檔案的內容;

  try(
      //InputStreamReader提供了一個指定字符集的構造方法,建立輸入字元物件,必須指定字符集跟檔案字符集一致
      BufferedReader bfrd = new BufferedReader(new InputStreamReader(new FileInputStream("D:/test/end1.txt"),"gbk"))
  ){
      //使用逐行讀取方式,讀取檔案
      String readLinestr = bfrd.readLine();

      //迴圈讀取,讀取到檔案末尾,返回null
      while(readLinestr != null){
          System.out.println(readLinestr);
          //繼續讀取下一行
          readLinestr = bfrd.readLine();
      }
      System.out.println("逐行讀取成功");

  }catch (Exception e) {
      e.printStackTrace();
  }

4、 OutputStreamWriter

OutputStreamWriter(OutputStream out) 預設本地字符集
OutputStreamWriter(OutputStream out, String charsetName) 自定義字符集

BufferedWriter 通過OutputStreamWriter可以指定字符集寫入檔案的內容;

  try(
        BufferedWriter bfrwt = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:/test/end1.txt"),"gbk"))
        ){
            String str = "測試指定檔案字符集為gbk寫入";
            bfrwt.write(str);

            System.out.println("檔案寫入完成!!!");

        }catch (Exception e) {
            e.printStackTrace();
        }

----------------------------------------------------

1、例項化

DataInputStream(InputStream in) 引數是一個位元組輸入流
DataOutputStream(OutputStream out) 引數是一個位元組輸出流

演示

DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));

2、舉例

複製圖片

 try(
  DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
  DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));
 ){	

     //字元緩衝區
     byte[] bytes = new byte[10];

     //讀取長度
     int hasread = 0;

     while((hasread = dis.read(bytes))>0){
         dos.write(bytes,0,hasread);
     }

     //重新整理緩衝區
     dos.flush();

     System.out.println("圖片複製成功");

 }catch (Exception e){
     e.printStackTrace();
 }

----------------------------------------------------

序列號

  • 序列號是序列化和反序列化的唯一標識,是一個長整型數值;
  • 如果類中不自己定義序列號,系統會自動生成一個序列號;
  • 當一方實體類發生改變,而呼叫方的序列號是不會跟著改變的,不知道物件已修改,會導致兩邊序列號不一致,反序列化失敗;
  • 所以要求必須手動生成一個序列號;
  • 手動生成序列號後,可以解決目標類發生改變,不影響介面呼叫,物件可以正確序列化,不過物件修改的屬性返序列化後沒有值;

序列化物件類

//如果要支援序列化操作必須實現序列化介面
//賬戶類
public class Account implements Serializable {
	//手動生成序列號
    private static final long serialVersionUID = 2116137267832764072L;
    
    //賬戶名
    private  String aname;

    //賬戶密碼
    private String apwd;
    
    //set,get方法省略
    
    @Override
    public String toString() {
        return "Account{" +
                "aname='" + aname + '\'' +
                ", apwd='" + apwd + '\'' +
                '}';
    }
}    

IDEA如何生成序列號

序列化

使用ObjectOutputStream 類的 writeObject(Object obj)方法

//序列化物件,寫入檔案
public static void xlhAccount() throws IOException {
    Account account = new Account("KH96","12345");

    //使用物件輸出流,將記憶體中的物件寫入到檔案
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test/account.txt"));
    
    //直接寫入物件
    oos.writeObject(account);

    oos.close();
    System.out.println("序列化物件寫入成功");
}

序列化結果

反序列化

使用 ObjectInputStream 類的 readObject()方法

//反序列化目標物件讀取寫入序列化的檔案,進行反序列化,變為寫入的那個目標物件
public static void fxlhAccount() throws IOException, ClassNotFoundException {
    //使用物件輸入流,讀入寫入了序列化物件的檔案
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test/account.txt"));
    
    Account account = (Account) ois.readObject();
    ois.close();
    
    //輸出目標物件
    System.out.println(account.toString());

    System.out.println("讀取序列化物件,反序列化成功");

}

反序列化結果

Account{aname='KH96', apwd='12345'}
讀取序列化物件,反序列化成功

當類發生改變

改變後的序列化物件

//賬戶類
public class Account implements Serializable {
	//手動生成序列號
    private static final long serialVersionUID = 2116137267832764072L;
    
    //賬戶名
    private  String aname;
    
    //賬戶密碼
    private String apwd;

    //新增手機
    private  String atel;
    
    //set,get方法省略
    
    @Override
    public String toString() {
        return "Account{" +
                "aname='" + aname + '\'' +
                ", apwd='" + apwd + '\'' +
                ", atel='" + atel + '\'' +
                '}';
    }
}
JAVA 複製 全屏

反序列化結果

Account{aname='KH96', apwd='12345', atel='null'}
讀取序列化物件,反序列化成功