JAVA 中的 IO 流

File 類的使用

  • java.io.File 類:文件和文件目錄路徑的抽象表示形式,與平臺無關(guān)
  • File 能新建纷闺、刪除算凿、重命名文件和目錄,但不能訪問文件內(nèi)容本身犁功。如果需要訪問文件內(nèi)容本身氓轰,則需要使用輸入/輸出流
  • 想要在 Java 程序中表示一個真實存在的文件或目錄,那么必須有一個 File 對 象浸卦,但是 Java 程序中的一個 File 對象署鸡,可能沒有一個真實存在的文件或目錄
  • File 對象可以作為參數(shù)傳遞給流的構(gòu)造器

File 類的常用構(gòu)造器

  • public File(String pathname)

    以 pathname 為路徑創(chuàng)建 File 對象

  • public File(String parent,String child)

    以 parent 為父路徑,child 為子路徑創(chuàng)建 File 對象

  • public File(File parent,String child)

    根據(jù)一個父 File 對象和子文件路徑創(chuàng)建 File 對象

路徑中的每級目錄之間用一個路徑分隔符隔開限嫌,windows和DOS系統(tǒng)默認(rèn)使用 \ 來表示靴庆,UNIX 和 URL 使用 / 來表示。Java 程序支持跨平臺運行萤皂,因此路徑分隔符要慎用撒穷。為了解決這個隱患,F(xiàn)ile 類提供了一個常量:

  • public static final String separator

根據(jù)操作系統(tǒng)裆熙,動態(tài)的提供分隔符端礼。

舉例:

File file1 = new File("d:\\atguigu\\info.txt");
File file2 = new File("d:" + File.separator + "atguigu" + File.separator + "info.txt");
File file3 = new File("d:/atguigu");

File 類常用方法

File 類的獲取功能

  • public String getAbsolutePath():獲取絕對路徑

  • public String getPath() :獲取路徑

  • public String getName() :獲取名稱

  • public String getParent():獲取上層文件目錄路徑禽笑。若無,返回 null

  • public long length() :獲取文件長度(即:字節(jié)數(shù))蛤奥。不能獲取目錄的長度佳镜。

  • public long lastModified() :獲取最后一次的修改時間,毫秒值

  • public String[] list() :獲取指定目錄下的所有文件或者文件目錄的名稱數(shù)組

  • public File[] listFiles() :獲取指定目錄下的所有文件或者文件目錄的 File 數(shù)組

File 類的重命名功能

  • public boolean renameTo(File dest):把文件重命名為指定的文件路徑

File 類的判斷功能

  • public boolean isDirectory():判斷是否是文件目錄

  • public boolean isFile() :判斷是否是文件

  • public boolean exists() :判斷是否存在

  • public boolean canRead() :判斷是否可讀

  • public boolean canWrite() :判斷是否可寫

  • public boolean isHidden() :判斷是否隱藏

File 類的創(chuàng)建功能

  • public boolean createNewFile() :創(chuàng)建文件凡桥。若文件存在蟀伸,則不創(chuàng)建,返回 false

  • public boolean mkdir() :創(chuàng)建文件目錄缅刽。如果此文件目錄存在啊掏,就不創(chuàng)建了。如果此文件目錄的上層目錄不存在衰猛,也不創(chuàng)建迟蜜。

  • public boolean mkdirs() :創(chuàng)建文件目錄。如果上層文件目錄不存在啡省,一并創(chuàng)建

File 類的刪除功能

  • public boolean delete():刪除文件或者文件夾

Java中的刪除不走回收站娜睛。要刪除一個文件目錄,請注意該文件目錄內(nèi)不能包含文件或者文件目錄卦睹。

IO 流原理及流的分類

Java IO 原理

  • I/O 是 Input/Output 的縮寫畦戒, I/O 技術(shù)是非常實用的技術(shù),用于處理設(shè)備之間的數(shù)據(jù)傳輸结序。如讀/寫文件障斋,網(wǎng)絡(luò)通訊等。Java 程序中笼痹,對于數(shù)據(jù)的輸入/輸出操作以 流(stream) 的方式進行配喳。java.io 包下提供了各種 類和接口,用以獲取不同種類的數(shù)據(jù)凳干,并通過標(biāo)準(zhǔn)的方法輸入或輸出數(shù)據(jù)晴裹。
  • 輸入input:讀取外部數(shù)據(jù)(磁盤、光盤等存儲設(shè)備的數(shù)據(jù))到程序(內(nèi)存)中救赐。
  • 輸出 output:將程序(內(nèi)存)數(shù)據(jù)輸出到磁盤涧团、光盤等存儲設(shè)備中。

