Java IO流(一)

IO(Input Output)流的概述

下面給出IO流的基本概述,這樣可以對(duì)IO流有一個(gè)宏觀上的基本了解。

    1. IO流用來(lái)處理設(shè)備之間的數(shù)據(jù)傳輸。
    1. Java對(duì)數(shù)據(jù)的操作是通過(guò)流(系統(tǒng)資源)的方式。
    1. Java用于操作流的對(duì)象都在java.io包中。
    1. 流按操作數(shù)據(jù)分為兩種:字節(jié)流與字符流。
    1. 流按流向分為:輸入流,輸出流。

雖如此,但我對(duì)IO流有一個(gè)自己的認(rèn)識(shí)。IO流是一門用于處理設(shè)備上的數(shù)據(jù)的技術(shù),此設(shè)備包括內(nèi)存、硬盤、光盤。流即系統(tǒng)資源,Windows系統(tǒng)本身就可以操作設(shè)備,各種語(yǔ)言只是使用了系統(tǒng)平臺(tái)上的這個(gè)資源,并對(duì)外提供了各種語(yǔ)言自己的操作功能,這些功能最終調(diào)用的是系統(tǒng)資源。當(dāng)我們使用完資源后一定要記住釋放。最后,Java中所涉及的功能對(duì)象都存儲(chǔ)到了java.io包中。
設(shè)備上數(shù)據(jù)最常見的存儲(chǔ)表現(xiàn)形式是文件(file),因此接下來(lái)先學(xué)習(xí)一下文件的基本操作。

File

File類的簡(jiǎn)要概述

  1. 用來(lái)將文件或者文件夾封裝成對(duì)象。
  2. 方便對(duì)文件與文件夾的屬性信息進(jìn)行操作。
  3. File對(duì)象可以作為參數(shù)傳遞給流的構(gòu)造函數(shù)。

File類中的常用方法#

#File類的構(gòu)造方法

創(chuàng)建File對(duì)象有三種方法,下面我會(huì)依次詳述。

第①種方法,將a.txt封裝成File對(duì)象,可以將已有和未出現(xiàn)的文件或文件夾封裝成對(duì)象,如下:

File f1 = new File("a.txt");

第②種方法:

File f2 = new File("c:\abc", "b.txt");
1
第③種方法:

File d = new File("c:\\abc");
File f3 = new File(d, "c.txt");

打印時(shí),new File()封裝的是什么,就打印什么,即以下語(yǔ)句

System.out.println("f1:"+f1);
System.out.println("f2:"+f2);
System.out.println("f3:"+f3);

會(huì)依次輸出:

f1:a.txt 
f2:c:\abc\b.txt 
f3:c:\abc\c.txt

separator字段

與系統(tǒng)有關(guān)的默認(rèn)名稱分隔符,為了方便,它被表示為一個(gè)字符串。該字段是跨平臺(tái)的,可這樣創(chuàng)建File對(duì)象:

File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");

獲取文件(夾)相關(guān)信息

獲取文件相關(guān)信息的方法如下:

  1. getName():獲取文件或目錄的名稱。

  2. long length():獲取文件的大小。

  3. getParent():該方法返回的是絕對(duì)路徑中的父目錄,如果獲取的是相對(duì)路徑,返回null。如果相對(duì)路徑中有上一層目錄,那么該目錄就是返回結(jié)果。

  4. getPath():返回的就是File類構(gòu)造函數(shù)里面的字符串,不管什么絕對(duì)或相對(duì)路徑,你給我什么,我就返回什么。

  5. getAbsolutePath():該方法返回的是文件對(duì)象的絕對(duì)路徑,即使封裝的是相對(duì)的,獲取到的也是絕對(duì)的。

    File f = new File("abc\file.txt");

    System.out.println("path:"+f.getPath()); // abc\file.txt
    System.out.println("abspath:"+f.getAbsolutePath()); // E:\MyJava\Java_Basic\day17\abc\file.txt
    System.out.println("parent:"+f.getParent()); // abc

long lastModified():文件最后一次被修改的時(shí)間。

創(chuàng)建文件(夾)

