IO(Input Output)流的概述
下面給出IO流的基本概述,這樣可以對(duì)IO流有一個(gè)宏觀上的基本了解。
- IO流用來(lái)處理設(shè)備之間的數(shù)據(jù)傳輸。
- Java對(duì)數(shù)據(jù)的操作是通過(guò)流(系統(tǒng)資源)的方式。
- Java用于操作流的對(duì)象都在java.io包中。
- 流按操作數(shù)據(jù)分為兩種:字節(jié)流與字符流。
- 流按流向分為:輸入流,輸出流。
雖如此,但我對(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)要概述
- 用來(lái)將文件或者文件夾封裝成對(duì)象。
- 方便對(duì)文件與文件夾的屬性信息進(jìn)行操作。
- 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)信息的方法如下:
getName():獲取文件或目錄的名稱。
long length():獲取文件的大小。
getParent():該方法返回的是絕對(duì)路徑中的父目錄,如果獲取的是相對(duì)路徑,返回null。如果相對(duì)路徑中有上一層目錄,那么該目錄就是返回結(jié)果。
getPath():返回的就是File類構(gòu)造函數(shù)里面的字符串,不管什么絕對(duì)或相對(duì)路徑,你給我什么,我就返回什么。
-
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