流的分類

  • 按操作數(shù)據(jù)單位不同分為:字節(jié)流(8 bit)经磅,字符流(16 bit)

  • 按數(shù)據(jù)流的流向不同分為:輸入流泌绣,輸出流

  • 按流的角色的不同分為:節(jié)點流,處理流

image.png

FileInputStream 用于讀取非文本數(shù)據(jù)之類的原始字節(jié)流预厌。要讀取字符流阿迈,需要使用 FileReader。

FileOutputStream 用于寫出非文本數(shù)據(jù)之類的原始字節(jié)流轧叽。要寫出字符流苗沧,需要使用 FileWriter刊棕。

在寫入一個文件時,如果使用構(gòu)造器 FileOutputStream(file)待逞,則目錄下有同名文
件將被覆蓋甥角。如果使用構(gòu)造器 FileOutputStream(file,true),則目錄下的同名文件不會被覆蓋识樱,在文件內(nèi)容末尾追加內(nèi)容嗤无。

在讀取文件時,必須保證該文件已存在怜庸,否則報異常当犯。

  • 字節(jié)流操作字節(jié),比如:.mp3割疾,.avi灶壶,.rmvb,mp4杈曲,.jpg,.doc胸懈,.ppt
  • 字符流操作字符担扑,只能操作普通文本文件。最常見的文本文:.txt趣钱,.java涌献,.c,.cpp 等語言的源代碼首有。尤其注意 .doc, excel, ppt 這些不是文本文件

緩沖流

為了提高數(shù)據(jù)讀寫的速度燕垃,Java API 提供了帶緩沖功能的流類,在使用這些流類時井联,會創(chuàng)建一個內(nèi)部緩沖區(qū)數(shù)組卜壕,缺省使用 8192 個字節(jié)(8Kb)的緩沖區(qū)。

  • 當(dāng)讀取數(shù)據(jù)時烙常,數(shù)據(jù)按塊讀入緩沖區(qū)轴捎,其后的讀操作則直接訪問緩沖區(qū)
  • 當(dāng)使用 BufferedInputStream 讀取字節(jié)文件時,BufferedInputStream 會一次性從文件中讀取 8192個(8Kb)蚕脏,存在緩沖區(qū)中侦副,直到緩沖區(qū)裝滿了,才重新從文件中讀取下一個 8192 個字節(jié)數(shù)組
  • 向流中寫入字節(jié)時驼鞭,不會直接寫到文件秦驯,先寫到緩沖區(qū)中直到緩沖區(qū)寫滿, BufferedOutputStream 才會把緩沖區(qū)中的數(shù)據(jù)一次性寫到文件里挣棕。使用方法 flush() 可以強制將緩沖區(qū)的內(nèi)容全部寫入輸出流
  • 關(guān)閉流的順序和打開流的順序相反译隘。只要關(guān)閉最外層流即可亲桥,關(guān)閉最外層流也會相應(yīng)關(guān)閉內(nèi)層節(jié)點流
  • flush() 方法的使用:手動將 buffer 中內(nèi)容寫入文件
  • 如果是帶緩沖區(qū)的流對象的 close() 方法,不但會關(guān)閉流细燎,還會在關(guān)閉流之前刷新緩沖區(qū)两曼,關(guān)閉后不能再寫出

轉(zhuǎn)換流

轉(zhuǎn)換流提供了在字節(jié)流和字符流之間的轉(zhuǎn)換。Java API提供了兩個轉(zhuǎn)換流:

  • InputStreamReader:將 InputStream 轉(zhuǎn)換為 Reader

  • OutputStreamWriter:將 Writer 轉(zhuǎn)換為 OutputStream

字節(jié)流中的數(shù)據(jù)都是字符時玻驻,轉(zhuǎn)成字符流操作更高效悼凑,很多時候我們使用轉(zhuǎn)換流來處理文件亂碼問題。實現(xiàn)編碼和解碼的功能璧瞬。

public void testMyInput() throws Exception {
    FileInputStream fis = new FileInputStream("dbcp.txt");
    FileOutputStream fos = new FileOutputStream("dbcp1.txt");
    
    InputStreamReader isr = new InputStreamReader(fis, "GBK");
    OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
    
    BufferedReader br = new BufferedReader(isr);
    BufferedWriter bw = new BufferedWriter(osw);
    
    String str = null;
    while ((str = br.readLine()) != null) {
        bw.write(str);
        bw.newLine();
        bw.flush();
    }
    bw.close();
    br.close();
}

數(shù)據(jù)流

