33.JAVA編程思想——JAVA IO File類
33.JAVA編程思想——JAVA IO File類
RandomAccessFile用於包括了已知長度記錄的文件。以便我們能用 seek()從一條記錄移至還有一條;然後讀取或改動那些記錄。
各記錄的長度並不一定同樣;僅僅要知道它們有多大以及置於文件何處就可以。
首先。我們有點難以相信RandomAccessFile 不屬於InputStream 或者OutputStream 分層結構的一部分。除了恰巧實現了DataInput 以及DataOutput(這兩者亦由 DataInputStream和DataOutputStream實現)接口之外,它們與那些分層結構並無什麽關系。它甚至沒實用到現有InputStream 或OutputStream 類的功能——採用的是一個全然不相幹的類。
該類屬於全新的設計,含有自己的全部(大多數為固有)方法。
之所以要這樣做,是由於RandomAccessFile 擁有與其它 IO類型全然不同的行為。由於我們可在一個文件中向前或向後移動。無論在哪種情況下。它都是獨立運作的,作為Object 的一個“直接繼承人”使用。
從根本上說,RandomAccessFile 相似DataInputStream和 DataOutputStream的聯合使用。
當中,getFilePointer()用於了解當前在文件的什麽地方。seek()用於移至文件內的一個新地點。而 length()用於推斷文件的最大長度。
此外,構建器要求使用還有一個自變量(與C 的fopen()全然一樣)。指出自己僅僅是隨機讀("r")。還是讀寫兼施("rw")。這裏沒有提供對“僅僅寫文件”的支持。也就是說,假如是從DataInputStream繼承的,那麽 RandomAccessFile也有可能能非常好地工作。
還有更難對付的。非常easy想象我們有時要在其它類型的數據流中搜索,比方一個ByteArrayInputStream。但搜索方法僅僅有RandomAccessFile 才會提供。而後者僅僅能針對文件才幹操作,不能針對數據流操作。此時。BufferedInputStream 確實同意我們標記一個位置(使用mark(),它的值容納於單個內部變量中)。並用reset()重設那個位置。但這些做法都存在限制。並非特別實用。
1.??File類
File 類有一個欺騙性的名字——一般會覺得它對付的是一個文件。但實情並非如此。它既代表一個特定文件的名字,也代表文件夾內一系列文件的名字。若代表一個文件集。便可用list()方法查詢這個集,返回的是一個字串數組。之所以要返回一個數組,而非某個靈活的集合類。是由於元素的數量是固定的。並且若想得到
一個不同的文件夾列表。僅僅需創建一個不同的File 對象就可以。其實,“FilePath”(文件路徑)似乎是一個更好的名字。
1.1?????????????文件夾列表器
如果想觀看一個文件夾列表。可用兩種方式列出File 對象。若在不含自變量(參數)的情況下調用list(),會獲得 File 對象包括的一個完整列表。
然而。若想對這個列表進行某些限制,就須要使用一個“文件夾過濾器”,該類的作用是指出應怎樣選擇File 對象來完畢顯示。
樣例的代碼:
l? 代碼例如以下
import java.io.*;
public classDirList {
??? public static void main(String[] args) {
??????? try {
??????????? Filepath= newFile(".");
??????????? String[]list;
??????????? if (args.length == 0)
??????????????? list = path.list();
??????????? else
??????????????? list = path.list(new DirFilter(args[0]));
??????????? for (int i = 0; i < list.length; i++)
??????????????? System.out.println(list[i]);
??????? }catch(Exception e) {
??????????? e.printStackTrace();
??????? }
??? }
}
class DirFilter implements FilenameFilter {
??? Stringafn;
??? DirFilter(Stringafn){
??????? this.afn = afn;
??? }
??? public boolean accept(File dir, String name) {
??????? // Strip path information:
??????? Stringf = new File(name).getName();
??????? return f.indexOf(afn) != -1;
??? }
} /// :~
l? 運行
.classpath
.project
.settings
bin
src
DirFilter 類“實現”了interface FilenameFilter。
以下讓我們看看FilenameFilter接口有多麽簡單:
public interface FilenameFilter {
boolean accept(文件文件夾, 字串名);
}
它指出這樣的類型的全部對象都提供了一個名為 accept()的方法。之所以要創建這樣的一個類,背後的全部原因就是把accept()方法提供給 list()方法。使list()可以“回調”accept(),從而推斷應將哪些文件名稱包括到列表中。因此,通常將這樣的技術稱為“回調”,有時也稱為“算子”(也就是說,DirFilter 是一個算子,由於它唯一的作用就是容納一個方法)。
由於 list()採用一個 FilenameFilter 對象作為自己的自變量使用。所以我們能傳遞實現了FilenameFilter 的不論什麽類的一個對象,用它決定(甚至在運行期)list()方法的行為方式。
回調的目的是在代碼的行為上提供更大的靈活性。
通過DirFilter。我們看出雖然一個“接口”僅僅包括了一系列方法。但並不局限於僅僅能寫那些方法(可是。至少必須提供一個接口內全部方法的定義。
在這樣的情況下,DirFilter 構建器也會創建)。accept()方法必須接納一個 File 對象,用它指示用於尋找一個特定文件的文件夾;並接納一個String,當中包括了要尋找之文件的名字。可決定使用或忽略這兩個參數之中的一個。但有時至少要使用文件名稱。
記住list()方法準備為文件夾對象中的每一個文件名稱調用accept(),核實哪個應包括在內——詳細由 accept()返回的“布爾”結果決定。
為確定我們操作的僅僅是文件名稱,當中沒有包括路徑信息,必須採用String對象,並在它的外部創建一個File 對象。
然後調用 getName()。它的作用是去除全部路徑信息(採用與平臺無關的方式)。隨後,accept()用String 類的indexOf()方法檢查文件名稱內部是否存在搜索字串"afn"。
若在字串內找到 afn,那麽返回值就是afn 的起點索引;但假如沒有找到,返回值就是-1。
註意這僅僅是一個簡單的字串搜索樣例。未使用常見的表達式“通配符”方案,比方"fo?.b?r*";這樣的方案更難實現。
list()方法返回的是一個數組。
可查詢這個數組的長度,然後在當中遍歷,選定數組元素。
與 C 和C++的相似行為相比,這樣的於方法內外方便遊歷數組的行為無疑是一個顯著的進步。
1.2?????????????匿名內部類
l? 代碼例如以下
用一個匿名內部類來重寫顯得非常理想。首先創建了一個filter()方法,它返回指向FilenameFilter 的一個句柄:
import java.io.*;
public classDirList2 {
??? public static FilenameFilter filter(final String afn) {
??????? // Creation of anonymous inner class:
??????? return new FilenameFilter() {
??????????? Stringfn = afn;
??????????? public boolean accept(File dir, String n) {
??????????????? // Strip path information:
??????????????? Stringf = new File(n).getName();
??????????????? return f.indexOf(fn) != -1;
??????????? }
??????? };// End of anonymous inner class
??? }
??? public static void main(String[] args) {
??????? try {
??????????? Filepath= newFile(".");
??????????? String[]list;
??????????? if (args.length == 0)
??????????????? list = path.list();
??????????? else
??????????????? list = path.list(filter(args[0]));
??????????? for (int i = 0; i < list.length; i++)
??????????????? System.out.println(list[i]);
??????? }catch(Exception e) {
??????????? e.printStackTrace();
??????? }
??? }
} /// :~
?
l? 運行
.classpath
.project
.settings
bin
src
註意filter()的自變量必須是final。
這一點是匿名內部類要求的,使其能使用來自本身作用域以外的一個對象。
之所以覺得這樣做更好,是由於FilenameFilter 類如今同DirList2 緊密地結合在一起。然而,我們可採取進一步的操作,將匿名內部類定義成list()的一個參數,使其顯得更加精簡。
l? 代碼2
import java.io.*;
?
public classDirList3 {
??? public static void main(final String[] args) {
??????? try {
??????????? Filepath= newFile(".");
??????????? String[]list;
??????????? if (args.length == 0)
??????????????? list = path.list();
??????????? else
??????????????? list = path.list(new FilenameFilter() {
??????????????????? public boolean accept(File dir, String n) {
??????????????????????? Stringf = new File(n).getName();
??????????????????????? return f.indexOf(args[0]) != -1;
??????????????????? }
??????????????? });
??????????? for (int i = 0; i < list.length; i++)
??????????????? System.out.println(list[i]);
??????? }catch(Exception e) {
??????????? e.printStackTrace();
??????? }
??? }
} /// :~
l? 運行
.classpath
.project
.settings
bin
src
main()如今的自變量是 final。由於匿名內部類直接使用args[0]。
這展示了怎樣利用匿名內部類高速創建精簡的類。以便解決一些復雜的問題。由於Java 中的全部東西都與類有關,所以它無疑是一種相當實用的編碼技術。它的一個優點是將特定的問題隔離在一個地方統一解決。但在還有一方面,這樣生成的代碼不是十分easy閱讀,所以使用時必須謹慎。
1.3?????????????順序文件夾列表
常常都須要文件名稱以排好序的方式提供。由於 Java 1.0 和Java 1.1 都沒有提供對排序的支持(從 Java 1.2開始提供),用創建的 SortVector將這一能力直接添加自己的程序。
l? 代碼
import java.io.*;
public classSortedDirList {
??? private File path;
??? private String[] list;
??? public SortedDirList(final String afn) {
??????? path = new File(".");
??????? if (afn == null)
??????????? list = path.list();
??????? else
??????????? list = path.list(new FilenameFilter() {
??????????????? public boolean accept(File dir, String n) {
??????????????????? Stringf = new File(n).getName();
??????????????????? return f.indexOf(afn) != -1;
??????????????? }
??????????? });
??????? sort();
??? }
??? void print() {
??????? for (int i = 0; i < list.length; i++)
??????????? System.out.println(list[i]);
??? }
??? private void sort() {
??????? StrSortVectorsv = new StrSortVector();
??????? for (int i = 0; i < list.length; i++)
??????????? sv.addElement(list[i]);
??????? // The first time an element is pulled from
??????? // the StrSortVector the list is sorted:
??????? for (int i = 0; i < list.length; i++)
??????????? list[i] = sv.elementAt(i);
??? }
??? // Test it:
??? public static void main(String[] args) {
??????? SortedDirListsd;
??????? if (args.length == 0)
??????????? sd = new SortedDirList(null);
??????? else
??????????? sd = new SortedDirList(args[0]);
??????? sd.print();
??? }
} /// :~
l? 運行
.classpath
.project
.settings
bin
src
這裏進行了另外少許改進。不再是將path(路徑)和 list(列表)創建為main()的本地變量,它們變成了類的成員。使它們的值能在對象“生存”期間方便地訪問。其實。main()如今僅僅是對類進行測試的一種方式。
一旦列表創建完畢,類的構建器就會自己主動開始對列表進行排序。
這樣的排序不要求區分大寫和小寫,所以終於不會得到一組全部單詞都以大寫字母開頭的列表。跟著是全部以小寫字母開頭的列表。
然而,我們註意到在以同樣字母開頭的一組文件名稱中。大寫字母是排在前面的——這對標準的排序來說仍是一種不合格的行為。
Java 1.2 已成功攻克了這個問題。
1.4?????????????檢查與創建文件夾
File 類並不僅僅是對現有文件夾路徑、文件或者文件組的一個表示。亦可用一個 File 對象新建一個文件夾,甚至創建一個完整的文件夾路徑——假如它尚不存在的話。
亦可用它了解文件的屬性(長度、上一次改動日期、讀/寫屬性等),檢查一個File 對象究竟代表一個文件還是一個文件夾。以及刪除一個文件等等。下列程序完整展示了怎樣運用File 類剩下的這些方法:
l? 代碼
import java.io.*;
?
public classMakeDirectories {
??? private final static String usage = "Usage:MakeDirectories path1 ...\n" + "Creates each path\n"
??????????? +"Usage:MakeDirectories -d path1...\n" + "Deleteseach path\n" + "Usage:MakeDirectories -r path1 path2\n"
??????????? +"Renames from path1 to path2\n";
??? private static void usage() {
??????? System.err.println(usage);
??????? System.exit(1);
??? }
??? private static void fileData(File f) {
??????? System.out.println("Absolute path: "+ f.getAbsolutePath()+ "\n Can read: " + f.canRead() + "\n Can write: "
??????????????? +f.canWrite() + "\n getName: "+ f.getName() + "\n getParent: "+ f.getParent() + "\n getPath: "
??????????????? +f.getPath() + "\n length: "+ f.length() + "\n lastModified: "+ f.lastModified());
??????? if (f.isFile())
??????????? System.out.println("it‘s a file");
??????? else if (f.isDirectory())
??????????? System.out.println("it‘s a directory");
??? }
?
??? public static void main(String[] args) {
??????? if (args.length < 1)
??????????? usage();
??????? if (args[0].equals("-r")) {
??????????? if (args.length != 3)
??????????????? usage();
??????????? Fileold= newFile(args[1]),rname= newFile(args[2]);
??????????? old.renameTo(rname);
??????????? fileData(old);
??????????? fileData(rname);
??????????? return; // Exit main
??????? }
??????? int count = 0;
??????? boolean del = false;
??????? if (args[0].equals("-d")) {
??????????? count++;
??????????? del = true;
??????? }
??????? for (; count < args.length; count++) {
??????????? Filef = new File(args[count]);
??????????? if (f.exists()) {
??????????????? System.out.println(f + " exists");
??????????????? if (del) {
??????????????????? System.out.println("deleting..."+ f);
??????????????????? f.delete();
??????????????? }
??????????? }else{ // Doesn‘t exist
??????????????? if (!del) {
??????????????????? f.mkdirs();
??????????????????? System.out.println("created "+ f);
??????????????? }
??????????? }
??????????? fileData(f);
??????? }
??? }
} /// :~
l? 運行
Usage:MakeDirectories path1 ...
Creates each path
Usage:MakeDirectories -d path1 ...
Deletes each path
Usage:MakeDirectories -r path1 path2
Renames from path1 to path2
加上運行參數:-rtest1.txt test2.txt
然後在文件夾中添加test1.txt文件,運行後
Absolute path: F:\java_test\test1.txt
?Can read: false
?Can write: false
?getName: test1.txt
?getParent: null
?getPath: test1.txt
?length: 0
?lastModified: 0
Absolute path: F:\java_test\test2.txt
?Can read: true
?Can write: true
?getName: test2.txt
?getParent: null
?getPath: test2.txt
?length: 0
?lastModified: 1460890496589
it‘s a file
?
在fileData()中。可看到應用了各種文件調查方法來顯示與文件或文件夾路徑有關的信息。
main()應用的第一個方法是 renameTo(),利用它可以重命名(或移動)一個文件至一個全新的路徑(該路徑由參數決定),它屬於還有一個File 對象。這也適用於不論什麽長度的文件夾。
若試驗上述程序。就可發現自己能制作隨意復雜程度的一個文件夾路徑,由於mkdirs()會幫我們完畢全部工作。在Java 1.0 中,-d標誌報告文件夾雖然已被刪除,但它依舊存在。但在 Java 1.1 中,文件夾會被實際刪除。
2.??附SortVector.java
import java.util.*;
public classSortVector extends Vector {
??? private Compare compare; // To hold the callback
??? public SortVector(Compare comp) {
??????? compare = comp;
??? }
??? public void sort() {
??????? quickSort(0,size() - 1);
??? }
??? private void quickSort(int left, int right) {
??????? if (right > left) {
??????????? Objecto1 = elementAt(right);
??????????? int i = left - 1;
??????????? int j = right;
??????????? while (true) {
??????????????? while (compare.lessThan(elementAt(++i), o1))
??????????????????? ;
??????????????? while (j > 0)
??????????????????? if (compare.lessThanOrEqual(elementAt(--j), o1))
??????????????????????? break; // out of while
??????????????? if (i >= j)
??????????????????? break;
??????????????? swap(i, j);
??????????? }
??????????? swap(i, right);
??????????? quickSort(left, i - 1);
??????????? quickSort(i + 1, right);
??????? }
??? }
??? private void swap(int loc1, int loc2) {
??????? Objecttmp= elementAt(loc1);
??????? setElementAt(elementAt(loc2), loc1);
??????? setElementAt(tmp, loc2);
??? }
} /// :~
3.??附StrSortVector.java
import java.util.*;
interface Compare {
??? boolean lessThan(Object lhs, Object rhs);
?
??? boolean lessThanOrEqual(Object lhs, Object rhs);
} /// :~
public classStrSortVector{
??? private SortVector v = new SortVector(
??????????? // Anonymous inner class:
??????????? new Compare() {
??????????????? public boolean lessThan(Object l, Object r) {
??????????????????? return ((String) l).toLowerCase().compareTo(((String)r).toLowerCase())< 0;
??????????????? }
??????????????? public boolean lessThanOrEqual(Object l, Object r) {
??????????????????? return ((String) l).toLowerCase().compareTo(((String)r).toLowerCase())<= 0;
??????????????? }
??????????? });
??? private boolean sorted = false;
??? public void addElement(String s) {
??????? v.addElement(s);
??????? sorted = false;
??? }
??? public String elementAt(int index) {
??????? if (!sorted) {
??????????? v.sort();
??????????? sorted = true;
??????? }
??????? return (String) v.elementAt(index);
??? }
??? public Enumerationelements() {
??????? if (!sorted) {
??????????? v.sort();
??????????? sorted = true;
??????? }
??????? return v.elements();
??? }
??? // Test it:
??? public static void main(String[] args) {
??????? StrSortVector sv = new StrSortVector();
??????? sv.addElement("d");
??????? sv.addElement("A");
??????? sv.addElement("C");
??????? sv.addElement("c");
??????? sv.addElement("b");
??????? sv.addElement("B");
??????? sv.addElement("D");
??????? sv.addElement("a");
??????? Enumeratione = sv.elements();
??????? while (e.hasMoreElements())
??????????? System.out.println(e.nextElement());
??? }
} /// :~
?
?
33.JAVA編程思想——JAVA IO File類