天天看點

黑馬程式員 九、IO 操作(1)

<a target="_blank" href="http://www.javahelp.com.cn/">java幫幫-it資源分享網</a>

 九、黑馬程式員—io 操作(1)

第九篇 io 檔案操作(1)

1、io 的概述和 file 方法

io 流用來處理裝置之間的資料傳輸

java 對資料的操作是通過流的方式

java 用于操作流的對象都在 io 包中

file 類在整個 io 包中與檔案本身有關的操作類,所有的與檔案本身有關指的是建立、删除

檔案等操作。在 java.io 包中的 file 類本身是一個跨平台的檔案操作類,是以在操作中要更

多的考慮到各個作業系統的差別。

file 即指檔案也指檔案夾。

file 類構造方法和字段摘要

static string pathseparator 路徑分隔符,window 下是";"。

static char pathseparatorchar 路徑分隔符,window 下是";"。

static string separator 路徑分隔符,window 下是"\"。

static char separatorchar 路徑分隔符,window 下是"\"。

file(file parent, string child) 根據 parent 抽象路徑名和 child 路徑名字元串建立一個新

file 執行個體。

file(string pathname) 通過将給定路徑名字元串轉換為抽象路徑名來建立一個新 file 實

例。

file(string parent, string child) 根據 parent 路徑名字元串和 child 路徑名字元串建立一個

新 file 執行個體。

file(uri uri) 通過将給定的 file: /uri 轉換為一個抽象路徑名來建立一個新的 file 執行個體。

file 的相關方法

string getname():傳回檔案名或路徑名(若是路徑,傳回最後一級子路徑名)

string getpath():傳回對象對應的路徑名

file getabsolutefile():傳回絕對路徑

string getabsolutepath():傳回對象對應的絕對路徑

string getparent():傳回檔案目錄的上一級目錄名

boolean renameto(file newname):重命名此 file 對象對應的檔案或目錄,若重命名成功傳回

true;

boolean exists():判斷對象對應的檔案或目錄是否存在;

boolean canwrite():判斷對象對應檔案或目錄是否可寫;

boolean canread():判斷對象對應檔案或目錄是否可讀;

boolean isfile():判斷對象是檔案,不是目錄;

boolean isdirectory() 判斷對象的檔案是否是一個目錄;

boolean isabsolute() 判斷對象對應檔案或目錄是否為絕對路徑名;

boolean createnewfile() 當且僅當不存在,該方法建立一個該 file 對象所指定的新檔案,創

建成功傳回 true。

boolean delete():删除 file 對象所對應的檔案或路徑;

boolean mkdir() 建立 file 對象所對應的目錄,調用該方法的 file 對象必須對應路徑,而不

是檔案。

string[] list():列出 file 對象的所有子檔案名和路徑名。

file[] listfiles():列出 file 對象的所有子檔案和路徑。

static file[] listroots():列出系統所有的根路徑;

我的總結:io 這一章節最應該記住的關鍵字:讀進來,寫進去!

eg:

package july7file;

import java.io.file;

import java.io.ioexception;