為了方便地操作 Java 語言的基本數(shù)據(jù)類型和 String 的數(shù)據(jù)户辫,可以使用數(shù)據(jù)流。為了方便地操作Java語言的基本數(shù)據(jù)類型和 String 的數(shù)據(jù)嗤锉,可以使用數(shù)據(jù)流渔欢。

  • DataInputStreamDataOutputStream
  • 分別“套接”在 InputStreamOutputStream 子類的流上

DataInputStream 中的方法

  • boolean readBoolean()
  • byte readByte()
  • char readChar()
  • float readFloat()
  • double readDouble()
  • short readShort()
  • long readLong()
  • int readInt()
  • String readUTF()
  • void readFully(byte[] b)
DataInputStream dis = null;
try {
    dis = new DataInputStream(new FileInputStream("destData.dat"));
    String info = dis.readUTF();
    boolean flag = dis.readBoolean();
    long time = dis.readLong();
    System.out.println(info);
    System.out.println(flag);
    System.out.println(time);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (dis != null) {
        try {
            dis.close();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

DataOutputStream 中的方法

將上述的方法的 read 改為相應(yīng)的 write 即可。

DataOutputStream dos = null;
try { // 創(chuàng)建連接到指定文件的數(shù)據(jù)輸出流對象
    dos = new DataOutputStream(new FileOutputStream("destData.dat"));
    dos.writeUTF("我愛北京天安門"); // 寫UTF字符串
    dos.writeBoolean(false); // 寫入布爾值
    dos.writeLong(1234567890L); // 寫入長整數(shù)
    System.out.println("寫文件成功!");
} catch (IOException e) {
    e.printStackTrace();
} finally { // 關(guān)閉流對象
    try {
        if (dos != null) {
            // 關(guān)閉過濾流時,會自動關(guān)閉它包裝的底層節(jié)點流
            dos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } 
}

對象流(ObjectInputStream和OjbectOutputSteam)

用于存儲和讀取基本數(shù)據(jù)類型數(shù)據(jù)或?qū)ο蟮奶幚砹魑脸馈K膹姶笾幘褪强梢园?Java 中的對象寫入到數(shù)據(jù)源中奥额,也能把對象從數(shù)據(jù)源中還原回來。

  • 序列化:用 ObjectOutputStream 類保存基本類型數(shù)據(jù)或?qū)ο蟮臋C制访诱。

  • 反序列化:用 ObjectInputStream 類讀取基本類型數(shù)據(jù)或?qū)ο蟮臋C制垫挨。

注意:ObjectOutputStream 和ObjectInputStream 不能序列化 static 和 transient 修飾的成員變量。

對象序列化機制允許把內(nèi)存中的 Java 對象轉(zhuǎn)換成平臺無關(guān)的二進制流触菜,從而允許把這種二進制流持久地保存在磁盤上九榔,或通過網(wǎng)絡(luò)將這種二進制流傳輸?shù)搅硪粋€網(wǎng)絡(luò)節(jié)點。當(dāng)其它程序獲取了這種二進制流涡相,就可以恢復(fù)成原來的 Java 對象哲泊。

序列化的好處在于可將任何實現(xiàn)了 Serializable 接口的對象轉(zhuǎn)化為字節(jié)數(shù)據(jù),使其在保存和傳輸時可被還原催蝗。

序列化是 RMI(Remote Method Invoke – 遠程方法調(diào)用)過程的參數(shù)和返回值都必須實現(xiàn)的機制切威,而 RMI 是 JavaEE 的基礎(chǔ)。因此序列化機制是 JavaEE 平臺的基礎(chǔ)丙号。

如果需要讓某個對象支持序列化機制牢屋,則必須讓對象所屬的類及其屬性是可序列化的,為了讓某個類是可序列化的槽袄,該類必須實現(xiàn)如下兩個接口之一烙无。否則,會拋出 NotSerializableException 異常遍尺。

  • Serializable

  • Externalizable

凡是實現(xiàn) Serializable 接口的類都有一個表示序列化版本標(biāo)識符的靜態(tài)變量:

  • private static final long serialVersionUID

如果類沒有顯示定義這個靜態(tài)常量截酷,它的值是 Java 運行時環(huán)境根據(jù)類的內(nèi)部細節(jié)自動生成的。若類的實例變量做了修改乾戏,serialVersionUID 可能發(fā)生變化迂苛。故建議三热,顯式聲明。

簡單來說三幻,Java 的序列化機制是通過在運行時判斷類的 serialVersionUID 來驗證版本一致性的就漾。在進行反序列化時,JVM 會把傳來的字節(jié)流中的 serialVersionUID 與本地相應(yīng)實體類的 serialVersionUID 進行比較念搬,如果相同就認(rèn)為是一致的抑堡,可以進行反序列化,否則就會出現(xiàn)序列化版本不一致的異常(InvalidCastException)朗徊。

// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韓梅梅", 18, "中華大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();

注意:寫一次首妖,操作 flush() 一次。

// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();

隨機存取文件流(RandomAccessFile 類)的使用

RandomAccessFile 聲明在 java.io 包下爷恳,但直接繼承于 java.lang.Object 類有缆。并且它實現(xiàn)了 DataInput、DataOutput 這兩個接口温亲,也就意味著這個類既可以讀也可以寫棚壁。

構(gòu)造器

  • public RandomAccessFile(File file, String mode)
  • public RandomAccessFile(String name, String mode)

創(chuàng)建 RandomAccessFile 類實例需要指定一個 mode 參數(shù),該參數(shù)指定 RandomAccessFile 的訪問模式:

  • r:以只讀方式打開
  • rw:打開以便讀取和寫入
  • rwd:打開以便讀取和寫入;同步文件內(nèi)容的更新
  • rws::打開以便讀取和寫入;同步文件內(nèi)容和元數(shù)據(jù)的更新

如果模式為只讀 r口柳。則不會創(chuàng)建文件,而是會去讀取一個已經(jīng)存在的文件,如果讀取的文件不存在則會出現(xiàn)異常逆害。 如果模式為 rw 讀寫头镊。如果文件不存在則會去創(chuàng)建文件,如果存在則不會創(chuàng)建魄幕。

RandomAccessFile 對象包含一個記錄指針相艇,用以標(biāo)示當(dāng)前讀寫處的位置。 RandomAccessFile 類對象可以自由移動記錄指針:

  • long getFilePointer():獲取文件記錄指針的當(dāng)前位置
  • void seek(long pos):將文件記錄指針定位到 pos 位置
// 讀取文件
RandomAccessFile raf = new RandomAccessFile(“test.txt”, “rw”);
// 指針跳到角標(biāo)為5的位置
raf.seek(5);
byte [] b = new byte[1024];
int off = 0;
int len = 5;
raf.read(b, off, len);
String str = new String(b, 0, len);
System.out.println(str);
raf.close();
// 寫入文件
RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
raf.seek(5);
//先讀出來
String temp = raf.readLine();
// 指針跳到角標(biāo)為5的位置纯陨,可以理解為在角標(biāo)為5的位置插入數(shù)據(jù)
raf.seek(5);
raf.write("xyz".getBytes());
raf.write(temp.getBytes());
raf.close();

我們可以用 RandomAccessFile 這個類坛芽,來實現(xiàn)一個多線程斷點下載的功能,用過下載工具的朋友們都知道翼抠,下載前都會建立兩個臨時文件咙轩,一個是與被下載文件大小相同的空文件,另一個是記錄文件指針的位置文件阴颖,每次暫停的時候活喊,都會保存上一次的指針,然后斷點下載的時候量愧,會繼續(xù)從上一次的地方下載钾菊,從而實現(xiàn)斷點下載或上傳的功能帅矗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市煞烫,隨后出現(xiàn)的幾起案子浑此,更是在濱河造成了極大的恐慌,老刑警劉巖滞详,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凛俱,死亡現(xiàn)場離奇詭異,居然都是意外死亡茵宪,警方通過查閱死者的電腦和手機最冰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稀火,“玉大人暖哨,你說我怎么就攤上這事』四” “怎么了篇裁?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赡若。 經(jīng)常有香客問我达布,道長,這世上最難降的妖魔是什么逾冬? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任黍聂,我火速辦了婚禮,結(jié)果婚禮上身腻,老公的妹妹穿的比我還像新娘产还。我一直安慰自己,他們只是感情好嘀趟,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布脐区。 她就那樣靜靜地躺著,像睡著了一般她按。 火紅的嫁衣襯著肌膚如雪牛隅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天酌泰,我揣著相機與錄音媒佣,去河邊找鬼。 笑死陵刹,一個胖子當(dāng)著我的面吹牛丈攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巡验,長吁一口氣:“原來是場噩夢啊……” “哼际插!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起显设,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤框弛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捕捂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瑟枫,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年指攒,在試婚紗的時候發(fā)現(xiàn)自己被綠了慷妙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡允悦,死狀恐怖膝擂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隙弛,我是刑警寧澤架馋,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站全闷,受9級特大地震影響叉寂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜总珠,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一屏鳍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧局服,春花似錦钓瞭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽超埋。三九已至搏讶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霍殴,已是汗流浹背媒惕。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留来庭,地道東北人妒蔚。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肴盏。 傳聞我的和親對象是個殘疾皇子科盛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容