boolean createNewFile():在指定位置創(chuàng)建文件,如果該文件已經(jīng)存在,則不創(chuàng)建,返回false;不存在,就會(huì)創(chuàng)建,創(chuàng)建成功并返回true。和輸出流不一樣,輸出流對(duì)象一建立就創(chuàng)建文件,而且文件已經(jīng)存在,會(huì)覆蓋。示例代碼如下:

File f = new File("file.txt");
System.out.println("create:"+f.createNewFile());

boolean mkdir():創(chuàng)建文件夾,但只能創(chuàng)建一級(jí)目錄。示例代碼如下:

File dir = new File("abc");
System.out.println("mkdir:"+dir.mkdir());

boolean mkdirs():創(chuàng)建多級(jí)文件夾。示例代碼如下:

File dir = new File("abc\\kkk\\a\\a\\dd\\ee\\qq\\aaa");
System.out.println("mkdirs:"+dir.mkdirs());

刪除文件(夾)

boolean delete():刪除失敗返回false,刪除文件夾時(shí),必須保證該文件夾沒有內(nèi)容,如果有內(nèi)容,必須先把內(nèi)容刪除后,才可以刪除當(dāng)前文件夾。示例代碼如下:

File f = new File("file.txt");
System.out.println("delete:"+f.delete());

void deleteOnExit():在程序退出時(shí)刪除指定文件,告訴JVM,一會(huì)退出時(shí)刪除文件(一般是臨時(shí)文件),即使發(fā)生異常。示例代碼如下:

File f = new File("file.txt");
f.deleteOnExit();
code(); // 省略一些代碼,這些代碼可能會(huì)拋出異常
System.out.println("delete:"+f.delete());

File類中的判斷方法

boolean exists():判斷文件(夾)是否存在。示例代碼如下:

File f = new File("file.txt");
System.out.println("exists:"+f.exists());

boolean canExecute():測(cè)試應(yīng)用程序是否可以執(zhí)行此抽象路徑名表示的文件。示例代碼如下:

File f = new File("FileDemo.java");
System.out.println("execute:"+f.canExecute());

isDirectory():判斷是否是一個(gè)目錄。

isFile():判斷是否是一個(gè)標(biāo)準(zhǔn)文件。記住在判斷文件對(duì)象是否是文件或者目錄時(shí),必須要先判斷該文件對(duì)象封裝的內(nèi)容是否存在,通過(guò)exists()判斷。
isAbsolute():判斷是否為絕對(duì)路徑,文件不存在也可以判斷。示例代碼如下:

File f = new File("c:\\file.txt");
System.out.println(f.isAbsolute());

isHidden():判斷是否是一個(gè)隱藏文件。

列出可用的文件系統(tǒng)根

File類中有static File[] listRoots()這樣一個(gè)方法可列出可用的文件系統(tǒng)根,示例代碼如下:

File[] files = File.listRoots();
for (File f : files) {
System.out.println(f);
}

運(yùn)行以上代碼,會(huì)輸出計(jì)算機(jī)可用盤符,諸如下面這樣:

C:\ 
D:\ 
E:\ 
F:\ 
G:\

list()與listFiles()方法

String[] list():列出當(dāng)前目錄下的所有文件和文件夾名稱,包含隱藏文件。注意:調(diào)用list()方法的File對(duì)象必須是封裝了一個(gè)目錄,而且該目錄還必須存在。示例代碼如下:

File f = new File("c:\\");
String[] names = dir.list();
if (names != null) 
for (String name : names) {
System.out.println(name);
}

File[] listFiles():返回一個(gè)抽象路徑名數(shù)組,這些路徑名表示此抽象路徑名表示的目錄中的文件。如果目錄為空,那么數(shù)組也將為空。如果此抽象路徑名不表示一個(gè)目錄,或者發(fā)生I/O錯(cuò)誤,則返回null。示例代碼如下:

File dir = new File("c:\\");

File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file.getName() + "..." + file.length());
}

String[] list(FilenameFilter filter):返回一個(gè)字符串?dāng)?shù)組,這些字符串指定此抽象路徑名表示的目錄中滿足指定過(guò)濾器的文件和目錄。用途:專門找指定目錄下指定后綴名(例如:.java/.jpg/.mp3/.log)的文件。示例代碼如下:

