亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java I/O深入學(xué)習(xí)之File和RandomAccessFile

 更新時間:2019年06月18日 09:17:31   作者:木瓜芒果  
這篇文章主要介紹了Java I/O深入學(xué)習(xí)之File和RandomAccessFile, I/O系統(tǒng)即輸入/輸出系統(tǒng),對于一門程序語言來說,創(chuàng)建一個好的輸入/輸出系統(tǒng)并非易事。在充分理解Java I/O系統(tǒng)以便正確地運用之前,我們需要學(xué)習(xí)相當(dāng)數(shù)量的類。,需要的朋友可以參考下

前言

I/O系統(tǒng)即輸入/輸出系統(tǒng),對于一門程序語言來說,創(chuàng)建一個好的輸入/輸出系統(tǒng)并非易事。因為不僅存在各種I/O源端和想要與之通信的接收端(文件、控制臺、網(wǎng)絡(luò)鏈接等),而且還需要支持多種不同方式的通信(順序、隨機存取、緩沖、二進制、按字符、按行、按字等)。

Java類庫的設(shè)計者通過創(chuàng)建大量的類來解決這個難題,比如面向字節(jié)的類(字節(jié)流,InputStream、OutputStream)、面向字符和基于Unicode的類(字節(jié)流,Reader、Writer)、nio類(新I/O,為了改進性能及功能)等。所以,在充分理解Java I/O系統(tǒng)以便正確地運用之前,我們需要學(xué)習(xí)相當(dāng)數(shù)量的類。因此一開始可能會對Java I/O系統(tǒng)提供的如此多的類感到迷惑,不過在我們系統(tǒng)地梳理完整個Java I/O系統(tǒng)并將這部分知識與融入到自我的整個知識體系中后,我們就能很快消除這種迷惑。

在I/O這個專題里面,我會總結(jié)Java 中涉及到的大多數(shù)I/O相關(guān)類的用法,從傳統(tǒng)I/O諸如:File、字節(jié)流、字符流、序列化到新I/O:nio。在本節(jié)中我會先總結(jié)File和RandomAccessFile的相關(guān)知識,按照如下順序:

1. File

1.1 File簡介常用方法

根據(jù)官方文檔的解釋,Java中的File類是文件和目錄路徑的抽象,用戶通過File直接執(zhí)行與文件或目錄相關(guān)的操作。我的理解就是File類的作用是用來指代文件或者目錄的,通過File的抽象我們可以很方便的操作文件或目錄,無需關(guān)心操作系統(tǒng)的差異。官方文檔是這樣描述的:

An abstract representation of file and directory pathnames.

User interfaces and operating systems use system-dependent pathname strings to name files and directories. This class presents an abstract, system-independent view of hierarchical pathnames.

用戶接口和操作系統(tǒng)通過系統(tǒng)相關(guān)的路徑名來命名文件和目錄。而File類提供了一個抽象地、系統(tǒng)無關(guān)的視角來描述分層次路徑名。File代表抽象路徑名,有兩個部分組成:  

  • 一個可選的系統(tǒng)相關(guān)的前綴,比如磁盤驅(qū)動器說明符(disk-drive specifier),unix系統(tǒng)中是“/”而windows系統(tǒng)中則是“\”;
  • 0或多個字符串名稱組成的序列;

關(guān)于File的用法,我覺得直接通過示例來學(xué)習(xí)會比較高效:  

public class FileDemo { 
public static void main(String[] args) throws IOException {
File dir = new File("f:/dirDemo");
System.out.println("dir exists: " + dir.exists());
dir.mkdirs();
System.out.println("dir exists: " + dir.exists());
if(dir.isFile()) {
System.out.println("dir is a file.");
}else if(dir.isDirectory()) {
System.out.println("dir is a directory");
}
File file = new File("f:/dirDemo/fileDemo"); 
System.out.println(
"\n Absolute path: " + file.getAbsolutePath() +
"\n Can read: " + file.canRead() + 
"\n Can write: " + file.canWrite() +
"\n getName: " + file.getName() +
"\n getParent: " + file.getParent() +
"\n getPath: " + file.getPath() +
"\n length: " + file.length() +
"\n lastModified: " + file.lastModified() +
"\n isExist: " + file.exists());
file.createNewFile();
System.out.println("is file exist: " + file.exists());
if(file.isFile()) {
System.out.println("file is a file.");
}else if(file.isDirectory()) {
System.out.println("file is a directory");
}
System.out.println();
for(String filename : dir.list()) {
System.out.println(filename);
}
} 
}

輸出結(jié)果:

dir exists: false
dir exists: true
dir is a directory
Absolute path: f:\dirDemo\fileDemo
Can read: false
Can write: false
getName: fileDemo
getParent: f:\dirDemo
getPath: f:\dirDemo\fileDemo
length: 0
lastModified: 0
isExist: false
is file exist: true
file is a file.
fileDemo