public class demo1 {

public static void main(string[] args) throws ioexception {

file f = new file("e:/你好.txt");

system.out.println(f.createnewfile());

system.out.println(f.getname());

system.out.println(f.getparent());

system.out.println(f.length());

}

輸出:

false

你好.txt

e:\

6905

2、遞歸(recursion)

現在要求輸出一個給定目錄中的全部檔案的路徑。

本程式肯定隻能依靠遞歸的操作完成,因為在一個給定的路徑下有可能還是檔案夾,那麼如

果是檔案夾的話則肯定要繼續列出,重複判斷。

遞歸:程式調用自身的程式設計技巧

遞歸就是在方法裡調用自身;

在使用遞歸時,必須有一個明确的遞歸結束條件,稱為遞歸出口。

練習:列出檔案夾下所有檔案(包含子檔案夾内)

//利用遞歸周遊輸出

public class demo2 {

public static void main(string[] args) {

file f = new file("d:/v5");

mylist(f);

public static void mylist(file f) {

system.out.println(f);// 先輸出一下,因為不能确定接受來的檔案是否是

檔案夾!

if (f.isdirectory()) {

file[] file = f.listfiles();

for (file file2 : file) {

mylist(file2);

練習:删除一個目錄(注意:要删除目錄必須删除目錄下的檔案和子目錄)

public class demo11 {

deleter(f);

system.out.println("删除成功 !");

public static void deleter(file f){//程式簡陋,就沒有判斷空引用!

if(f.isfile()){

f.delete();

}else if(f.isdirectory()){

file []file = f.listfiles();

deleter(file2);//調用自身,遞歸!

file2.delete();//删除子檔案夾(内部沒有檔案的時候可以删除),

如果這裡寫上f.delete();那麼v5這個檔案夾也沒有了

3、檔案過濾器 java.io.filenamefilter

file 類裡有方法: string[] list(filenamefilter filter) 傳回一個字元串數組,這些字元串指

定此抽象路徑名表示的目錄中滿足指定過濾器的檔案和目錄。

filenamefilter(檔案過濾器)該接口裡包含 accept(file dir,string name)方法,該方法依次對指定

file 的所有子目錄,子檔案夾進行疊代。

dir - 被找到的檔案所在的目錄。

name - 檔案的名稱。

當且僅當該名稱應該包含在檔案清單中時傳回 true;否則傳回 false

//構造過濾器,隻輸出需要的檔案!

import java.io.filenamefilter;

class myfilter implements filenamefilter {

private string ext;

public myfilter(string ext) {

super();

this.ext = ext;

@override

public boolean accept(file dir, string name) {

return name.endswith(ext);// 真正起作用的還是這裡的ext

public class demo3 {

file f = new file("d:/v5/牛/水牛");

file[] file = f.listfiles(new myfilter(".txt"));

system.out.println(file2);

4、流

資料流是一串連續不斷的資料的集合,就像水管裡的水流,在水管的一端一點一點地供水,而

在水管的另一端看到的是一股連續不斷的水流.

資料寫入程式可以使一段一段地向資料流管道中寫入資料,這些資料段會按先後順序形成一

個長的資料流.

在程式中所有的資料都是以流的方法進行傳輸和儲存的。

java 的 io 是實作輸入和輸出的基礎。

java 把所有傳統的流類型(類或抽象類)都放在 java.io 包中,用以實作輸入輸出功能。

輸入和輸出是一個相對的概念,我們一般站在程式的角度來分析和處理問題的。

程式需要資料 --&gt; 讀進來 --&gt; 輸入

程式儲存資料 --&gt; 寫出去 --&gt; 輸出

水流

我的總結:最重要的:從程式的角度出發,讀進來,寫出去!(在儲存資料的時候是把資料

寫出去,這時候資料就儲存在了檔案裡面,在需要調用資料的時候就把資料讀進來,這樣

資料就又到了程式中!)

流的分類(面試常考)

從不同角度分類:

按流動方向的不同可以分為輸入流和輸出流;

按處理資料的機關不同分為位元組流和字元流;

按功能的不同可分為節點流和處理流;

節點流:直接操作目标裝置,例如:磁盤或一塊記憶體區域。

處理流:通過操作節點流,進而間接完成輸入或輸出功能的流。處理流是的存在是建立

在一個已經存在的輸入流或輸出流的基礎之上的。

所有流都繼承于以下四種抽象流類型的某一種:(抽象流)

黑馬程式員 九、IO 操作(1)

5、操作流的步驟(重點)

file 類本身是與檔案操作有關,但是如果要想操作内容則必須使用位元組流或字元流完成,但

是不管是使用何種的輸入輸出流,其基本的操作原理是一樣的(以檔案流為準):

一、使用 file 類找到一個檔案對象,得到 io 操作的源或目标

二、通過位元組流或字元流的子類建立對象,(得到 io 操作的通道)

三、進行讀或寫的操作,(io 操作)

四、關閉輸入/輸出,(打完收工,注意節約資源,關掉)

由于流的操作屬于資源操作,是以在操作的最後一定要關閉以釋放資源。

其實上面的流操作步驟可以聯系生活中的例子:比如想把水井裡的水弄到家裡的大水缸去,怎

麼搞呢?

1.找到水井在哪裡;2.找根管子一頭接在水井裡,一頭接在家裡的大水缸裡;3.打開管子上的龍

頭,放水;4.水放滿了,關掉水龍頭.

計算機通路外部裝置,要比直接通路記憶體慢得多,若我們每一次 write 方法調用都是直接寫到

外部裝置(比如磁盤上的一個檔案),cpu 就要花費更多的時間去等待外部裝置;我們可以開辟

一個記憶體緩沖區,程式每一次的 write 方法都是寫到這個記憶體緩沖區中,隻有這個緩沖區裝滿

了之後,系統才将這個緩沖區的内容一次集中寫到外部裝置.

我的總結:

好處:1.有效提高了 cpu 的使用率;2.write 方法并沒有馬上真正寫入到外部裝置,我們還

有機會復原部分寫入的資料;

//建構輸入流,讀進來,輸出到控制台!

import java.io.fileinputstream;

import java.io.inputstream;

public class demo4 {

public static void main(string[] args) throws exception {

//第一步:建立源!

string filename = "6.4";//這個檔案是在工作空間裡面,沒有字尾名!

//第二步:建立管道!

inputstream ips = new fileinputstream(filename);

//第三步:操作!

byte []buff = new byte[1024];

int len;//定義緩沖區

while((len = ips.read(buff)) != -1){

system.out.println(new string(buff,0,buff.length));//輸出

到控制台!此時的輸出流就是列印流!

system.out.println("==========================================

");//列印下,看哪裡在1024。1024的地方被隔開了

//第四步:關閉資源(字元流必須關閉資源,因為它中間有緩沖區!對于位元組流可

以不用關閉,但是還是建議寫上,習慣!)

ips.close();

輸出:就将檔案 6.4 中的資料列印到了控制台!

6、位元組流和字元流

二者僅僅是操作機關不一樣。

inputstream 和 reader 是所有輸入流的基類,他們都是抽象類,本身不能建立執行個體,但是他

們是所有輸入流的模闆。

一般來說處理字元或字元串時使用字元流,處理位元組或二進制對象時應使用位元組流;

備注:字元流必須關閉資源,因為它中間有緩沖區!而位元組流不需要!但是一般都會(最後)

關閉資源!

位元組流

位元組流主要是操作 byte(位元組)的類型資料:

位元組輸出流:outputstream

位元組輸入流:inputstream

字元流

java 中的字元是 unicode 編碼,是雙位元組的,1 個字元 等于 2 個位元組;

使用位元組來處理字元文本就不太友善了,此時可以考慮使用字元流;

字元流主要是操作 char 的類型資料:

字元輸出流:writer

字元輸入流:reader

位元組流和字元流的差別

位元組流和字元流在使用上的代碼結構都是非常類似的,但是其内部本身也是有差別的,因為

在進行字元流操作的時候會使用到緩沖區(記憶體中),而位元組流操作的時候是不會使用

到緩沖區的。

在輸出的時候,outputstream 類即使最後沒有關閉内容也可以輸出。但是如果是 writer

的話,則如果不關閉,最後一條内容是無法輸出的,因為所有的内容都是儲存在了緩沖區

之中,每當調用了 close()方法就意味着清空緩沖區了。那麼可以證明字元流确實使用了

緩沖區:

位元組流:程式 → 檔案

字元流:程式 → 緩沖區(記憶體中) → 檔案

如果現在字元流即使不關閉也可以完成輸出的話,則必須強制性清空緩沖區:

方法:public void flush() throws ioexception

兩者相比,肯定使用位元組流更加的友善,而且在程式中像圖檔、mp3 等都是采用位元組的方式

的儲存,那麼肯定位元組流會比字元流使用的更廣泛。

但是需要說明的是,但是如果要是想操作中文的話,字元流肯定是最好使的。(位元組流的話

可能會出現亂碼(一個漢字分成了兩份)!)

//字元流讀出來,這時候就不會出現亂碼的情況,在進行文字操作的時候最好使用字元流!

import java.io.filenotfoundexception;

import java.io.filereader;

import java.io.reader;

public class demo6 {

file src = new file("6.4");

read(src);

public static void read(file src){

reader r = null;

try {

r = new filereader(src);

} catch (filenotfoundexception e) {

e.printstacktrace();

char []c = new char[1024];

int len;

while((len = r.read(c)) != -1){

system.out.println(new string(c,0,c.length));//列印到

控制台

} catch (ioexception e) {

r.close();

7、檔案拷貝

需求:源和目标!

那麼我們需要源檔案和目标檔案!

建構管道的時候就需要兩個:輸出流和輸入流管道!

//java7開始的自動關閉資源

import java.io.fileoutputstream;

import java.io.outputstream;

public class demo8 {

file src = new file("e:/自薦信.doc");

file tar = new file("e:/自薦信1.doc");

copy(src, tar);

system.out.println("well done !");

public static void copy(file src, file tar) throws ioexception {

try (inputstream is = new fileinputstream(src);

outputstream os = new fileoutputstream(tar);) {

byte[] b = new byte[1024];

while ((len = is.read(b)) != -1) {

os.write(b);

題目:複制圖檔!

/**

* 檔案的複制!對于本題而言,因為是圖檔,是以要想讀出來,必須使用位元組流!

* 字元流必須關閉資源,而位元組流可以不關閉資源!但是還是建議全部的關閉,因為也不

會出錯,這是關閉資源的習慣!

* 另外:最常用的是位元組流,因為位元組流在記憶體中不需要緩沖區,圖檔,mp3 等都是位元組

流!但是對于文字的話還是字元流比較好;

* 因為字元流可以避免在位元組流操作文字時出現的亂碼現象(正好讀取到了自定義緩沖區

的分割處);

*/

public class demo7 {

file src = new file("d:/java.jpg");

file tar = new file("d:/meinv.jpg");

copy(src,tar);

system.out.println("複制完成!");

public static void copy(file src,file tar) throws exception{

/* reader r = new filereader(src);

writer w = new filewriter(tar);*/

/*if(!src.exists()){

throw new exception("對不起,源檔案不存在!");

}*/

inputstream in = new fileinputstream(src);

outputstream os = new fileoutputstream(tar);

byte []c = new byte[1024];

while((len = in.read(c)) != -1){

os.write(c);

/* w.close();

r.close();*/

我的總結:對于圖檔的複制,可以使用字元流,但是這樣的話檔案可以複制成功但是

無法讀取!

8、位元組→字元轉換流

outputstreamwriter:把位元組輸出流對象轉成字元輸出流對象

inputstreamreader:把位元組輸入流對象轉成字元輸入流對象

filewriter 和 filereader 分别是 outputstreamwriter 和 inputstreamreader 的直接子類,而不

是 writer 和 reader 的直接子類,差別于 fileinputstream 和 inputstream。

我的總結:無論使用位元組流還是字元流實際上在記憶體中最終都是通過位元組的形式來操

作流的。

是以并沒有字元流轉換位元組流。

//建構一個位元組輸出流對象

outputstream out = new fileoutputstream("");

//把位元組輸出流轉成字元輸出流

writer w = new outputstreamwriter(out);

//然後的操作和使用字元輸出流的操作一樣

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

//建構一個位元組輸入流對象

inputstream is = new fileinputstream("");

//把位元組輸入流轉成字元輸入流

reader r = new inputstreamreader(is);

//然後的操作和使用字元輸入流的操作一樣

9、自動關閉資源的 try 語句

java 7 簡化資源清理(try-with-resources)自動關閉資源的 try 語句

自動關閉資源格式:

try( )//此處多了圓括号,()圓括号内寫打開資源的代碼,在這裡建立的對象必須實作

autocloseable 接口

{

io 操作

catch(){

處理異常的代碼

eg:package july7file;

outputstream os = new fileoutputstream(tar);) //圓括号

内寫打開資源的操作