public static void listDemo_2() {
File dir = new File("E:\\MyJava\\Java_Basic\\day16");
String[] arr = dir.list(new FilenameFilter() {

        /**
         * @param dir   被過(guò)濾的目錄。
         * @param name  被遍歷目錄中的文件夾或者文件的名稱。
         */
@Override
public boolean accept(File dir, String name) {
        // System.out.println("dir:"+dir+".....name:"+name);
        // 誰(shuí)會(huì)這樣寫代碼呢?顯然很麻煩
        /*
        if(name.endsWith(".java"))
            return true;
        else
            return false;
        */
        // 簡(jiǎn)寫
        return name.endsWith(".java");
}
});
        System.out.println("len:"+arr.length);
        for (String name : arr) {
         System.out.println(name);
        }
}

遞歸

遞歸就是函數(shù)自身調(diào)用自身,即函數(shù)內(nèi)部又使用到了該函數(shù)功能。雖然知道是這么一個(gè)意思,但一寫代碼遇到遞歸就懵逼了。所以這里我就舉幾個(gè)例子來(lái)詳述一下它。
例1,列出指定目錄下的文件或者文件夾,包含子目錄中的內(nèi)容。也就是列出指定目錄下的所有內(nèi)容。
分析:因?yàn)槟夸浿羞€有目錄,只要使用同一個(gè)列出目錄功能的函數(shù)完成即可。在列出過(guò)程中出現(xiàn)的還是目錄的話,還可以再次調(diào)用本功能。也就是函數(shù)自身調(diào)用自身。這種表現(xiàn)形式或者編程手法,稱為遞歸。
首先定義一個(gè)列出目錄功能的遞歸函數(shù),如下:

public static void getAllFiles(File dir) {
System.out.println("dir:" + dir);

// 1、獲取該目錄的文件對(duì)象數(shù)組。
File[] files = dir.listFiles();

// 2、對(duì)數(shù)組進(jìn)行遍歷。
for (File file : files) {

if (file.isDirectory()) {
getAllFiles(file);
} else {
System.out.println("file:" + file);
}

}
}

然后調(diào)用以上遞歸函數(shù),調(diào)用代碼如下:

public static void main(String[] args) {
File dir = new File("F:\\Java\\java_bxd");
getAllFiles(dir);
}

最后,我們似乎可以知道了遞歸什么時(shí)候使用了?——功能被重復(fù)使用,但是每次該功能使用參與運(yùn)算的數(shù)據(jù)不同時(shí),可以考慮遞歸方式解決。
例2,十進(jìn)制數(shù)轉(zhuǎn)二進(jìn)制數(shù),代碼如下:

public static void toBin(int num) {
if(num > 0) {
toBin(num / 2);
System.out.print(num % 2);
}
}

不理解以上代碼沒關(guān)系,下面我會(huì)圖解,如下:
這里寫圖片描述
例3、求和,代碼如下:

public static int getSum(int n) {
if(n == 1)
return 1;
return n + getSum(n - 1);
}

我圖解如下:
這里寫圖片描述
從以上兩個(gè)例子我們可以得出如下結(jié)論——遞歸要注意:

限定條件。
要注意遞歸的次數(shù),盡量避免內(nèi)存溢出(java.lang.StackOverflowError)。
現(xiàn)在我們來(lái)思考一個(gè)問題——?jiǎng)h除一個(gè)目錄的過(guò)程是如何進(jìn)行的呢?
分析:在Windows中,刪除目錄從里面往外刪除的。既然是從里往外刪除,就需要用到遞歸了。這里,就直接給出程序代碼了,如下:

import java.io.*;

class RemoveDir {
public static void main(String[] args) {
File dir = new File("d:\\java");
removeDir(dir);
}

public static void removeDir(File dir) {
File[] files = dir.listFiles();
for (int x = 0; x < files.length; x++) {
if(!files[x].isHidden() && files[x].isDirectory()) // 避開隱藏文件
removeDir(files[x]);
else
System.out.println(files[x].toString()+":-file-:"+files[x].delete());
}
System.out.println(dir+"::dir::"+dir.delete());
}
}

此處須注意Java刪除時(shí)是不走回車站的,除此之外,還須注意兩點(diǎn),如下:

