I/O梳理

一详瑞、創(chuàng)建文件

File file = new File("D:/yunqingPojects/lol.txt");  // 可以用絕對(duì)路徑或者相對(duì)路徑創(chuàng)建
file.getParentFile().mkdirs();
file.createNewFile();

二、流 的概念

1.為什么需要流臣缀?
不同介質(zhì)之間數(shù)據(jù)交互蛤虐,比如讀取硬盤上文件到程序中
數(shù)據(jù)源可以是文件,數(shù)據(jù)庫(kù)肝陪,網(wǎng)絡(luò)甚至是其他的程序
2.輸入流or輸出流 - 默認(rèn)是站在程序的角度來(lái)說(shuō)來(lái)說(shuō)輸入輸出
e.g.從文件中讀數(shù)據(jù) 就是輸入流

三驳庭、ASCII碼 的概念

所有的數(shù)據(jù)存放在計(jì)算機(jī)中都是以數(shù)字的形式存放的。 所以字母就需要轉(zhuǎn)換為數(shù)字才能夠存放氯窍。
包含簡(jiǎn)單的英文字母饲常,符號(hào),數(shù)字等等狼讨。 不包含中文贝淤,德文,俄語(yǔ)等復(fù)雜的政供。

四播聪、字節(jié)流(InputStream,OutputStream)

InputStream,OutputStream都是抽象類;
FileInputStream 是InputStream子類;FileOutputStream 是OutputStream子類

  • 以字節(jié)流的形式讀取文件內(nèi)容(即 將文件數(shù)據(jù)讀取到 \color{red}{字節(jié)數(shù)組} 中):
