Java IO中的其他流的使用

本文主要介紹Java IO中的其他幾種流:

  • 標(biāo)準(zhǔn)輸入、輸出流
  • 打印流
  • 數(shù)據(jù)流
  • 對象流
  • 隨機(jī)存取文件流

標(biāo)準(zhǔn)輸入、輸出流

簡介

System.in:標(biāo)準(zhǔn)的輸入流庸推,默認(rèn)從鍵盤輸入蒜茴。

System.out:標(biāo)準(zhǔn)的輸出流,默認(rèn)從控制臺輸出疆栏。

主要方法

System類的setIn(InputStream is)方式重新指定輸入的流曾掂。

System類的setOut(PrintStream ps)方式重新指定輸出的流。

使用示例

從鍵盤輸入字符串壁顶,要求將讀取到的整行字符串轉(zhuǎn)成大寫輸出珠洗。然后繼續(xù)進(jìn)行輸入操作,直至當(dāng)輸入e或者exit時若专,退出程序许蓖。

設(shè)計(jì)思路

方法一:使用Scanner實(shí)現(xiàn),調(diào)用next()返回一個字符串调衰。

方法二:使用System.in實(shí)現(xiàn)膊爪。System.in ---> 轉(zhuǎn)換流 ---> BufferedReaderreadLine()

public class OtherStream {

    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            // System.in:為InputStream類型,讀取從鍵盤輸入的字符串嚎莉,使用轉(zhuǎn)換流
            InputStreamReader isr = new InputStreamReader(System.in);
            br = new BufferedReader(isr);

            while (true) {
                System.out.println("請輸入字符串:");
                String data = br.readLine();
                
                if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
                    System.out.println("程序結(jié)束");
                    break;
                }
                
                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

小練習(xí)

設(shè)計(jì)實(shí)現(xiàn)Scanner

public class MyInput {
    // 從鍵盤讀取字符串
    public static String readString() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 聲明并初始化字符串
        String string = "";

        // 從鍵盤獲取字符串
        try {
            string = br.readLine();

        } catch (IOException ex) {
            System.out.println(ex);
        }

        // 返回從鍵盤獲取的字符串
        return string;
    }

    // 從鍵盤讀取一個int值
    public static int readInt() {
        return Integer.parseInt(readString());
    }

    // 從鍵盤讀取double值
    public static double readDouble() {
        return Double.parseDouble(readString());
    }

    // 從鍵盤讀取byte值
    public static double readByte() {
        return Byte.parseByte(readString());
    }

    // 從鍵盤讀取short值
    public static double readShort() {
        return Short.parseShort(readString());
    }

    // 從鍵盤讀取long值
    public static double readLong() {
        return Long.parseLong(readString());
    }

    // 從鍵盤讀取float值
    public static double readFloat() {
        return Float.parseFloat(readString());
    }
}

打印流

PrintStreamPrintWriter說明:

  • 提供了一系列重載的print()println()方法米酬,用于多種數(shù)據(jù)類型的輸出
  • System.out返回的是PrintStream的實(shí)例