隱藏目錄——無(wú)法訪問就不能刪除,返回的files為空,會(huì)導(dǎo)致空指針異常。
系統(tǒng)中的有些文件雖然看上去是一個(gè)文件,其實(shí)是一個(gè)目錄,或反之。
遞歸綜合練習(xí)

獲取一個(gè)想要的指定文件的集合,例如獲取F:\Java\java_bxd目錄下(包含子目錄)的所有的.java的文件對(duì)象,并存儲(chǔ)到集合中。
以下是我的分析:

對(duì)指定的目錄進(jìn)行遞歸。
在遞歸的過(guò)程中需要過(guò)濾器,獲取指定過(guò)濾器條件的.java文件對(duì)象。
將滿足指定過(guò)濾器條件的.java文件對(duì)象都添加到集合中。
首先編寫一個(gè)對(duì)指定的目錄進(jìn)行遞歸的函數(shù),可寫成如下,以供參考。

/**
 * @param dir 需要遍歷的目錄。
 * @param list 用于存儲(chǔ)符合條件的File對(duì)象。
 * @param filter 接收指定的過(guò)濾器。
 */
public static void getFileList(File dir, List<File> list, FileFilter filter) {

// 1、通過(guò)listFiles方法,獲取dir當(dāng)前下的所有的文件或文件夾對(duì)象。
File[] files = dir.listFiles();

// 2,遍歷該數(shù)組
for (File file : files) {

// 3,判斷是否是文件夾。如果是,遞歸!如果不是,那就是文件,就需要對(duì)文件進(jìn)行過(guò)濾。
if (file.isDirectory()) {
getFileList(file, list, filter);
} else {
// 4,通過(guò)過(guò)濾器對(duì)文件進(jìn)行過(guò)濾。
if (filter.accept(file)) {
list.add(file);
}
}
}

}

在編寫該函數(shù)時(shí)一定要注意:多級(jí)目錄下都要用到相同的集合和過(guò)濾器,那么不要在遞歸方法中定義,而是不斷地進(jìn)行傳遞。
然后我們?cè)俣x一個(gè)獲取指定過(guò)濾器條件的文件的集合的函數(shù),可寫成如下,以供參考。

public static List<File> fileList(File dir, String suffix) {

// 1,定義集合。
List<File> list = new ArrayList<File>();

// 2,定義過(guò)濾器。
FileFilter filter = new FileFilterBySuffix(suffix);

getFileList(dir, list, filter);

return list;

}

從以上函數(shù)可看出,需要用到文件過(guò)濾器,所以我們還需要定義一個(gè)文件過(guò)濾器,這里我設(shè)計(jì)了一個(gè)——FileFilterBySuffix.java,其內(nèi)容如下:

public class FileFilterBySuffix implements FileFilter {

private String suffix;

public FileFilterBySuffix(String suffix) {
super();
this.suffix = suffix;
}

@Override
public boolean accept(File pathname) {

return pathname.getName().endsWith(suffix);
}

}

最后,我們編寫測(cè)試代碼進(jìn)行測(cè)試。

public static void main(String[] args) {

File dir = new File("F:\\Java\\java_bxd");

List<File> list = fileList(dir, ".java");

for (File file : list) {
System.out.println(file);
}

}

此綜合練習(xí)用到了比較多的知識(shí)點(diǎn),做起來(lái)還蠻不錯(cuò)的,知識(shí)點(diǎn)都串聯(lián)起來(lái)了。
轉(zhuǎn)載地址:https://blog.csdn.net/yerenyuan_pku/article/details/78231697

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,544評(píng)論 19 139
  • 概述 java.io 包幾乎包含了所有操作輸入、輸出需要的類。所有這些流類代表了輸入源和輸出目標(biāo)。java.io ...
    Steven1997閱讀 9,404評(píng)論 1 25
  • 文 | 葉伊嘉 我生活在一個(gè)四線小城里,眨眼的功夫就能從城南到城北,由城東穿到城西。 在一個(gè)地方待久了,自然沒了新...
    葉伊嘉閱讀 1,199評(píng)論 2 3
  • 鐘表滴答滴答地作響,像極了心臟跳動(dòng)的節(jié)奏,每走一圈,生命便流逝一分。
    花貓咩閱讀 489評(píng)論 0 0

友情鏈接更多精彩內(nèi)容