在這個簡單demo中我們用到多種不同的文件特征查詢方法來顯示文件或目錄路徑的信息:

  • getAbsolutePath(),獲取文件或目錄的絕對路徑;
  • canRead()、canWrite(),文件是否可讀/可寫;
  • getName(),獲取文件名;
  • getParent(),獲取父一級的目錄路徑名;
  • getPath(),獲取文件路徑名;
  • length(),文件長度;
  • lastModified(),文件最后修改時間,返回時間戳;
  • exists(),文件是否存在;
  • isFile(),是否是文件;
  • isDirectory(),是否是目錄;
  • mkdirs(),創(chuàng)建目錄,會把不存在的目錄一并創(chuàng)建出來;
  • createNewFile(),創(chuàng)建文件;
  • list(),可以返回目錄下的所有File名,以字符數(shù)組的形式返回;

exists()方法可以返回一個File實例是否存在,這里的存在是指是否在磁盤上存在,而不是指File實例存在于虛擬機堆內(nèi)存中。一個File類的實例可能表示一個實際的文件系統(tǒng)如文件或目錄,也可能沒有實際意義,僅僅只是一個File類,并沒有關(guān)聯(lián)實際文件,如果沒有則exists()返回false。

1.2 File過濾器

list()方法返回的數(shù)組中包含此File下的所有文件名,如果想要獲得一個指定的列表,比如,希望得到所有擴展名為.java的文件,可以使用“目錄過濾器”(實現(xiàn)了FilenameFilter接口),在這個類里面可以指定怎樣顯示符合條件的File對象。我們把一個自己實現(xiàn)的FilenameFilter傳入list(FilenameFilter filter)方法中,在這個被當(dāng)做參數(shù)的FilenameFilter中重寫其accept()方法,指定我們自己想要的邏輯即可,這其實是策略模式的體現(xiàn)。

比如我們只要獲取當(dāng)前項目跟目錄下的xml文件:

public class XmlList { 
public static void main(final String[] args) {
File file = new File(".");
String list;
list = file.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
Pattern pattern = Pattern.compile("(.*)\\.xml");
return pattern.matcher(name).matches();
}
});
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for(String dirItem : list)
System.out.println(dirItem);
}
}

在這個例子中,我們用匿名內(nèi)部類的方式給list()傳參,accept()方法內(nèi)部我們指定了正則過濾策略,在調(diào)用File的list()方法時會自動為此目錄對象下的每個文件名調(diào)用accept()方法,來判斷是否要將該文件包含在內(nèi),判斷結(jié)果由accept()返回的布爾值來表示。

如上也只是羅列了一些個人認(rèn)為File類較常用的方法,也只是一部分,若需要更詳細(xì)信息請參考官方文檔。

1.3 目錄工具

接下來我們來看一個實用工具,可以獲得指定目錄下的所有或者符合要求的File集合:

public class Directory {
// local方法可以獲得指定目錄下指定文件的集合
public static File[] local(File dir,String regex) {
return dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
}
public static File[] local(String dir,String regex) {
return local(new File(dir),regex);
}
// walk()方法可以獲得指定目錄下所有符合要求的文件或目錄,包括子目錄下
public static TreeInfo walk(String start,String regex) {
return recurseDirs(new File(start),regex);
}
public static TreeInfo walk(File start,String regex) {
return recurseDirs(start,regex);
}
public static TreeInfo walk(String start) {
return recurseDirs(new File(start),".*");
}
public static TreeInfo walk(File start) {
return recurseDirs(start,".*");
}
static TreeInfo recurseDirs(File startDir,String regex) {
TreeInfo treeInfo = new TreeInfo();
for(File item : startDir.listFiles()) {
if(item.isDirectory()) {
treeInfo.dirs.add(item);
treeInfo.addAll(recurseDirs(item,regex));
}else {
if(item.getName().matches(regex))
treeInfo.files.add(item);
}
}
return treeInfo;
}
public static class TreeInfo implements Iterable<File>{

public List<File> files = new ArrayList();
public List<File> dirs = new ArrayList();
@Override
public Iterator<File> iterator() {
return files.iterator();
}
void addAll(TreeInfo other) {
files.addAll(other.files);
dirs.addAll(other.dirs);
}
}
}

通過工具中的local()方法,我們可以獲得指定目錄下符合要求文件的集合,通過walk()方法可以獲得指定目錄下所有符合要求的文件或目錄,包括其子目錄下的文件,這個工具只是記錄在這里以備不時之需。

2. RandomAccessFile