try {
    //準(zhǔn)備文件lol.txt其中的內(nèi)容是AB,對(duì)應(yīng)的ASCII分別是65 66
    File f =new File("d:/lol.txt");
    //創(chuàng)建基于文件的輸入流
    FileInputStream fis =new FileInputStream(f);
    //創(chuàng)建字節(jié)數(shù)組布隔,其長(zhǎng)度就是文件的長(zhǎng)度
    byte[] all =new byte[(int) f.length()];
    //以字節(jié)流的形式讀取文件所有內(nèi)容
    fis.read(all);
    for (byte b : all) {
        //打印出來(lái)是65 66
        System.out.println(b);
    }   
    //每次使用完流离陶,都應(yīng)該進(jìn)行關(guān)閉
    fis.close();  
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
  • 以字節(jié)流的形式向文件寫入數(shù)據(jù)(即 通過(guò) \color{red}{字節(jié)數(shù)組} 的形式向文件寫數(shù)據(jù))::
try {
    // 準(zhǔn)備文件lol2.txt其中的內(nèi)容是空的
    File f = new File("d:/lol2.txt");
    // 準(zhǔn)備長(zhǎng)度是2的字節(jié)數(shù)組,用88,89初始化衅檀,其對(duì)應(yīng)的字符分別是X,Y
    byte data[] = { 88, 89 };
    // 創(chuàng)建基于文件的輸出流
    FileOutputStream fos = new FileOutputStream(f);
    // 把數(shù)據(jù)寫入到輸出流
    fos.write(data);
    // 關(guān)閉輸出流
    fos.close();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

五招刨、關(guān)閉流的方式

把流定義在try()里,try,catch或者finally結(jié)束的時(shí)候,會(huì)自動(dòng)關(guān)閉哀军。
JDK7之后沉眶,所有的流都實(shí)現(xiàn)了一個(gè)接口叫做 AutoCloseable打却,任何類實(shí)現(xiàn)了這個(gè)接口,都可以在try()中進(jìn)行實(shí)例化谎倔。 并且在try, catch, finally結(jié)束的時(shí)候自動(dòng)關(guān)閉柳击,回收相關(guān)資源。

public static void main(String[] args) {
    File f = new File("d:/lol.txt");
    //把流定義在try()里,try,catch或者finally結(jié)束的時(shí)候片习,會(huì)自動(dòng)關(guān)閉
    try (FileInputStream fis = new FileInputStream(f)) {
        byte[] all = new byte[(int) f.length()];
        fis.read(all);
        for (byte b : all) {
            System.out.println(b);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

六腻暮、字符流(Reader,Writer)

Reader,Writer都是抽象類
FileReader 是Reader子類,FileWriter 是Writer的子類

  • 使用字符流讀取文件(以 \color{red}{字符數(shù)組} 為基礎(chǔ))
public static void main(String[] args) {
    // 準(zhǔn)備文件lol.txt其中的內(nèi)容是AB
    File f = new File("d:/lol.txt");
    // 創(chuàng)建基于文件的Reader
    try (FileReader fr = new FileReader(f)) {
        // 創(chuàng)建字符數(shù)組毯侦,其長(zhǎng)度就是文件的長(zhǎng)度
        char[] all = new char[(int) f.length()];
        // 以字符流的形式讀取文件所有內(nèi)容
        fr.read(all);
        for (char b : all) {
            // 打印出來(lái)是A B
            System.out.println(b);
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
  • 使用字符流把數(shù)據(jù)寫入到文件(以 \color{red}{字符數(shù)組} 為基礎(chǔ))
public static void main(String[] args) {
    // 準(zhǔn)備文件lol2.txt
    File f = new File("d:/lol2.txt");
    // 創(chuàng)建基于文件的Writer
    try (FileWriter fr = new FileWriter(f)) {
        // 以字符流的形式把數(shù)據(jù)寫入到文件中
        String data="abcdefg1234567890";
        char[] cs = data.toCharArray();
        fr.write(cs);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

七哭靖、中文問(wèn)題

1.編碼概念:

  • 計(jì)算機(jī)上的所有的數(shù)據(jù)都是以數(shù)字的形式進(jìn)行存儲(chǔ)的。
    那么一個(gè)文件到底在硬盤上是由哪些數(shù)字組成的侈离,取決于用的什么編碼方式(可以理解為:文件中存儲(chǔ)的都是對(duì)應(yīng)棋盤的坐標(biāo))


    字符編碼的理解.png
  • 同一個(gè)字符在不同的坐標(biāo)體系中坐標(biāo)是不一樣的试幽,即在硬盤中的實(shí)際數(shù)值不一樣
    2.常見編碼方式
    工作后經(jīng)常接觸的編碼方式有如下幾種:
    ISO-8859-1 ASCII 數(shù)字和西歐字母
    GBK GB2312 BIG5 中文
    UNICODE (統(tǒng)一碼,萬(wàn)國(guó)碼)
    其中
    ISO-8859-1 包含 ASCII
    GB2312 是簡(jiǎn)體中文卦碾,BIG5是繁體中文铺坞,GBK同時(shí)包含簡(jiǎn)體和繁體以及日文。
    UNICODE 包括了所有的文字洲胖,無(wú)論中文济榨,英文,藏文绿映,法文擒滑,世界所有的文字都包含其中
    3.用 字節(jié)流 正確讀取中文
    為了能夠正確的讀取中文內(nèi)容
    1>. 必須了解文本是以哪種編碼方式保存字符的
    2>. 使用字節(jié)流讀取了文本后,再使用對(duì)應(yīng)的編碼方式去識(shí)別這些數(shù)字叉弦,得到正確的字符.
    如本例丐一,一個(gè)文件中的內(nèi)容是字符 \color{orange}{中},編碼方式是GBK淹冰,那么讀出來(lái)的數(shù)據(jù)一定是D6D0库车。
    再使用GBK編碼方式識(shí)別D6D0,就能正確的得到字符 \color{orange}{中}

public static void main(String[] args) {
        File f = new File("E:\\project\\j2se\\src\\test.txt");
        try (FileInputStream fis = new FileInputStream(f);) {
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            //文件中讀出來(lái)的數(shù)據(jù)是
            System.out.println("文件中讀出來(lái)的數(shù)據(jù)是:");
            for (byte b : all)
            {
                int i = b&0x000000ff;  //只取16進(jìn)制的后兩位
                System.out.println(Integer.toHexString(i));
            }
            System.out.println("把這個(gè)數(shù)字樱拴,放在GBK的棋盤上去:");
            String str = new String(all,"GBK");
            System.out.println(str);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

4.用 字符流 正確讀取中文
FileReader得到的是字符柠衍,所以一定是已經(jīng)把字節(jié) \color{orange}{根據(jù)某種編碼識(shí)別成字符}
而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統(tǒng)晶乔,就是GBK
FileReader是不能手動(dòng)設(shè)置編碼方式的珍坊,為了使用其他的編碼方式,只能使用InputStreamReader來(lái)代替瘪弓,像這樣:

new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 

在本例中垫蛆,用記事本另存為UTF-8格式,然后用UTF-8就能識(shí)別對(duì)應(yīng)的中文了腺怯。

public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
        File f = new File("E:\\project\\j2se\\src\\test.txt"); // 此處文件是以UTF8 的編碼方式存儲(chǔ)的一個(gè) "中"字
        //FileReader是不能手動(dòng)設(shè)置編碼方式的袱饭,為了使用其他的編碼方式,只能使用InputStreamReader來(lái)代替
        //并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 這樣的形式
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
            char[] cs = new char[(int) f.length()];
            isr.read(cs);
            System.out.printf("InputStreamReader 指定編碼方式UTF-8,識(shí)別出來(lái)的字符是:%n");
            System.out.println(new String(cs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }     
    }

八呛占、緩存流

  1. 為什么出現(xiàn)了緩存流(BufferedReader,PrintWriter)
  • 字符流 和 字節(jié)流 每一次讀寫的時(shí)候 都會(huì)訪問(wèn)硬盤虑乖,性能不佳
  • 緩存流 在讀取的時(shí)候,會(huì)一次性讀較多的數(shù)據(jù)到緩存中晾虑,以后每一次的讀取疹味,都是在緩存中訪問(wèn),直到緩存中的數(shù)據(jù)讀取完畢帜篇,再到硬盤中讀炔谵唷;
    緩存流 在寫入數(shù)據(jù)的時(shí)候笙隙,會(huì)先把數(shù)據(jù)寫入到緩存區(qū)洪灯,直到緩存區(qū)達(dá)到一定的量,才把這些數(shù)據(jù)一起寫入到硬盤中去竟痰。按照這種操作模式签钩,就不會(huì)像字節(jié)流,字符流那樣每寫一個(gè)字節(jié)都訪問(wèn)硬盤坏快,從而減少了IO操作
  • 就好比吃飯铅檩,不用緩存就是\color{orange}{每吃一口都到鍋里去鏟}。用緩存就是\color{orange}{先把飯盛到碗里莽鸿,碗里的吃完了昧旨,再到鍋里去鏟}
  • 緩存流必須建立在一個(gè)存在的流的基礎(chǔ)上

2.使用緩存流寫入數(shù)據(jù)
PrintWriter 緩存字符輸出流, 可以一次寫出一行數(shù)據(jù)
API:pw.println()

public void testCacheStrem(){
        // 向文件lol3.txt中寫入三行語(yǔ)句
        File f = new File("D:/pojects/lol3.txt");
        try (FileWriter fw = new FileWriter(f);PrintWriter pw = new PrintWriter(fw)) {
            pw.println("garen kill teemo");
            pw.println("teemo revive after 1 minutes");
            pw.println("teemo try to garen, but killed again");
        }catch (IOException e){
            e.printStackTrace();
        }
    }

3.使用緩存流讀取數(shù)據(jù)
BufferedReader 緩存字符輸入流祥得,可以一次讀取一行數(shù)據(jù)
br.readLine()

public void testCacheStremRead(){
        // 從文件lol3.txt中寫入三行語(yǔ)句
        File f = new File("D:/pojects/lol3.txt");
        try (FileReader fr = new FileReader(f);BufferedReader br = new BufferedReader(fr)) {
            while (true){
                String line = br.readLine();
                if (line == null) break;
                System.out.println(line);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
  1. 強(qiáng)制寫入硬盤 flush()
    有的時(shí)候臼予,需要立即把數(shù)據(jù)寫入到硬盤,而不是等緩存滿了才寫出去啃沪。 這時(shí)候就需要用到flush
public static void main(String[] args) {
        //向文件lol2.txt中寫入三行語(yǔ)句
        File f =new File("d:/lol2.txt");
        //創(chuàng)建文件字符流
        //緩存流必須建立在一個(gè)存在的流的基礎(chǔ)上
        try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
            pw.println("garen kill teemo");
            //強(qiáng)制把緩存中的數(shù)據(jù)寫入硬盤粘拾,無(wú)論緩存是否已滿
                pw.flush();           
            pw.println("teemo revive after 1 minutes");
                pw.flush();
            pw.println("teemo try to garen, but killed again");
                pw.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
} 

九、數(shù)據(jù)流(DataInputStream,DataOutputStream)

1.What for
如果向文件中先后寫入一個(gè)浮點(diǎn)數(shù)11.3 和一個(gè)整數(shù)38创千,那么文件中的內(nèi)容為11.338缰雇,
需要自己添加特殊字符進(jìn)行在寫入的時(shí)候插入才能在讀取的時(shí)候判別第一次寫的浮點(diǎn)數(shù)和第二次寫的整數(shù)。
數(shù)據(jù)流幫我們進(jìn)行了維護(hù)追驴。
2.用數(shù)據(jù)流直接進(jìn)行數(shù)字的讀寫

public void testDataStream(){
        // 向文件中順序?qū)懭雰蓚€(gè)數(shù)字械哟,然后順序讀出
        write();
        read();
    }
    public void write(){
        File f = new File("D:/yunqingPojects/lol3.txt");
        try (FileOutputStream fos = new FileOutputStream(f);DataOutputStream dos = new DataOutputStream(fos)) {
            dos.writeFloat(11.2f);
            dos.writeInt(30);
        }catch (IOException e){

        }
    }
    public void read(){
        File f = new File("D:/yunqingPojects/lol3.txt");
        try (FileInputStream fis = new FileInputStream(f);DataInputStream dis = new DataInputStream(fis)) {
            float num1 = dis.readFloat();
            int num2 = dis.readInt();
            System.out.println(num1);
            System.out.println(num2);
        }catch (IOException e){

        }
    }

十、對(duì)象流( ObjectInputStream,ObjectOutputStream)

對(duì)象流指的是可以直接把一個(gè) \color{orange}{對(duì)象以流的形式傳輸}給其他的介質(zhì)殿雪,比如硬盤 暇咆。
一個(gè)對(duì)象以流的形式進(jìn)行傳輸叫做\color{orange}{序列化}。 該對(duì)象所對(duì)應(yīng)的類,必須是實(shí)現(xiàn)Serializable接口爸业。
2.API:

oos.writeObject(h); // 將對(duì)象寫入文件
Hero h2 = (Hero) ois.readObject();  // 將對(duì)象從文件讀出

2.例子
創(chuàng)建一個(gè)Hero對(duì)象其骄,設(shè)置其名稱為garen。
把該對(duì)象序列化到一個(gè)文件garen.lol扯旷。然后再通過(guò)序列化把該文件轉(zhuǎn)換為一個(gè)Hero對(duì)象

public void testObjStream(){
    Hero hero = new Hero();
    hero.name = "gareen";
    hero.hp = 616;

    File f = new File("D:/yunqingPojects/lol4.txt");
    try (
            // 創(chuàng)建對(duì)象輸出流
            FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos);
            //創(chuàng)建對(duì)象輸入流
            FileInputStream fis = new FileInputStream(f);ObjectInputStream ois = new ObjectInputStream(fis)) {

            oos.writeObject(hero);
            Hero h = (Hero) ois.readObject();

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

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

十一拯爽、控制臺(tái)輸入流(System.in,Scanner)

1.System.in

public static void main(String[] args) {
    // 控制臺(tái)輸入
    try (InputStream is = System.in;) {
        while (true) {
            // 敲入a,然后敲回車可以看到
            // 97 13 10
            // 97是a的ASCII碼
            // 13 10分別對(duì)應(yīng)回車換行
            int i = is.read();
            System.out.println(i);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
 }

2.Scanner讀取字符串(sc..nextLine())
使用System.in.read雖然可以讀取數(shù)據(jù)钧忽,但是很不方便,
使用Scanner就可以逐行讀取了

public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    while(true){
        String line = s.nextLine();
        System.out.println(line);
     }
}

3.Scanner從控制臺(tái)讀取整數(shù)(sc.nextInt())

public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    int a = s.nextInt();
    System.out.println("第一個(gè)整數(shù):"+a);
    int b = s.nextInt();
    System.out.println("第二個(gè)整數(shù):"+b);
}

十二毯炮、流關(guān)系圖

StreamRelationship.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耸黑,隨后出現(xiàn)的幾起案子桃煎,更是在濱河造成了極大的恐慌,老刑警劉巖大刊,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件为迈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡奈揍,警方通過(guò)查閱死者的電腦和手機(jī)曲尸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)男翰,“玉大人另患,你說(shuō)我怎么就攤上這事《暌铮” “怎么了昆箕?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)租冠。 經(jīng)常有香客問(wèn)我鹏倘,道長(zhǎng),這世上最難降的妖魔是什么顽爹? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任纤泵,我火速辦了婚禮,結(jié)果婚禮上镜粤,老公的妹妹穿的比我還像新娘捏题。我一直安慰自己,他們只是感情好肉渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布公荧。 她就那樣靜靜地躺著,像睡著了一般同规。 火紅的嫁衣襯著肌膚如雪循狰。 梳的紋絲不亂的頭發(fā)上窟社,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音绪钥,去河邊找鬼灿里。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昧识,可吹牛的內(nèi)容都是我干的钠四。 我是一名探鬼主播盗扒,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼跪楞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了侣灶?” 一聲冷哼從身側(cè)響起甸祭,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎褥影,沒(méi)想到半個(gè)月后池户,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凡怎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年校焦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片统倒。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寨典,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出房匆,到底是詐尸還是另有隱情耸成,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布浴鸿,位于F島的核電站井氢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岳链。R本人自食惡果不足惜花竞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掸哑。 院中可真熱鬧约急,春花似錦、人聲如沸举户。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)俭嘁。三九已至躺枕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拐云。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工罢猪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叉瘩。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓膳帕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親薇缅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子危彩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

  • 查爾斯.史考勃說(shuō)真正值錢的是不花一文錢的微笑。每個(gè)人對(duì)其都有獨(dú)一無(wú)二的表達(dá)泳桦,無(wú)法復(fù)制汤徽。微笑源自于心中不斷涌...
    小靜漫雨溪閱讀 646評(píng)論 6 50
  • 晨光是藏在薄霧里的一縷沙 河流是你柔軟的肩膀 輕輕托起一座城 鋼筋混凝土框架的橋梁 嘈雜呼嘯的大風(fēng) 是落寞老人的背...
    念今塵閱讀 798評(píng)論 0 50