1. 程式人生 > >Java----IO(File OutputStream InputStream Writer Reader)

Java----IO(File OutputStream InputStream Writer Reader)

在Java中IO的核心組成是5個類(File、OutputStream、InputStream、Reader、Writer)和一個介面(Serializable)。
IO需要匯入的包的是java.io。並在是阻塞式IO。

File操作檔案類
java.io包中,FILE類是唯一 一個與檔案本身操作(建立、刪除、取得資訊)有關,與檔案內容無關的程式類。

FILE的基本使用
java.io.File類是一個普通的類,直接產生例項化物件即可。如果要例項化物件用到下面2個構造方法:

  • public File(String pathname) ;
  • public File(String parent, String child),設定父路徑和子路徑。

如果需要建立一個新檔案,方法如下:

public boolean createNewFile() throws IOException

判斷檔案是否存在(可判斷資料夾和檔案)
public boolean exists();

刪除檔案:
public boolean delete();

對上面方法進行練習:

package CODE.JavaIo;

import java.io.File;
import java.io.IOException;

//檔案的建立、判斷是否存在、刪除檔案
public class Create {
    public static
void main(String[] args) { //定義要操作的檔案路徑 File file=new File("C:\\Users\\lenovo\\Desktop\\IO.txt"); System.out.println(file); //C:\Users\lenovo\Desktop\IO.txt //判斷檔案是否存在,不存在則建立,存在則刪除 if(!file.exists()) { System.out.println("檔案不存在"); try
{ file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } else file.delete(); } }

注意:IO異常都是受查異常。
如果第一次執行這個Java程式,將會在桌面上新建一個IO.txt,第二次將會刪除。
可以發現在例項化File物件時,路徑之間用的是"",而在linux下用的"/",為了程式碼可移植性,一般將路徑分隔符用 File.separator。

File file=new File("C:"+File.separator+"Users"+File.separator+            "lenovo"+File.separator+"Desktop"+File.separator+"IO.txt");

目錄操作

取得父路徑

public String getParent()

取得父File物件

public File getParentFile()

建立目錄(無論有多少目錄,都會建立)

public boolean mkdirs()

程式碼如下:

package CODE.JavaIo;

import java.io.File;
import java.io.IOException;

public class Create {
    public static void main(String[] args) {
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+File.separator+"java"+
                File.separator+"IO"+File.separator+"IO.txt");
          //exists可以判斷資料夾是否存在      
           if(!file.getParentFile().exists())
        {
            file.getParentFile().mkdirs(); //有多少目錄,就建立多少父目錄
        }
        else
        {
            System.out.println("父路徑:"+file.getParent()+" 父檔案:"+file.getParentFile());
            if(!file.exists())  //如果IO.txt不存在,即建立該檔案
            {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            else
            {
                System.out.println("檔案已存在");
            }
        }
    }
}

第一次執行,建立父目錄;第二次執行,父目錄存在,建立檔案;第三次執行,檔案已存在。
在這裡插入圖片描述

取得檔案資訊

在File類裡面提供有一系列取得檔案資訊的操作:

  • 判斷File物件是否是檔案: public boolean isFile();
  • 判斷File物件是否是目錄:public boolean isDirectory()
  • 取得檔案大小(位元組):public long length();
  • 取得最後修改日期:public long lastModified
package CODE.JavaIo;

import java.io.File;
import java.sql.Date;

public class File1 {
    public static void main(String[] args) {
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+File.separator+"java"+
                File.separator+"IO"+File.separator+"IO.txt");
        if(file.exists()&&file.isFile())
        {
            System.out.println(file.length());  //取得檔案大小 9位元組
            System.out.println(new Date(file.lastModified())); //2018-12-01
        }
    }
}

例:取得桌面資料夾測試工具裡內容:

package CODE.JavaIo;

import java.io.File;
//檢視資料夾測試工具內容
public class File1 {
    public static void main(String[] args) {
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+File.separator+"測試工具");
        if(file.exists()&&file.isDirectory())//是資料夾且存在
        {
            File files[]=file.listFiles();
            for(File file2:files)
            {
                System.out.println(file2);
            }
        }
    }
}

在這裡插入圖片描述
從圖可以看出,這些都是資料夾,那怎麼檢視資料夾測試工具裡所有檔案呢?

package CODE.JavaIo;

import java.io.File;