因為File類知識文件的抽象表示,并沒有指定信息怎樣從文件讀取或向文件存儲,而向文件讀取或存儲信息主要有兩種方式:

  • 通過輸入輸出流,即InputStream、OutputStream;
  • 通過RandomAccessFile;

輸入輸出流的方式我們后面會專門總結(jié),這也是Java I/O系統(tǒng)中很大的一塊,本文會講一下RandomAccessFile,因為它比較獨立,和流的相關(guān)性不大。

RandomAccessFile是一個完全獨立的類,其擁有和我們后面將總結(jié)的IO類型有本質(zhì)不同的行為,可以在一個文件內(nèi)向前和向后移動。我們來看一下其主要方法:

  • void write(int d) 向文件中寫入1個字節(jié),寫入的是傳入的int值對應(yīng)二進制的低8位;
  • int read() 讀取1個字節(jié),并以int形式返回,如果返回-1則代表已到文件末尾;
  • int read(byte[] data) 一次性從文件中讀取字節(jié)數(shù)組總長度的字節(jié)量,并存入到該字節(jié)數(shù)組中,返回的int值代表讀入的總字節(jié)數(shù),如果返回-1則代表未讀取到任何數(shù)據(jù)。通常字節(jié)數(shù)組的長度可以指定為1024*10(大概10Kb的樣子,效率比較好);
  • int read(byte[] data, int off, int len) 一次性從文件中讀取最多l(xiāng)en個字節(jié),并存入到data數(shù)組中,從下標(biāo)off處開始;
  • void write(int b) 往文件中寫入1個字節(jié)的內(nèi)容,所寫的內(nèi)容為傳入的int值對應(yīng)二進制的低8位;
  • write(byte b[]) 往文件中寫入一個字節(jié)數(shù)組的內(nèi)容;
  • write(byte b[], int off, int len) 往文件中寫入從數(shù)組b的下標(biāo)off開始len個字節(jié)的內(nèi)容;
  • seek(long pos) 設(shè)置文件指針偏移量為指定值,即在文件內(nèi)移動至新的位置;
  • long getFilePointer() 獲取文件指針的當(dāng)前位置;
  • void close() 關(guān)閉RandomAccessFile;

上面只是一部分方法,更多請參考官方文檔。我們再來看一個簡單demo學(xué)習(xí)一下:

public class RandomAccessFileDemo { 
public static void main(String[] args) {
File file = new File("./test.txt");
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("./test.txt","rw");
raf.write(1000);
raf.seek(0);
System.out.println(raf.read());
raf.seek(0); 
System.out.println(raf.readInt());
} catch (FileNotFoundException e) {
System.out.println("file not found");
} catch (EOFException e) {
System.out.println("reachs end before read enough bytes");
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

輸出結(jié)果:

232
reachs end before read enough bytes

在RandomAccessFile的構(gòu)造器中有兩個參數(shù),第一個是文件路徑或者File,代表該RandomAccessFile要操作的文件,第二個是讀寫模式。如果操作的文件不存在,在模式為“rw”時會直接創(chuàng)建文件,如果是“r”則會拋出異常。

這是一個簡單的例子,首先創(chuàng)建文件test.txt,然后創(chuàng)建一個和該文件關(guān)聯(lián)的RandomAccessFile,指定讀寫模式為讀寫,調(diào)用write()寫入1000,這里只會寫入一個字節(jié),跳到文件頭部,讀取1個字節(jié),輸出232(正好是1000對應(yīng)二進制的低8位),再跳到文件頭部,調(diào)用readInt()讀取1個整數(shù),這時候因為文件中只有1個字節(jié),所以拋出EOFException異常,最后關(guān)閉RandomAccessFile。

如上例子我們學(xué)習(xí)了RandomAccessFile的基本用法,這里有一點需要注意,RandomAccessFile是基于文件指針從當(dāng)前位置來讀寫的,并且寫入操作是直接將插入點后面的內(nèi)容覆蓋而不是插入。如果我們想實現(xiàn)插入操作,則需要將插入點后面的內(nèi)容先保存下來,再寫入要插入的內(nèi)容,最后將保存的內(nèi)容添加進來,看下面的例子:

public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
File file = new File("f:/test.txt");
file.createNewFile();
// 創(chuàng)建臨時空文件用于緩沖,并指定在虛擬機停止時將其刪除
File temp = File.createTempFile("temp", null);
temp.deleteOnExit();
RandomAccessFile raf = null;
try {
// 首先往文件中寫入下面的詩句,并讀取出來在控制臺打印
raf = new RandomAccessFile(file,"rw");
raf.write("明月幾時有,把酒問青天".getBytes());
raf.seek(0); 
byte[] b = new byte[60];
raf.read(b, 0, 30);
System.out.println(new String(b));
// 接下來在詩句中間再插入一句詩
raf.seek(12);
FileOutputStream fos = new FileOutputStream(temp);
FileInputStream fis = new FileInputStream(temp);
byte[] buffer = new byte[10];
int num = 0;
while(-1 != (num = raf.read(buffer))) {
fos.write(buffer, 0, num);
}
raf.seek(12);
raf.write("但愿人長久,千里共嬋娟。".getBytes());
// 插入完成后將緩沖的后半部分內(nèi)容添加進來
while(-1 != (num = fis.read(buffer))) {
raf.write(buffer, 0, num);
}
raf.seek(0);
raf.read(b, 0, 60);
System.out.println(new String(b));
System.out.println();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
raf.close();
}
}
}

