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種情況:
- 返回值>0 返回陣列b長度 :當讀取資料大小 > 位元組陣列大小,返回陣列大小;
- 返回值大於0但是小於b長度:當讀取資料大小 < 位元組陣列大小,返回真正讀取大小;
- 返回-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類中其他方法:
- 將指定的字元陣列全部輸出 : public void write(char cbuf[]) throws IOException;
- 將部分字元陣列輸出:abstract public void write(char cbuf[], int off, int len) throws IOException;
- 輸出單個字元:public void write(int c) throws IOException ;
這3個方法和OutputStream.write一樣。 - 輸出字串:public void write(String str) throws IOException;
如果要對將檔案