//檢視資料夾測試工具所有檔案
public class File1 {
    public static void main(String[] args) {
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+File.separator+"測試工具");
        ListAllFile(file);
    }
    public static void ListAllFile(File file)
    {
        //如果file是檔案則列印
        if(file.isFile())
        {
            System.out.println(file);
            return ;
        }
        //現在是資料夾
        //files裡存的是資料夾裡內容,包括資料夾和檔案
        File files[]=file.listFiles();
        if(files!=null)  //如果這個資料夾什麼都沒有,需要判斷
        {
            for(File file1:files)
            {
                ListAllFile(file1);
            }
        }
    }
}

在這裡插入圖片描述
位元組流與字元流

File類不支援檔案內容處理,如果要處理檔案內容,必須通過流的操作模式來完成。流分為輸入流和輸出流。
在java.io包中,流分為兩種:位元組流和字元流。
1.位元組流:InputStream、OutputStream
2.字元流:Reader、Writer

位元組流和字元流操作的本質區別只有一個:位元組流是原生的操作,而字元流是處理後操作。
一般使用位元組流,無論是網路傳輸還是磁碟資料儲存均以位元組為單位。
只有處理文字時才會使用字元流。

流的操作流程:
無論是位元組流還是字元流,操作流程幾乎一樣,以檔案操作為例:

  • 取得File物件
  • 取得File物件輸入、輸出流
  • 進行資料的讀取或寫入
  • 關閉流(close)

IO屬於資源處理,所有資源樹立(IO、資料庫、網路)使用後都必須關閉。

位元組輸出流(OutputSream)

如果要想通過程式進行內容輸出,可以使用java.io.OutputSream。
OutputStream類的定義結構:

public abstract class OutputStream implements Closeable, Flushable

OutputStream類實現了Closeable,Flushable兩個介面,這兩個介面中的方法為:
1.Closeable介面:public void close() throws IOException;
2.Flushable介面: public void flush() throws IOException;

在OutputStream抽象類中定義其他方法:

  • 將指定的位元組陣列全部輸出:public void write(byte[] b) throws IOException;
  • 將部分位元組陣列輸出:public void write(byte b[], int off, int len) throws IOException;
  • 輸出單個位元組:public abstract void write(int b) throws IOException;

從OutputStream定義可以看見,OutputStream是一個抽象類,如果要例項化物件,需要依賴子類。如果要進行檔案的操作,可以使用FileOutputStream類來處理,FileOutputStream構造方法如下:

  • 接收File類(覆蓋):public FileOutputStream(File file) throws FileNotFoundException
  • 接收File類(追加):public FileOutputStream(File file, boolean append)

覆蓋式寫入:

package CODE.JavaIo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class ByteStream {
    public static void main(String[] args) throws  IOException{
        //取得File物件
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"java"+File.separator+"IO.txt");
       //檔案輸出時,如果檔案不存在,會自動生成,但是必須保證父目錄存在,如果父目錄不存在,必須建立
        if(!file.getParentFile().exists())
        {
            System.out.println("父目錄不存在");
            file.getParentFile().mkdirs();
        }
        //取得file物件的輸出流
        OutputStream out=new FileOutputStream(file);  //覆蓋式寫入
        String msg="hello pick";
        //進行資料的寫入
        out.write(msg.getBytes()); //將字串轉換成位元組陣列
        //關閉流
        out.close();
    }
}

如果父目錄java不存在,將會建立一個父目錄,如果該檔案不存在,該檔案會自動生成,不需要手動建立,但是必須保證父目錄存在。
當使用FileOutputStream進行檔案內容輸出時,只要檔案的父路徑存在,FileOutputStream會自動建立檔案。

上面程式碼使用的是覆蓋式寫入,也就是不論執行多少遍,IO.txt文件裡都是"hello pick”這一句話。
如果需要追加式寫入,用public FileOutputStream(File file, boolean append),程式碼如下:

package CODE.JavaIo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


////追加式寫入
public class ByteStream {
    public static void main(String[] args) throws  IOException{
        //取得File物件
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"java"+File.separator+"IO.txt");
        //檔案輸出時,如果檔案不存在,會自動生成,但是必須保證父目錄存在,如果父目錄不存在,必須建立
        if(!file.getParentFile().exists())
        {
            System.out.println("父目錄不存在");
            file.getParentFile().mkdirs();
        }
        //取得file物件的輸出流
        OutputStream out=new FileOutputStream(file,true);  //追加式寫入
        String msg="hello pick\r\n";
        //進行資料的寫入
        out.write(msg.getBytes()); //將字串轉換成位元組陣列
        //關閉流
        out.close();
    }
}

在這裡插入圖片描述

部分內容寫入:public void write(byte b[], int off, int len) throws IOException;