輸出結(jié)果,插入詩句成功:

明月幾時有,把酒問青天
明月幾時有,但愿人長久,千里共嬋娟。把酒問青天

3. 總結(jié)

本文是Java I/O系統(tǒng)系列第一篇,主要總結(jié)了File和RandomAccessFile的一些知識。

File類是對文件和目錄路徑的抽象,用戶通過File來直接執(zhí)行與文件或目錄相關(guān)的操作,無需關(guān)心操作系統(tǒng)的差異。

RandomAccessFile類可以寫入和讀取文件,其最大的特點就是可以在任意位置讀取文件(random access的意思),是通過文件指針實現(xiàn)的。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 學(xué)習(xí)Java之如何對時間進行格式化

    學(xué)習(xí)Java之如何對時間進行格式化

    當(dāng)我們在默認(rèn)情況下構(gòu)造出來的時間對象,它的時間格式并不適合我們閱讀,并且在開發(fā)時,pc端、Android端、iOS端等展示的時間格式可能也并不完全一樣,本文就從這幾個問題給大家介紹如何對時間進行格式化,感興趣的同學(xué)可以借鑒一下
    2023-05-05
  • Java深入分析動態(tài)代理

    Java深入分析動態(tài)代理

    動態(tài)代理指的是,代理類和目標(biāo)類的關(guān)系在程序運行的時候確定的,客戶通過代理類來調(diào)用目標(biāo)對象的方法,是在程序運行時根據(jù)需要動態(tài)的創(chuàng)建目標(biāo)類的代理對象。本文將通過案例詳細(xì)講解一下Java動態(tài)代理的原理及實現(xiàn),需要的可以參考一下
    2022-07-07
  • Java實現(xiàn)快速并查集

    Java實現(xiàn)快速并查集

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)快速并查集,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 詳解Java?Unsafe如何花式操作內(nèi)存

    詳解Java?Unsafe如何花式操作內(nèi)存

    C++可以動態(tài)的分類內(nèi)存,而java并不能這樣,是不是java就不能操作內(nèi)存呢,其實是有其他辦法可以操作內(nèi)存的,下面就一起看看Unsafe是如何花式操作內(nèi)存的吧
    2023-08-08
  • spring與mybatis三種整合方法

    spring與mybatis三種整合方法

    這篇文章主要介紹了spring與mybatis三種整合方法,需要的朋友可以參考下
    2017-04-04
  • Java使用MySQL實現(xiàn)連接池代碼實例

    Java使用MySQL實現(xiàn)連接池代碼實例

    這篇文章主要介紹了Java使用MySQL實現(xiàn)連接池代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • java中常見XML解析器的使用詳解(JAXP,DOM4J,Jsoup,JsoupXPath)

    java中常見XML解析器的使用詳解(JAXP,DOM4J,Jsoup,JsoupXPath)

    為了處理和操作XML數(shù)據(jù),我們需要使用XML解析器,本文將介紹幾種常用的XML解析器,包括JAXP、DOM4J、Jsoup和JsoupXPath,需要的小伙伴可以參考一下
    2023-11-11
  • 這么設(shè)置IDEA中的Maven,再也不用擔(dān)心依賴下載失敗了

    這么設(shè)置IDEA中的Maven,再也不用擔(dān)心依賴下載失敗了

    今天給大家?guī)硪粋€IDEA中Maven設(shè)置的小技巧.這個技巧可以說非常有用,學(xué)會設(shè)置之后,再也不用擔(dān)心maven依賴下載變慢的問題,需要的朋友可以參考下
    2021-05-05
  • Java實現(xiàn)滑動驗證碼(前端部分)

    Java實現(xiàn)滑動驗證碼(前端部分)

    這篇文章主要為大家介紹了如何用Java語言實現(xiàn)滑動驗證碼的生成(前端部分),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2022-10-10
  • Java實現(xiàn)生成n個不重復(fù)的隨機數(shù)

    Java實現(xiàn)生成n個不重復(fù)的隨機數(shù)

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)生成n個不重復(fù)的隨機數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05

最新評論