public class OtherStreamTest {
    // 打印流
    @Test
    public void test() {
        PrintStream ps = null;
        try {
            FileOutputStream fos = new FileOutputStream(new File("D:\\io\\hello.txt"));
            // 創(chuàng)建打印輸出流,設(shè)置為自動刷新模式(寫入換行符或字節(jié)‘\n’時都會花心緩沖區(qū))
            ps = new PrintStream(fos, true);
            if (ps != null) { // 把標(biāo)準(zhǔn)輸出流(控制臺輸出)改成輸出到文件
                System.setOut(ps);
            }

            for (int i = 0; i <= 255; i++) { // 輸出ASCII字符
                System.out.print((char) i);
                if (i % 50 == 0) { // 每50個數(shù)據(jù)一行
                    System.out.println(); // 換行
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }
}

數(shù)據(jù)流

DataInputStreamDataOutputStream 作用: 用于讀取或?qū)懗龌緮?shù)據(jù)類型的變量或字符串

示例代碼:

將內(nèi)存中的字符串趋箩、基本數(shù)據(jù)類型的變量寫出到文件中赃额。

@Test
public void test2() {
    DataOutputStream dos = null;
    try {
        // 1.創(chuàng)建對象
        dos = new DataOutputStream(new FileOutputStream("D:\\io\\data.txt"));

        // 2.數(shù)據(jù)輸出
        dos.writeUTF("Bruce");
        dos.flush();    // 刷新操作加派,將內(nèi)存的數(shù)據(jù)寫入到文件
        dos.writeInt(23);
        dos.flush();
        dos.writeBoolean(true);
        dos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 3.關(guān)閉流
        if (dos != null) {
            try {
                dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

將文件中存儲的基本數(shù)據(jù)類型變量和字符串讀取到內(nèi)存中,保存在變量中跳芳。

/*
注意點(diǎn):讀取不同類型的數(shù)據(jù)的順序要與當(dāng)初寫入文件時芍锦,保存的數(shù)據(jù)的順序一致!
 */
@Test
public void test3() {

    DataInputStream dis = null;
    try {
        // 1.創(chuàng)建對象
        dis = new DataInputStream(new FileInputStream("D:\\io\\data.txt"));
        // 2.從文件中讀入數(shù)據(jù)飞盆,讀取的順序要和當(dāng)初寫入時一致
        String name = dis.readUTF();
        int age = dis.readInt();
        boolean isMale = dis.readBoolean();
        System.out.println("name: " + name);
        System.out.println("age: " + age);
        System.out.println("isMale: " + isMale);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 3. 關(guān)閉資源
        if (dis != null) {
            try {
                dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

對象流

ObjectInputStreamObjectOutputStream

作用

  • ObjectOutputStream:內(nèi)存中的對象--->存儲中的文件娄琉、通過網(wǎng)絡(luò)傳輸出去:序列化過程。
  • ObjectInputStream:存儲中的文件吓歇、通過網(wǎng)絡(luò)接收過來 --->內(nèi)存中的對象:反序列化過程车胡。

對象的序列化

  • 對象序列化機(jī)制允許把內(nèi)存中的Java對象轉(zhuǎn)換成平臺無關(guān)的二進(jìn)制流,從而允許把這種二進(jìn)制流持久地保存在磁盤上,或通過網(wǎng)絡(luò)將這種二進(jìn)制流傳輸?shù)搅硪粋€網(wǎng)絡(luò)節(jié)點(diǎn)。當(dāng)其它程序獲取了這種二進(jìn)制流堡赔,就可以恢復(fù)成原來的Java對象魁袜。
  • 序列化的好處在于可將任何實(shí)現(xiàn)了Serializable接口的對象轉(zhuǎn)化為字節(jié)數(shù)據(jù),使其在保存和傳輸時可被還原。
  • 序列化是RMI(Remote Method Invoke-遠(yuǎn)程方法調(diào)用)過程的參數(shù)和返回值都必須實(shí)現(xiàn)的機(jī)制,RMI是JavaEE的基礎(chǔ)。因此序列化機(jī)制是JavaEE平臺的基礎(chǔ)簇搅。
  • 如果需要讓某個對象支持序列化機(jī)制,則必須讓對象所屬的類及其屬性是可序列化的软吐,為了讓某個類是可序列化的瘩将,該類必須實(shí)現(xiàn)如下兩個接口之一。否則凹耙,會拋出 NotserializableEXception異常
    • Serializable
    • Externalizable
  • 凡是實(shí)現(xiàn)Serializable接口的類都有一個表示序列化版本標(biāo)識符的靜態(tài)變量:
    • private static final long serialVersionUID;
    • serialVersionUID用來表明類的不同版本間的兼容性姿现。簡言之,其目的是以序列化對象進(jìn)行版本控制肖抱,有關(guān)各版本反序列化時是否兼容
    • 如果類沒有顯示定義這個靜態(tài)常量备典,它的值是Java運(yùn)行時環(huán)境根據(jù)類的內(nèi)部細(xì)節(jié)自動生成的。若類的實(shí)例變量做了修改意述,serialVersionUID可能發(fā)生變化提佣。故建議顯式聲明。
  • 簡單來說荤崇,Java的序列化機(jī)制是通過在運(yùn)行時判斷類的serialversionUID來驗(yàn)證版本一致性的拌屏。在進(jìn)行反序列化時,JVM會把傳來的字節(jié)流中的serialversionUID與本地相應(yīng)實(shí)體類的serialversionUID進(jìn)行比較术荤,如果相同就認(rèn)為是一致的倚喂,可以進(jìn)行反序列化,否則就會出現(xiàn)序列化版本不一致的異常喜每。(InvalidCastException)

實(shí)現(xiàn)序列化的對象所屬的類需要滿足

  1. 需要實(shí)現(xiàn)接口:Serializable(標(biāo)識接口)
  2. 當(dāng)前類提供一個全局常量:serialVersionUID(序列版本號)
  3. 除了當(dāng)前Person類需要實(shí)現(xiàn)Serializable接口之外务唐,還必須保證其內(nèi)部所屬性也必須是可序列化的雳攘。(默認(rèn)情況下带兜,基本數(shù)據(jù)類型可序列化)

補(bǔ)充:ObjectOutputStreamObjectInputStream不能序列化statictransient修飾的成員變量

對象流的使用

序列化代碼實(shí)現(xiàn)

要求被序列化對象必須實(shí)現(xiàn)序列化

@Test
public void test1() {
    ObjectOutputStream oos = null;
    try {
        // 1.創(chuàng)建對象枫笛,創(chuàng)建流
        oos = new ObjectOutputStream(new FileOutputStream("D:\\io\\object.dat"));

        // 2.操作流
        oos.writeObject(new String("億貧如洗王道長"));
        oos.flush(); // 刷新操作

        oos.writeObject(new Person("馮寶寶", 18));
        oos.flush();

        oos.writeObject(new Person("王也", 18));
        oos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 關(guān)閉流
        if (oos != null) {
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Person類:

public class Person implements Serializable { // 不實(shí)現(xiàn)Serializable接口不能序列化
    private static final long serialVersionUID = -7226360431328584153L;

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

反序列化代碼實(shí)現(xiàn)

@Test
public void test2() {
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("D:\\io\\object.dat"));
        Object obj = ois.readObject();
        String str = (String) obj;

        Person p1 = (Person) ois.readObject();
        Person p2 = (Person) ois.readObject();

        System.out.println(str);
        System.out.println(p1);
        System.out.println(p2);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (ois != null) {
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

任意存取文件流

RandomAccessFile的使用

簡介

  • RandomAccessFile直接繼承于java.lang.Object類,實(shí)現(xiàn)了DataInputDataOutput接口
  • RandomAccessFile既可以作為一個輸入流刚照,又可以作為一個輸出流
  • RandomAccessFile類支持“隨機(jī)訪問”的方式刑巧,程序可以直接跳到文件的任意地方來讀、寫文件
    • 支持只訪問文件的部分內(nèi)容
    • 可以向已存在的文件后追加內(nèi)容
  • RandomAccessFile對象包含一個記錄指針无畔,用以標(biāo)示當(dāng)前讀寫處的位置
  • RandomaccessFile類對象可以自由移動記錄指針:
    • long getFilePointer():獲取文件記錄指針的當(dāng)前位置
    • void seek(long pos):將文件記錄指針定位到pos位置

構(gòu)造器

public RandomAccessFile(File file,String mode)

public RandomAccessFile(String name,String mode)

使用說明

  1. 如果RandomAccessFile作為輸出流時啊楚,寫出到的文件如果不存在,則在執(zhí)行過程中自動創(chuàng)建浑彰。
  2. 如果寫出到的文件存在恭理,則會對原文件內(nèi)容進(jìn)行覆蓋。(默認(rèn)情況下郭变,從頭覆蓋)
  3. 可以通過相關(guān)的操作颜价,實(shí)現(xiàn)RandomAccessFile“插入”數(shù)據(jù)的效果。借助seek(int pos)方法
  4. 創(chuàng)建RandomAccessFile類實(shí)例需要指定一個mode參數(shù)诉濒,該參數(shù)指定RandomAccessFile的訪問模式:
    • r:以只讀方式打開
    • rw:打開以便讀取和寫入
    • rwd:打開以便讀取和寫入周伦;同步文件內(nèi)容的更新
    • rws:打開以便讀取和寫入;同步文件內(nèi)容和元數(shù)據(jù)的更新
  5. 如果模式為只讀r未荒,則不會創(chuàng)建文件专挪,而是會去讀取一個已經(jīng)存在的文件,讀取的文件不存在則會出現(xiàn)異常片排。如果模式為rw讀寫寨腔,文件不存在則會去創(chuàng)建文件,存在則不會創(chuàng)建率寡。

使用示例

文件的讀取和寫出操作

@Test
public void test1() {

    RandomAccessFile raf1 = null;
    RandomAccessFile raf2 = null;
    try {
        //1.創(chuàng)建對象脆侮,創(chuàng)建流
        raf1 = new RandomAccessFile(new File("test.jpg"),"r");
        raf2 = new RandomAccessFile(new File("test1.jpg"),"rw");
        //2.操作流
        byte[] buffer = new byte[1024];
        int len;
        while((len = raf1.read(buffer)) != -1){
            raf2.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.關(guān)閉流
        if(raf1 != null){
            try {
                raf1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if(raf2 != null){
            try {
                raf2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

使用RandomAccessFile實(shí)現(xiàn)數(shù)據(jù)的插入效果

@Test
public void test2() {
    RandomAccessFile raf1 = null;
    try {
        raf1 = new RandomAccessFile(new File("D:\\io\\hello.txt"), "rw");

        raf1.seek(3); // 將指針調(diào)到角標(biāo)為3的位置
        // 方式一:保存指針3后面的所有數(shù)據(jù)到StringBuilder中
        //            StringBuilder builder = new StringBuilder((int) new File("D:\\io\\hello.txt").length());
        //            byte[] buffer = new byte[1024];
        //            int len;
        //            while ((len = raf1.read(buffer)) != -1) {
        //                builder.append(new String(buffer, 0, len));
        //            }
        //            // 將指針調(diào)回角標(biāo)為3的位置
        //            raf1.seek(3);
        //            // 寫入"xyz"
        //            raf1.write("xyz".getBytes());
        //            // 從“xyz”的后面開始,將StringBuilder中的數(shù)據(jù)寫入到文件中去
        //            raf1.write(builder.toString().getBytes());

        // 方式二
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 內(nèi)部是一個數(shù)組勇劣,類似于StringBuilder
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            baos.write(buffer);
        }
        // 將指針調(diào)回角標(biāo)為3的位置
        raf1.seek(3);
        // 寫入"xyz"
        raf1.write("xyz".getBytes());
        // 從“xyz”的后面開始靖避,將baos中的數(shù)據(jù)寫入到文件中去
        raf1.write(baos.toString().getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (raf1 != null) {
            try {
                raf1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市比默,隨后出現(xiàn)的幾起案子幻捏,更是在濱河造成了極大的恐慌,老刑警劉巖命咐,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篡九,死亡現(xiàn)場離奇詭異,居然都是意外死亡醋奠,警方通過查閱死者的電腦和手機(jī)榛臼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門伊佃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沛善,你說我怎么就攤上這事航揉。” “怎么了金刁?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵帅涂,是天一觀的道長。 經(jīng)常有香客問我尤蛮,道長媳友,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任产捞,我火速辦了婚禮醇锚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坯临。我一直安慰自己焊唬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布尿扯。 她就那樣靜靜地躺著求晶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衷笋。 梳的紋絲不亂的頭發(fā)上芳杏,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音辟宗,去河邊找鬼爵赵。 笑死,一個胖子當(dāng)著我的面吹牛泊脐,可吹牛的內(nèi)容都是我干的空幻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼容客,長吁一口氣:“原來是場噩夢啊……” “哼秕铛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缩挑,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤但两,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后供置,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谨湘,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了紧阔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坊罢。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖擅耽,靈堂內(nèi)的尸體忽然破棺而出活孩,到底是詐尸還是另有隱情,我是刑警寧澤秫筏,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布诱鞠,位于F島的核電站挎挖,受9級特大地震影響这敬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕉朵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一崔涂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧始衅,春花似錦冷蚂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至诸老,卻和暖如春隆夯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背别伏。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工蹄衷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厘肮。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓愧口,卻偏偏與公主長得像,于是被迫代替她去往敵國和親类茂。 傳聞我的和親對象是個殘疾皇子耍属,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

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

  • File 類的使用 java.io.File 類:文件和文件目錄路徑的抽象表示形式,與平臺無關(guān) File 能新建巩检、...
    Edwinpanzzz閱讀 314評論 0 1
  • 1 IO(三)No20 1.1Properties 屬性集 【 Properties屬性集厚骗,主要用于操作配置屬...
    征程_Journey閱讀 894評論 0 1
  • Java IO(Input,Output) IO是我們的程序與外界交換數(shù)據(jù)的方式; Java提供一種能統(tǒng)一的標(biāo)準(zhǔn)方...
    頦傦銘心閱讀 514評論 0 1
  • IO流 1.File類的使用 1.1 是什么 文件和文件目錄路徑的抽象表示形式(與平臺無關(guān)) 1.2 特點(diǎn) Fil...
    controler閱讀 273評論 0 0
  • Java對數(shù)據(jù)的操作是通過流的方式,io是java中實(shí)現(xiàn)輸入輸出的基礎(chǔ)碴巾,它可以很方便的完成數(shù)據(jù)的輸入輸出操作溯捆,Ja...
    Java柱柱閱讀 258評論 0 0