package CODE.JavaIo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


//部分內容寫入
public class ByteStream {
    public static void main(String[] args) throws  IOException{
        //取得File物件
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"java"+File.separator+"IO.txt");
        //檔案輸出時,如果檔案不存在,會自動生成,但是必須保證父目錄存在,如果父目錄不存在,必須建立
        if(!file.getParentFile().exists())
        {
            System.out.println("父目錄不存在");
            file.getParentFile().mkdirs();
        }
        //取得file物件的輸出流
        OutputStream out=new FileOutputStream(file,true);  //追加式寫入
        String msg="hello pick\r\n";
        //進行資料的寫入
        out.write(msg.getBytes(),6,6); //將字串轉換成位元組陣列
        //關閉流
        out.close();
    }
}

在這裡插入圖片描述

AutoCloseable自動關閉支援
從JDk1.7開始追加了一個AutoCloseable介面,這個介面的主要目的是自動進行關閉處理,但是這種處理一般不好用,因為使用它必須結合try…catch
程式碼如下:

package CODE.JavaIo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

//AutoCloseable自動關閉
class Message implements AutoCloseable
{
    @Override
   public void close()
   {
       System.out.println("自動關閉");
   }
}
public class ByteStream {
    public static void main(String[] args) {
        try(Message message=new Message())  //必須在try中定義物件
        {
            //取得File物件
            File file=new File("C:"+File.separator+"Users"+File.separator+
                    "lenovo"+File.separator+"Desktop"+
                    File.separator+"java"+File.separator+"IO.txt");
            //檔案輸出時,如果檔案不存在,會自動生成,但是必須保證父目錄存在,如果父目錄不存在,必須建立
            if(!file.getParentFile().exists())
            {
                System.out.println("父目錄不存在");
                file.getParentFile().mkdirs();
            }
            //取得file物件的輸出流
            OutputStream out=new FileOutputStream(file,true);  //追加式寫入
            String msg="hello pick\r\n";
            //進行資料的寫入
            out.write(msg.getBytes(),6,6); //將字串轉換成位元組陣列
            out.close();//關閉流
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

在這裡插入圖片描述

位元組輸入流(InputStream)

InputStream類的定義如下:

public abstract class InputStream implements Closeable

InputStream類只實現了Closeable介面。
在InputStream類中提供有如下方法:

  • 讀取資料到位元組陣列b中:public int read(byte[ ] b ) throws IOException;
    對於這個方法返回值有3種情況:
  1. 返回值>0 返回陣列b長度 :當讀取資料大小 > 位元組陣列大小,返回陣列大小;
  2. 返回值大於0但是小於b長度:當讀取資料大小 < 位元組陣列大小,返回真正讀取大小;
  3. 返回-1 :資料讀取完畢。
  • 讀取單個位元組:public int read() throws IOException;

同OutputStream的使用一樣,InputStream是一個抽象類,如果要對其例項化,同樣也需要使用子類。如果要對
檔案進行處理,則使用FileInputStream類。

//從檔案讀取資料
package CODE.JavaIo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ByteInStream {
    public static void main(String[] args) throws IOException {
        //取得File物件
        File file=new File("C:"+File.separator+"Users"+File.separator+
                "lenovo"+File.separator+"Desktop"+
                File.separator+"java"+File.separator+"IO.txt");
        //從檔案讀資料,必須保證檔案存在而且是檔案即不能是資料夾
        if(file.exists()&&file.isFile()) {
            //取得file物件的輸入流
            InputStream in = new FileInputStream(file);
            byte[] b = new byte[1024]; //每次可以讀取的最大數量
            int len=in.read(b);  //將讀取的資料放在位元組陣列b中,返回實際讀取資料大小
            System.out.println(new String(b,0,len)); //將位元組陣列b轉換成String,並且長度是實際讀取資料大小
            in.close(); //關閉流
        }
    }
}

在這裡插入圖片描述

字元輸出流(Writer)

Writer類的定義如下:

public abstract class Writer implements Appendable, Closeable, Flushable

Writer與OutputStream相比多了一個Appendable介面。
Writer類中其他方法:

  1. 將指定的字元陣列全部輸出 : public void write(char cbuf[]) throws IOException;
  2. 將部分字元陣列輸出:abstract public void write(char cbuf[], int off, int len) throws IOException;
  3. 輸出單個字元:public void write(int c) throws IOException ;
    這3個方法和OutputStream.write一樣。
  4. 輸出字串:public void write(String str) throws IOException;

如果要對將檔案