Java學(xué)習(xí)總結(jié)之Java IO系統(tǒng)(一)

概述

java.io 包幾乎包含了所有操作輸入富稻、輸出需要的類。所有這些流類代表了輸入源和輸出目標(biāo)猪狈。java.io 包中的流支持很多種格式,比如:基本類型辩恼、對(duì)象罪裹、本地化字符集等等。一個(gè)流可以理解為一個(gè)數(shù)據(jù)的序列运挫。輸入流表示從一個(gè)源讀取數(shù)據(jù)状共,輸出流表示向一個(gè)目標(biāo)寫數(shù)據(jù)。Java 為 I/O 提供了強(qiáng)大的而靈活的支持谁帕,使其更廣泛地應(yīng)用到文件傳輸和網(wǎng)絡(luò)編程中峡继。

Java 的 I/O 大概可以分成以下幾類:

  • 磁盤操作:File
  • 字節(jié)操作:InputStream 和 OutputStream
  • 字符操作:Reader 和 Writer
  • 對(duì)象操作:Serializable
  • 網(wǎng)絡(luò)操作:Socket
  • 新的輸入/輸出:NIO

File

Java中IO操作有相應(yīng)步驟,以文件操作為例匈挖,主要操作流程如下:
1.使用File類打開一個(gè)文件
2.通過字節(jié)流或字符流的子類碾牌,指定輸出的位置
3.進(jìn)行讀/寫操作
4.關(guān)閉輸入/輸出

那么我們先來介紹一下File類
Java文件類在java.io包中,它以抽象的方式代表文件名和目錄路徑名儡循。該類主要用于獲取文件和目錄的屬性舶吗,文件和目錄的創(chuàng)建、查找择膝、刪除誓琼、重命名等,但不能進(jìn)行文件的讀寫操作
File對(duì)象代表磁盤中實(shí)際存在的文件和目錄。通過以下構(gòu)造方法創(chuàng)建一個(gè)File對(duì)象腹侣。

通過給定的父抽象路徑名子路徑名字符串創(chuàng)建一個(gè)新的File實(shí)例叔收。
File(File parent, String child)

通過將給定路徑名字符串轉(zhuǎn)換成抽象路徑名來創(chuàng)建一個(gè)新 File 實(shí)例。
File(String pathname)

根據(jù) parent 路徑名字符串和 child 路徑名字符串創(chuàng)建一個(gè)新 File 實(shí)例傲隶。
File(String parent, String child)

通過將給定的 file: URI 轉(zhuǎn)換成一個(gè)抽象路徑名來創(chuàng)建一個(gè)新的 File 實(shí)例饺律。
File(URI uri)

注意:
1.在各個(gè)操作系統(tǒng)中,路徑的分隔符是不一樣的跺株,例如:Windows中使用反斜杠:"\"复濒,Linux|Unix中使用正斜杠:"/"。在使用反斜杠時(shí)要寫成"\\"的形式乒省,因?yàn)榉葱备芤M(jìn)行轉(zhuǎn)義芝薇。如果要讓Java保持可移植性,應(yīng)該使用File類的靜態(tài)常量File.pathSeparator作儿。
2.構(gòu)建一個(gè)File實(shí)例并不會(huì)在機(jī)器上創(chuàng)建一個(gè)文件。不管文件是否存在馋劈,都可以創(chuàng)建任意文件名的File實(shí)例攻锰。可以調(diào)用File實(shí)例上的exists()方法來判斷這個(gè)文件是否存在妓雾。通過后續(xù)的學(xué)習(xí)我們會(huì)知道娶吞,當(dāng)把一個(gè)輸出流綁定到一個(gè)不存在的File實(shí)例上時(shí),會(huì)自動(dòng)在機(jī)器上創(chuàng)建該文件械姻,如果文件已經(jīng)存在妒蛇,把輸出流綁定到該文件上則會(huì)覆蓋該文件,但這些都不是在創(chuàng)建File實(shí)例時(shí)進(jìn)行的楷拳。

創(chuàng)建File對(duì)象成功后绣夺,可以使用以下列表中的方法操作文件。

File1.png

File2.png
File3.png
File4.png

下面給出一個(gè)使用File類的實(shí)例:

import java.io.File;
public class DirList {
   public static void main(String args[]) {
      String dirname = "/java";
      File f1 = new File(dirname);
      if (f1.isDirectory()) {
         System.out.println( "Directory of " + dirname);
         String s[] = f1.list();
         for (int i=0; i < s.length; i++) {
            File f = new File(dirname + "/" + s[i]);
            if (f.isDirectory()) {
               System.out.println(s[i] + " is a directory");
            } else {
               System.out.println(s[i] + " is a file");
            }
         }
      } else {
         System.out.println(dirname + " is not a directory");
    }
  }
}

小貼士:lastModified()方法返回的是從時(shí)間戳(1970年1月1日0時(shí)0分0秒)到當(dāng)前的毫秒數(shù)欢揖,返回值類型是long陶耍,可以用Date類對(duì)它進(jìn)行包裝使其更易讀。

Java中的目錄

創(chuàng)建目錄:
File類中有兩個(gè)方法可以用來創(chuàng)建文件夾:

  • mkdir( )方法創(chuàng)建一個(gè)文件夾她混,成功則返回true烈钞,失敗則返回false。失敗表明File對(duì)象指定的路徑已經(jīng)存在坤按,或者由于整個(gè)路徑還不存在毯欣,該文件夾不能被創(chuàng)建。
  • mkdirs()方法創(chuàng)建一個(gè)文件夾和它的所有父文件夾臭脓。
    下面的例子創(chuàng)建 "/tmp/user/java/bin"文件夾:
import java.io.File;
 
public class CreateDir {
  public static void main(String args[]) {
    String dirname = "/tmp/user/java/bin";
    File d = new File(dirname);
    // 現(xiàn)在創(chuàng)建目錄
    d.mkdirs();
  }
}

mkdirs是遞歸創(chuàng)建文件夾酗钞,允許在創(chuàng)建某文件夾時(shí)其父文件夾不存在,從而一同創(chuàng)建;mkdir必須滿足路徑上的父文件夾全都存在
注意: Java 在 UNIX 和 Windows 自動(dòng)按約定分辨文件路徑分隔符。如果你在 Windows 版本的 Java 中使用分隔符 (/) ,路徑依然能夠被正確解析算吩。
讀取目錄:
一個(gè)目錄其實(shí)就是一個(gè) File 對(duì)象留凭,它包含其他文件和文件夾。
如果創(chuàng)建一個(gè) File 對(duì)象并且它是一個(gè)目錄偎巢,那么調(diào)用 isDirectory() 方法會(huì)返回 true蔼夜。
可以通過調(diào)用該對(duì)象上的 list() 方法,來提取它包含的文件和文件夾的列表压昼。
下面展示的例子說明如何使用 list() 方法來檢查一個(gè)文件夾中包含的內(nèi)容:

import java.io.File;
 
public class DirList {
  public static void main(String args[]) {
    String dirname = "/tmp";
    File f1 = new File(dirname);
    if (f1.isDirectory()) {
      System.out.println( "目錄 " + dirname);
      String s[] = f1.list();
      for (int i=0; i < s.length; i++) {
        File f = new File(dirname + "/" + s[i]);
        if (f.isDirectory()) {
          System.out.println(s[i] + " 是一個(gè)目錄");
        } else {
          System.out.println(s[i] + " 是一個(gè)文件");
        }
      }
    } else {
      System.out.println(dirname + " 不是一個(gè)目錄");
    }
  }
}

刪除目錄或文件:
刪除文件可以使用 java.io.File.delete() 方法求冷。
以下代碼會(huì)刪除目錄/tmp/java/,即便目錄不為空窍霞。
測(cè)試目錄結(jié)構(gòu):

/tmp/java/
|-- 1.log
|-- test

deleteFolder是一個(gè)遞歸函數(shù)匠题,類似于DFS思想

import java.io.File;
 
public class DeleteFileDemo {
  public static void main(String args[]) {
      // 這里修改為自己的測(cè)試目錄
    File folder = new File("/tmp/java/");
    deleteFolder(folder);
  }
 
  //刪除文件及目錄
  public static void deleteFolder(File folder) {
    File[] files = folder.listFiles();
        if(files!=null) { 
            for(File f: files) {
                if(f.isDirectory()) {
                    deleteFolder(f);
                } else {
                    f.delete();
                }
            }
        }
        folder.delete();
    }
}

RandomAccessFile

RandomAccessFile不同于File,它提供了對(duì)文件內(nèi)容的訪問但金,可以讀寫文件且支持隨機(jī)訪問文件的任意位置韭山。
RandomAccessFile讀寫用到文件指針,它的初始位置為0,可以用getFilePointer()方法獲取文件指針的位置冷溃。下面是RandomAccessFile常用的方法钱磅。

RandomAccessFile.png

public int read(int x) throws IOException 方法只讀取一個(gè)字節(jié),也就是x的低八位似枕。


import java.io.File ;
import java.io.RandomAccessFile ;
public class RandomAccessFileDemo01{
    // 所有的異常直接拋出盖淡,程序中不再進(jìn)行處理
    public static void main(String args[]) throws Exception{
        File f = new File("d:" + File.separator + "test.txt") ; // 指定要操作的文件
        RandomAccessFile rdf = null ;       // 聲明RandomAccessFile類的對(duì)象
        rdf = new RandomAccessFile(f,"rw") ;// 讀寫模式,如果文件不存在凿歼,會(huì)自動(dòng)創(chuàng)建
        String name = null ;
        int age = 0 ;
        name = "zhangsan" ;         // 字符串長度為8
        age = 30 ;                  // 數(shù)字的長度為4
        rdf.writeBytes(name) ;      // 將姓名寫入文件之中
        rdf.writeInt(age) ;         // 將年齡寫入文件之中
        name = "lisi    " ;         // 字符串長度為8
        age = 31 ;                  // 數(shù)字的長度為4
        rdf.writeBytes(name) ;      // 將姓名寫入文件之中
        rdf.writeInt(age) ;         // 將年齡寫入文件之中
        name = "wangwu  " ;         // 字符串長度為8
        age = 32 ;                  // 數(shù)字的長度為4
        rdf.writeBytes(name) ;      // 將姓名寫入文件之中
        rdf.writeInt(age) ;         // 將年齡寫入文件之中
        rdf.close() ;               // 關(guān)閉
    }
};

寫完之后褪迟,開始讀取數(shù)據(jù)。寫的時(shí)候可以將一個(gè)字符串寫入答憔,讀的時(shí)候需要一個(gè)個(gè)的以字節(jié)的形式讀取出來味赃。


import java.io.File ;
import java.io.RandomAccessFile ;
public class RandomAccessFileDemo02{
    // 所有的異常直接拋出,程序中不再進(jìn)行處理
    public static void main(String args[]) throws Exception{
        File f = new File("d:" + File.separator + "test.txt") ; // 指定要操作的文件
        RandomAccessFile rdf = null ;       // 聲明RandomAccessFile類的對(duì)象
        rdf = new RandomAccessFile(f,"r") ;// 以只讀的方式打開文件
        String name = null ;
        int age = 0 ;
        byte b[] = new byte[8] ;    // 開辟byte數(shù)組
        // 讀取第二個(gè)人的信息虐拓,意味著要空出第一個(gè)人的信息
        rdf.skipBytes(12) ;     // 跳過第一個(gè)人的信息
        for(int i=0;i<b.length;i++){
            b[i] = rdf.readByte() ; // 讀取一個(gè)字節(jié)
        }
        name = new String(b) ;  // 將讀取出來的byte數(shù)組變?yōu)樽址?        age = rdf.readInt() ;   // 讀取數(shù)字
        System.out.println("第二個(gè)人的信息 --> 姓名:" + name + "洁桌;年齡:" + age) ;
        // 讀取第一個(gè)人的信息
        rdf.seek(0) ;   // 指針回到文件的開頭
        for(int i=0;i<b.length;i++){
            b[i] = rdf.readByte() ; // 讀取一個(gè)字節(jié)
        }
        name = new String(b) ;  // 將讀取出來的byte數(shù)組變?yōu)樽址?        age = rdf.readInt() ;   // 讀取數(shù)字
        System.out.println("第一個(gè)人的信息 --> 姓名:" + name + ";年齡:" + age) ;
        rdf.skipBytes(12) ; // 跳過第二個(gè)人的信息
        for(int i=0;i<b.length;i++){
            b[i] = rdf.readByte() ; // 讀取一個(gè)字節(jié)
        }
        name = new String(b) ;  // 將讀取出來的byte數(shù)組變?yōu)樽址?        age = rdf.readInt() ;   // 讀取數(shù)字
        System.out.println("第三個(gè)人的信息 --> 姓名:" + name + "侯嘀;年齡:" + age) ;
        rdf.close() ;               // 關(guān)閉
    }
};

結(jié)果如下:

result.png

在Java程序中所有的數(shù)據(jù)都是以的方式進(jìn)行傳輸或保存的另凌,程序需要數(shù)據(jù)的時(shí)候要使用輸入流讀取數(shù)據(jù),而當(dāng)程序需要將一些數(shù)據(jù)保存起來的時(shí)候戒幔,就要使用輸出流完成吠谢。程序中的輸入輸出都是以流的形式保存的,流中保存的實(shí)際上全都是字節(jié)文件诗茎。流涉及的領(lǐng)域很廣:標(biāo)準(zhǔn)輸入輸出工坊,文件的操作献汗,網(wǎng)絡(luò)上的數(shù)據(jù)流,字符串流王污,對(duì)象流罢吃,zip文件流等等。

Stream.png

流具有方向性昭齐,至于是輸入流還是輸出流則是一個(gè)相對(duì)的概念尿招,一般以程序?yàn)閰⒖迹绻麛?shù)據(jù)的流向是程序至設(shè)備阱驾,我們成為輸出流就谜,反之我們稱為輸入流。
可以將流想象成一個(gè)“水流管道”里覆,水流就在這管道中形成了丧荐,自然就出現(xiàn)了方向的概念。

Information.jpg

先上一個(gè)Java IO流類層次圖喧枷,如前所述虹统,一個(gè)流被定義為一個(gè)數(shù)據(jù)序列。輸入流用于從源讀取數(shù)據(jù)隧甚,輸出流用于向目標(biāo)寫數(shù)據(jù):

JavaIO流類層次圖.png

是不是被嚇到了车荔?沒關(guān)系,我們將通過一個(gè)個(gè)例子來學(xué)習(xí)這些功能呻逆。

IO流分類

1.按操作數(shù)據(jù)類型分:字符流和字節(jié)流

編碼與解碼:編碼就是把字符轉(zhuǎn)換為字節(jié),而解碼是把字節(jié)重新組合成字符菩帝。
如果編碼和解碼過程使用不同的編碼方式那么就出現(xiàn)了亂碼咖城。

  • GBK 編碼中,中文字符占 2 個(gè)字節(jié)呼奢,英文字符占 1 個(gè)字節(jié)宜雀;
  • UTF-8 編碼中,中文字符占 3 個(gè)字節(jié)握础,英文字符占 1 個(gè)字節(jié)辐董;
  • UTF-16be 編碼中,中文字符和英文字符都占 2 個(gè)字節(jié)禀综。

UTF-16be 中的 be 指的是 Big Endian简烘,也就是大端。相應(yīng)地也有 UTF-16le定枷,le 指的是 Little Endian孤澎,也就是小端。
Java 使用雙字節(jié)編碼 UTF-16be欠窒,這不是指 Java 只支持這一種編碼方式覆旭,而是說 char 這種類型使用 UTF-16be 進(jìn)行編碼。char 類型占 16 位,也就是兩個(gè)字節(jié)型将,Java 使用這種雙字節(jié)編碼是為了讓一個(gè)中文或者一個(gè)英文都能使用一個(gè) char 來存儲(chǔ)寂祥。

字符流:Java中的字符流處理的最基本的單元是2字節(jié)的Unicode碼元(char),它通常用來處理文本數(shù)據(jù)七兜,如字符丸凭、字符數(shù)組或字符串等。所謂Unicode碼元惊搏,也就是一個(gè)Unicode代碼單元贮乳,范圍是0x0000~0xFFFF。在以上范圍內(nèi)的每個(gè)數(shù)字都與一個(gè)字符相對(duì)應(yīng)恬惯,Java中的String類型默認(rèn)就把字符以Unicode規(guī)則編碼而后存儲(chǔ)在內(nèi)存中向拆。然而與存儲(chǔ)在內(nèi)存中不同,存儲(chǔ)在磁盤上的數(shù)據(jù)通常有著各種各樣的編碼方式酪耳。使用不同的編碼方式浓恳,相同的字符會(huì)有不同的二進(jìn)制表示。實(shí)際上字符流是這樣工作的:

  • 輸出字符流:把要寫入文件的字符序列(實(shí)際上是Unicode碼元序列)轉(zhuǎn)為指定編碼方式下的字節(jié)序列碗暗,然后再寫入到文件中颈将。
  • 輸入字符流:把要讀取的字節(jié)序列按指定編碼方式解碼為相應(yīng)字符序列(實(shí)際上是Unicode碼元序列從)從而可以存在內(nèi)存中。

也就是說言疗,所有的文件在硬盤或在傳輸時(shí)都是以字節(jié)的方式進(jìn)行的晴圾,包括圖片等都是按字節(jié)的方式存儲(chǔ)的,而字符是只有在內(nèi)存中才會(huì)形成噪奄。

字節(jié)流:Java中的字節(jié)流處理的最基本單位為單個(gè)字節(jié)(byte)死姚,它通常用來處理二進(jìn)制數(shù)據(jù),如果要得到字節(jié)對(duì)應(yīng)的字符需要強(qiáng)制類型轉(zhuǎn)換。

兩者比較:
1.字符流是由Java虛擬機(jī)將字節(jié)轉(zhuǎn)化為2個(gè)字節(jié)的Unicode字符為單位的字符而成的勤篮,所以它對(duì)多國語言支持性較好都毒,如果要操作中文數(shù)據(jù)等,用字符流碰缔。
2.字符流只用來處理文本數(shù)據(jù)账劲,字節(jié)流還可以用來處理媒體數(shù)據(jù),如視頻金抡、音頻瀑焦、圖片等。
3.字符流的兩個(gè)抽象基類為Reader和Writer梗肝,字節(jié)流的兩個(gè)抽象基類為InputStream和OutputStream蝠猬。它們的具體子類名以基類名為后綴進(jìn)行擴(kuò)展。
4.字節(jié)流在操作的時(shí)候不會(huì)用到緩沖區(qū)(內(nèi)存)统捶,是直接對(duì)文件本身操作的榆芦,而字符流在操作的時(shí)候使用緩沖區(qū)柄粹。

Compare.jpg

以向一個(gè)文件輸出"Hello world!"為例,我們分別使用字節(jié)流和字符流進(jìn)行輸出匆绣,且在使用完之后都不關(guān)閉流驻右。

使用字節(jié)流不關(guān)閉執(zhí)行:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


public class IOPractice {

    public static void main(String[] args) throws IOException {
        // 第1步:使用File類找到一個(gè)文件    
             File f = new File("/home/xiejunyu/"+
             "桌面/text.txt");   
        // 第2步:通過子類實(shí)例化父類對(duì)象     
             OutputStream out = new FileOutputStream(f); 
        // 通過對(duì)象多態(tài)性進(jìn)行實(shí)例化    
        // 第3步:進(jìn)行寫操作    
             String str = "Hello World!";      
        // 準(zhǔn)備一個(gè)字符串    
             byte b[] = str.getBytes();          
        // 字符串轉(zhuǎn)byte數(shù)組    
             out.write(b);                      
        // 將內(nèi)容輸出    
         // 第4步:關(guān)閉輸出流    
            // out.close();                  
        // 此時(shí)沒有關(guān)閉    
                }    
}
1.png

此時(shí)沒有關(guān)閉字節(jié)流操作,但是文件中也依然存在了輸出的內(nèi)容崎淳,證明字節(jié)流是直接操作文件本身的堪夭。

使用字符流不關(guān)閉執(zhí)行:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;


public class IOPractice {

    public static void main(String[] args) throws IOException {
         // 第1步:使用File類找到一個(gè)文件    
        File f = new File("/home/xiejunyu/桌面/test.txt");
        // 第2步:通過子類實(shí)例化父類對(duì)象            
        Writer  out = new FileWriter(f);            
        // 第3步:進(jìn)行寫操作    
        String str = "Hello World!";      
        // 準(zhǔn)備一個(gè)字符串    
        out.write(str);                    
        // 將內(nèi)容輸出    
        // 第4步:關(guān)閉輸出流    
        // out.close();
        // 此時(shí)沒有關(guān)閉    
    }    
}
2.png

程序運(yùn)行后會(huì)發(fā)現(xiàn)文件中沒有任何內(nèi)容,這是因?yàn)樽址鞑僮鲿r(shí)使用了緩沖區(qū)拣凹,而在關(guān)閉字符流時(shí)會(huì)強(qiáng)制性地將緩沖區(qū)中的內(nèi)容進(jìn)行輸出森爽,但是如果程序沒有關(guān)閉字符流,緩沖區(qū)中的內(nèi)容是無法輸出的嚣镜,所以得出結(jié)論:字符流使用了緩沖區(qū)爬迟,而字節(jié)流沒有使用緩沖區(qū)。如果想讓緩沖區(qū)中的內(nèi)容輸出菊匿,要么關(guān)閉流強(qiáng)制刷新緩沖區(qū)付呕,要么調(diào)用flush方法沖刷緩沖區(qū)〉Γ可以簡(jiǎn)單地把緩沖區(qū)理解為一段特殊的內(nèi)存徽职。某些情況下,如果一個(gè)程序頻繁地操作一個(gè)資源(如文件或數(shù)據(jù)庫)佩厚,則性能會(huì)很低姆钉,此時(shí)為了提升性能,就可以將一部分?jǐn)?shù)據(jù)暫時(shí)讀入到內(nèi)存的一塊區(qū)域之中抄瓦,以后直接從此區(qū)域中讀取數(shù)據(jù)即可潮瓶,因?yàn)樽x取內(nèi)存速度會(huì)比較快,這樣可以提升程序的性能闺鲸。
在字符流的操作中筋讨,所有的字符都是在內(nèi)存中形成的埃叭,在輸出前會(huì)將所有的內(nèi)容暫時(shí)保存在內(nèi)存之中摸恍,所以使用了緩沖區(qū)暫存數(shù)據(jù)。

建議:
1.雖然不關(guān)閉字節(jié)流不影響數(shù)據(jù)的輸出赤屋,且后續(xù)JVM會(huì)自動(dòng)回收這部分內(nèi)存立镶,但還是建議在使用完任何流對(duì)象之后關(guān)閉流。
2.使用流對(duì)象都要聲明或拋出IOException
3.在創(chuàng)建一個(gè)文件時(shí)类早,如果目錄下有同名文件將被覆蓋
4.在寫文件時(shí)媚媒,如果文件不存在,會(huì)在創(chuàng)建輸出流對(duì)象并綁定文件時(shí)自動(dòng)創(chuàng)建文件涩僻,不必使用File的exists方法提前檢測(cè)
4.在讀取文件時(shí)缭召,必須使用File的exists方法提前檢測(cè)來保證該文件已存在栈顷,否則拋出FileNotFoundException

2.按流向分:輸入流和輸出流

輸入流:程序從輸入流讀取數(shù)據(jù)源。數(shù)據(jù)源包括外界(鍵盤嵌巷、文件萄凤、網(wǎng)絡(luò)等),即是將數(shù)據(jù)源讀入到程序的通信通道搪哪。輸入流主要包括兩個(gè)抽象基類:InputStream(字節(jié)輸入流)和Reader(字符輸入流)及其擴(kuò)展的具體子類靡努。
輸出流:程序向輸出流寫入數(shù)據(jù)。將程序中的數(shù)據(jù)輸出到外界(顯示器晓折、打印機(jī)惑朦、文件、網(wǎng)絡(luò)等)的通信通道漓概。輸出流主要包括兩個(gè)抽象基類:OutputStream(字節(jié)輸出流)和Writer(字符輸出流)及其擴(kuò)展的具體子類漾月。

3.按功能分:節(jié)點(diǎn)流和處理流

按照流是否直接與特定的地方(如磁盤、內(nèi)存垛耳、設(shè)備等)相連栅屏,分為節(jié)點(diǎn)流和處理流兩類。
節(jié)點(diǎn)流:程序用于直接操作目標(biāo)設(shè)備所對(duì)應(yīng)的類叫節(jié)點(diǎn)流堂鲜。(低級(jí)流)
處理流:程序通過一個(gè)間接流類去調(diào)用節(jié)點(diǎn)流類栈雳,以達(dá)到更加靈活方便地讀寫各種類型的數(shù)據(jù),這個(gè)間接流類就是處理流缔莲。處理流可以看成是對(duì)已存在的流進(jìn)行連接和封裝的流哥纫。(高級(jí)流)

注意:在使用到處理流對(duì)流進(jìn)行連接和封裝時(shí),讀寫完畢只需關(guān)閉處理流痴奏,不用關(guān)閉節(jié)點(diǎn)流蛀骇。處理流關(guān)閉的時(shí)候,會(huì)調(diào)用其處理的節(jié)點(diǎn)流的關(guān)閉方法读拆。如果將節(jié)點(diǎn)流關(guān)閉以后再關(guān)閉處理流擅憔,會(huì)拋出IO異常。

(1) 節(jié)點(diǎn)流
節(jié)點(diǎn)流.png
  • File 文件流檐晕。對(duì)文件進(jìn)行讀暑诸、寫操作:FileReader、FileWriter辟灰、FileInputStream个榕、FileOutputStream。
  • Memory 流芥喇。
    向內(nèi)存數(shù)組讀寫數(shù)據(jù): CharArrayReader與 CharArrayWriter西采、ByteArrayInputStream與ByteArrayOutputStream梅割。
    向內(nèi)存字符串讀寫數(shù)據(jù):StringReader诺舔、StringWriter停巷、StringBufferInputStream厌杜。
  • Pipe管道流:實(shí)現(xiàn)管道的輸入和輸出(進(jìn)程間通信): PipedReader與PipedWriter、PipedInputStream與PipedOutputStream霹崎。
節(jié)點(diǎn)流示意圖.png
(1) 處理流
處理流.png
  • Buffering緩沖流:在讀入或?qū)懗鰰r(shí)瘦材,對(duì)數(shù)據(jù)進(jìn)行緩存,以減少I/O的次數(shù):BufferedReader與BufferedWriter仿畸、BufferedInputStream與BufferedOutputStream食棕。
  • Filtering 濾流:在數(shù)據(jù)進(jìn)行讀或?qū)憰r(shí)進(jìn)行過濾:FilterReader與FilterWriter、FilterInputStream與FilterOutputStream错沽。
  • Converting between Bytes and Characters 轉(zhuǎn)換流:按照一定的編碼/解碼標(biāo)準(zhǔn)將字節(jié)流轉(zhuǎn)換為字符流簿晓,或進(jìn)行反向轉(zhuǎn)換(Stream到Reader):InputStreamReader、OutputStreamWriter千埃。
  • Object Serialization 對(duì)象流 :ObjectInputStream憔儿、ObjectOutputStream。
  • DataConversion數(shù)據(jù)流:按基本數(shù)據(jù)類型讀放可、寫(處理的數(shù)據(jù)是Java的基本類型):DataInputStream谒臼、DataOutputStream 。
  • Counting計(jì)數(shù)流:在讀入數(shù)據(jù)時(shí)對(duì)行記數(shù) :LineNumberReader耀里、LineNumberInputStream蜈缤。
  • Peeking Ahead預(yù)讀流: 通過緩存機(jī)制,進(jìn)行預(yù)讀 :PushbackReader冯挎、PushbackInputStream底哥。
  • Printing打印流: 包含方便的打印方法 :PrintWriter、PrintStream房官。
處理流示意圖.png

讀取控制臺(tái)輸入

在Java中趾徽,從控制臺(tái)輸入有三種方法:

1.使用標(biāo)準(zhǔn)輸入流對(duì)象System.in

System.in是System中內(nèi)置的InputStream類對(duì)象,它的read方法一次只讀入一個(gè)字節(jié)數(shù)據(jù)翰守,返回0 ~ 255的一個(gè)byte值,一般用來讀取一個(gè)字符孵奶,需要強(qiáng)制類型轉(zhuǎn)換為char類型,而我們通常要取得一個(gè)字符串或一組數(shù)字蜡峰,故這種方法不常用了袁。下面給出這種方法的一個(gè)例子:

public class CharTest{
public static void main(String[] args) {
         try{   
         System.out.print("Enter a Char:");   
         char i = (char)System.in.read();   
         System.out.println("Yout Enter Char is:" + i);           }   
         catch(IOException e){   
            e.printStackTrace();   
         }   
    }
}

使用這種方法必須提供try-catch塊或者在main方法首部聲明IOException異常,因?yàn)镾ystem.in是一個(gè)流對(duì)象

2.使用Scanner類

Scanner類功能十分強(qiáng)大事示,可以讀入字符串早像、整數(shù)僻肖、浮點(diǎn)數(shù)肖爵、布爾類型值等等。下面是例子:

public class ScannerTest{
public static void main(String[] args){
    Scanner sc = new Scanner(System.in);   
    System.out.println("ScannerTest, Please Enter Name:");   
    String name = sc.nextLine();  //讀取字符串型輸入   
    System.out.println("ScannerTest, Please Enter Age:");   
    int age = sc.nextInt();    //讀取整型輸入   
    System.out.println("ScannerTest, Please Enter Salary:");   
    float salary = sc.nextFloat(); //讀取float型輸入   
    System.out.println("Your Information is as below:");   
    System.out.println("Name:" + name +"\n" + "Age:"+age 
    + "\n"+"Salary:"+salary);   
    }
 }   

注意:
1.用nextXXX()讀入XXX類型的數(shù)據(jù)臀脏,XXX可以是除了char外的所有基本數(shù)據(jù)類型劝堪,還可以是BigInteger或BigDecimal冀自,其中凡是整型類型的數(shù)據(jù)還可以指定radix(進(jìn)制),可以用next()和nextLine()讀取一個(gè)字符串或一行字符
2.next()和nextLine()的區(qū)別:
next()

  • 一定要讀取到有效字符后才可以結(jié)束輸入秒啦。
  • 對(duì)輸入有效字符之前遇到的空白熬粗,next() 方法會(huì)自動(dòng)將其去掉。
  • 只有輸入有效字符后才將其后面輸入的空白作為分隔符或者結(jié)束符余境。
  • next() 不能得到帶有空格的字符串驻呐,除非用useDelimeter方法修改分隔符。

nextLine()

  • 以Enter為結(jié)束符,也就是說 nextLine()方法返回的是輸入回車之前的所有字符芳来。
  • 可以獲得空白含末。

3.可以用循環(huán)配合hasNextXXX方法判斷輸入是否繼續(xù)
4.Scanner類沒有直接提供讀取一個(gè)字符的方法,如果要讀取一個(gè)字符即舌,有三種方法佣盒,一是讀入一個(gè)字符串后取字符串的第一個(gè)字符,二是使用System.in的read方法顽聂,三是使用字符流讀入

更多Scanner的用法之前已經(jīng)在Java學(xué)習(xí)總結(jié)之Java基本程序設(shè)計(jì)結(jié)構(gòu)中總結(jié)過了肥惭,不再贅述。

3.使用BufferedReader對(duì)象

可以把 System.in 包裝在一個(gè) BufferedReader 對(duì)象中來創(chuàng)建一個(gè)字符流紊搪。
下面是創(chuàng)建 BufferedReader 的基本語法:

BufferedReader br = new BufferedReader(new 
                      InputStreamReader(System.in));

其中蜜葱,System.in是一個(gè)InputStream對(duì)象(字節(jié)流),使用InputStreamReader作為橋梁耀石,將字節(jié)流轉(zhuǎn)換為字符流笼沥,然后再使用BufferedReader進(jìn)行進(jìn)一步包裝。
BufferedReader 對(duì)象創(chuàng)建后娶牌,我們便可以使用 read() 方法從控制臺(tái)讀取一個(gè)字符(讀入一個(gè)用0~65535之間的整數(shù)表示的字符奔浅,需要強(qiáng)制類型轉(zhuǎn)換為char類型,如果已到達(dá)流末尾诗良,則返回 -1)汹桦,或者用 readLine() 方法讀取一個(gè)字符串。下面是例子:

public static void main(String[] args){
//必須要處理java.io.IOException異常
  BufferedReader br = new BufferedReader(new InputStreamReader
  (System.in ));
  //java.io.InputStreamReader繼承了Reader類
  String read = null;
  System.out.print("輸入數(shù)據(jù):");
  try {
   read = br.readLine();
  } catch (IOException e) {
   e.printStackTrace();
  }
  System.out.println("輸入數(shù)據(jù):"+read);
 }

下面的程序示范了用 read() 方法從控制臺(tái)不斷讀取字符直到用戶輸入 "q"鉴裹。

// 使用 BufferedReader 在控制臺(tái)讀取字符
 
import java.io.*;
 
public class BRRead {
  public static void main(String args[]) throws IOException
  {
    char c;
    // 使用 System.in 創(chuàng)建 BufferedReader 
    BufferedReader br = new BufferedReader(new 
                       InputStreamReader(System.in));
    System.out.println("輸入字符, 按下 'q' 鍵退出舞骆。");
    // 讀取字符
    do {
       c = (char) br.read();
       System.out.println(c);
    } while(c != 'q');
  }
}

下面的程序讀取和顯示字符行直到你輸入了單詞"end"。

// 使用 BufferedReader 在控制臺(tái)讀取字符
import java.io.*;
public class BRReadLines {
  public static void main(String args[]) throws IOException
  {
    // 使用 System.in 創(chuàng)建 BufferedReader 
    BufferedReader br = new BufferedReader(new
                            InputStreamReader(System.in));
    String str;
    System.out.println("Enter lines of text.");
    System.out.println("Enter 'end' to quit.");
    do {
       str = br.readLine();
       System.out.println(str);
    } while(!str.equals("end"));
  }
}

在ACM等算法競(jìng)賽中径荔,我們常常也會(huì)使用Java督禽,在輸入數(shù)據(jù)時(shí)有以下幾點(diǎn)注意:
1.hasXXX等價(jià)于C++中讀到文件末尾(EOF)
2.使用BufferedReader輸入會(huì)比Scanner輸入快十倍左右!

控制臺(tái)輸出

控制臺(tái)的輸出由 print() 和 println() 完成。這些方法都由類 PrintStream 定義总处,System.out 是該類的一個(gè)對(duì)象狈惫。
PrintStream 繼承了 OutputStream類,并且實(shí)現(xiàn)了方法 write()鹦马。這樣胧谈,write() 也可以用來往控制臺(tái)寫操作忆肾。
PrintStream 定義 write() 的最簡(jiǎn)單格式如下所示:
void write(int byteval)該方法將 byteval 的低八位字節(jié)寫到流中,即System.out的write方法一次只能寫一個(gè)字節(jié)(類比System.in的read方法一次只能讀取一個(gè)字節(jié))。
下面的例子用 write() 把字符 "A" 和緊跟著的換行符輸出到屏幕:

import java.io.*;
 
// 演示 System.out.write().
public class WriteDemo {
   public static void main(String args[]) {
      int b; 
      b = 'A';//向上類型轉(zhuǎn)換
      System.out.write(b);
      System.out.write('\n');
   }
}

注意:write() 方法不經(jīng)常使用菱肖,因?yàn)?print() 和 println() 方法用起來更為方便客冈。

字節(jié)流(OutputStream、InputStream)

字節(jié)流主要是操作byte類型的數(shù)據(jù)稳强,以byte數(shù)組為準(zhǔn)场仲,主要操作類是OutputStream、InputStream退疫。
由于文件讀寫最為常見燎窘,我們先討論兩個(gè)重要的字節(jié)流 FileInputStream(文件輸入流) 和 FileOutputStream(文件輸出流),分別是抽象類InputStream和OutputStream的具體子類:

FileInputStream
該流用于從文件讀取數(shù)據(jù)蹄咖,它的對(duì)象可以用關(guān)鍵字 new 來創(chuàng)建褐健。
有多種構(gòu)造方法可用來創(chuàng)建對(duì)象。
可以使用字符串類型的文件名來創(chuàng)建一個(gè)輸入流對(duì)象來讀取文件:

InputStream f = new FileInputStream("C:/java/hello");

也可以使用一個(gè)文件對(duì)象來創(chuàng)建一個(gè)輸入流對(duì)象來讀取文件澜汤。我們首先得使用 File() 方法來創(chuàng)建一個(gè)文件對(duì)象:

File f = new File("C:/java/hello");
InputStream in = new FileInputStream(f);

創(chuàng)建了InputStream對(duì)象蚜迅,就可以使用下面的方法來讀取流或者進(jìn)行其他的流操作。


InputStream.png

下面是一個(gè)例子:

public static void main(String[] args) throws IOException{
    InputStream f  = new FileInputStream
    ("/home/xiejunyu/桌面/test.txt");
    int c = 0;
    while((c =  f.read()) != -1) 
    //這里也可以先用available方法得到可讀的字節(jié)數(shù)
    System.out.println((char)c);
}

當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)byte[]來保存讀取的字節(jié)時(shí)俊抵,如果數(shù)組太小谁不,無法完整讀入數(shù)據(jù),如果太大又會(huì)造成內(nèi)存浪費(fèi)徽诲。可以使用File類的length方法得到文件的數(shù)據(jù)字節(jié)數(shù)刹帕,從而有效確定byte數(shù)組的大小。

public static void main(String[] args) {
        // 創(chuàng)建一個(gè)FileInputStream對(duì)象
        try {
            FileInputStream fis = new FileInputStream("/home/xiejunyu/桌面/test.txt");
            byte[] b=new byte[100];
            fis.read(b,0,5); 
            /*把字節(jié)從文件讀入b數(shù)組谎替,從b數(shù)組的0位置開始存放偷溺,
            讀取5個(gè)字節(jié)*/
            System.out.println(new String(b));
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

注意: 每調(diào)用一次read方法,當(dāng)前讀取在文件中的位置就會(huì)向后移動(dòng)一個(gè)字節(jié)或者移動(dòng)byte[]的長度(read的兩個(gè)重載方法),已經(jīng)到文件末尾會(huì)返回-1钱贯,可以通過read方法返回-1判斷是否讀到文件末尾挫掏,也可以使用available方法返回下一次可以不受阻塞讀取的字節(jié)數(shù)來讀取。FileInputStream不支持mark和reset方法進(jìn)行重復(fù)讀取秩命。BufferedInputStream支持此操作尉共。

FileOutputStream
該類用來創(chuàng)建一個(gè)文件并向文件中寫數(shù)據(jù)。
如果該流在打開文件進(jìn)行輸出前弃锐,目標(biāo)文件不存在袄友,那么該流會(huì)創(chuàng)建該文件。
有兩個(gè)構(gòu)造方法可以用來創(chuàng)建 FileOutputStream 對(duì)象霹菊。
使用字符串類型的文件名來創(chuàng)建一個(gè)輸出流對(duì)象:

OutputStream f = new FileOutputStream("C:/java/hello")

也可以使用一個(gè)文件對(duì)象來創(chuàng)建一個(gè)輸出流來寫文件剧蚣。我們首先得使用File()方法來創(chuàng)建一個(gè)文件對(duì)象:

File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);

之前的所有操作中,如果重新執(zhí)行程序,則肯定會(huì)覆蓋文件中的已有內(nèi)容券敌,那么此時(shí)就可以通過FileOutputStream向文件中追加內(nèi)容,F(xiàn)ileOutputStream的另外一個(gè)構(gòu)造方法:

public FileOutputStream(File file,boolean append) 

在構(gòu)造方法中柳洋,如果將append的值設(shè)置為true待诅,則表示在文件的末尾追加內(nèi)容。程序代碼如下:

File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f,true);

創(chuàng)建OutputStream 對(duì)象完成后熊镣,就可以使用下面的方法來寫入流或者進(jìn)行其他的流操作卑雁。

FileOutputStream.png

當(dāng)有一個(gè)字符串時(shí),可以用getBytes方法轉(zhuǎn)為byte數(shù)組用于字節(jié)流的輸出绪囱。

下面是一個(gè)演示 InputStream 和 OutputStream 用法的例子:

import java.io.*;
 
public class FileStreamTest{
  public static void main(String args[]){
    try{
      byte bWrite[] = "ABC".getBytes();
      OutputStream os = new FileOutputStream("/home/xiejunyu/桌面/test.txt");
      for(int x=0; x < bWrite.length ; x++){
      os.write(bWrite[x] ); // writes the bytes
    }
    os.close();
 
    InputStream is = new FileInputStream("/home/xiejunyu/桌面/test.txt");
    int size = is.available();
 
    for(int i=0; i< size; i++){
      System.out.print((char)is.read() + "  ");
    }
      is.close();
    }catch(IOException e){
      System.out.print("Exception");
    }  
  }
}

上面的程序首先創(chuàng)建文件test.txt测蹲,并把給定的數(shù)字以二進(jìn)制形式寫進(jìn)該文件,同時(shí)輸出到控制臺(tái)上鬼吵。
以上代碼由于是二進(jìn)制寫入扣甲,可能存在亂碼,你可以使用以下代碼實(shí)例來解決亂碼問題:

import java.io.*;
 
public class fileStreamTest2{
  public static void main(String[] args) throws IOException {
    
    File f = new File("a.txt");
    FileOutputStream fop = new FileOutputStream(f);
    // 構(gòu)建FileOutputStream對(duì)象,文件不存在會(huì)自動(dòng)新建;如果存在會(huì)覆蓋原文件
    
    OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
    // 構(gòu)建OutputStreamWriter對(duì)象,參數(shù)可以指定編碼,默認(rèn)為操作系統(tǒng)默認(rèn)編碼,windows上是gbk
    
    writer.append("中文輸入");
    // 寫入到緩沖區(qū)
    
    writer.append("\r\n");
    //換行
    
    writer.append("English");
    // 刷新緩沖區(qū),寫入到文件,如果下面已經(jīng)沒有寫入的內(nèi)容了,直接close也會(huì)寫入
    
    writer.close();
    //關(guān)閉寫入流,同時(shí)會(huì)把緩沖區(qū)內(nèi)容寫入文件,所以上面的注釋掉
    
    fop.close();
    // 關(guān)閉輸出流,釋放系統(tǒng)資源
 
    FileInputStream fip = new FileInputStream(f);
    // 構(gòu)建FileInputStream對(duì)象
    
    InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
    // 構(gòu)建InputStreamReader對(duì)象,編碼與寫入相同
 
    StringBuffer sb = new StringBuffer();
    while (reader.ready()) {
      sb.append((char) reader.read());
      // 轉(zhuǎn)成char加到StringBuffer對(duì)象中
    }
    System.out.println(sb.toString());
    reader.close();
    // 關(guān)閉讀取流
    
    fip.close();
    // 關(guān)閉輸入流,釋放系統(tǒng)資源
 
  }
}

以上例子證明:在對(duì)多國語言的支持上齿椅,字符流表現(xiàn)更優(yōu)琉挖,此時(shí)應(yīng)使用字符流而不是字節(jié)流。

還可以用InputStream和OutputStream配合進(jìn)行文件的復(fù)制涣脚,即讀取原件數(shù)據(jù)示辈,寫入副本文件。
復(fù)制有兩種實(shí)現(xiàn)方式:
實(shí)現(xiàn)一:將源文件中的內(nèi)容全部讀取進(jìn)來遣蚀,之后一次性的寫入到目標(biāo)文件
實(shí)現(xiàn)二:邊讀邊寫

在實(shí)際開發(fā)中建議使用邊讀邊寫的方式矾麻,代碼如下:

public static void main(String[] args) {
        // 文件拷貝
        try {
            FileInputStream fis=new FileInputStream("happy.gif");
            FileOutputStream fos=new FileOutputStream("happycopy.gif");
            int n=0;
            byte[] b=new byte[1024];
            while((n=fis.read(b))!=-1){ 
            /*循環(huán)讀取,每次1024個(gè)字節(jié)芭梯,最后一次可能不滿1024险耀。
            后面的字節(jié)覆蓋前面的字節(jié),不必?fù)?dān)心數(shù)組溢出玖喘。*/
                fos.write(b,0,n); //n是實(shí)際讀取到的字節(jié)數(shù)胰耗,如果寫fos.write(b),會(huì)造成最后一次數(shù)組未滿的情況也寫1024個(gè)字節(jié)芒涡,從而造成副本比原件略大
            }
            fis.close();
            fos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

實(shí)際上邊讀邊寫也分為三種方式:
1.批量拷貝(循環(huán)讀取柴灯,每次讀入一個(gè)byte數(shù)組)
2.緩沖拷貝(使用緩沖流)
3.批量+緩沖拷貝(循環(huán)批量讀取到字節(jié)數(shù)組中,然后使用緩沖輸出流寫入到文件)

第三種方式是最快的费尽。

注意:InputStream的int read()方法讀取一個(gè)字節(jié)赠群,并用這個(gè)字節(jié)填充整型的低八位并返回,OutputStream的void write(int x)寫入x的低八位旱幼,如果要寫入一個(gè)int查描,需要移位并寫4次。讀寫基本數(shù)據(jù)類型建議使用DataInputStream和DataOutputStream。

后續(xù)內(nèi)容見 Java學(xué)習(xí)總結(jié)之Java IO系統(tǒng)(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冬三,一起剝皮案震驚了整個(gè)濱河市匀油,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌勾笆,老刑警劉巖敌蚜,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異窝爪,居然都是意外死亡弛车,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門蒲每,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纷跛,“玉大人,你說我怎么就攤上這事邀杏∑兜欤” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵望蜡,是天一觀的道長叮阅。 經(jīng)常有香客問我,道長泣特,這世上最難降的妖魔是什么浩姥? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮状您,結(jié)果婚禮上勒叠,老公的妹妹穿的比我還像新娘。我一直安慰自己膏孟,他們只是感情好眯分,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柒桑,像睡著了一般弊决。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上魁淳,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天飘诗,我揣著相機(jī)與錄音,去河邊找鬼界逛。 笑死昆稿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的息拜。 我是一名探鬼主播溉潭,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼净响,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了喳瓣?” 一聲冷哼從身側(cè)響起馋贤,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎畏陕,沒想到半個(gè)月后配乓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹭秋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年扰付,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堤撵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仁讨。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖实昨,靈堂內(nèi)的尸體忽然破棺而出洞豁,到底是詐尸還是另有隱情,我是刑警寧澤荒给,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布丈挟,位于F島的核電站,受9級(jí)特大地震影響志电,放射性物質(zhì)發(fā)生泄漏曙咽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一挑辆、第九天 我趴在偏房一處隱蔽的房頂上張望例朱。 院中可真熱鬧,春花似錦鱼蝉、人聲如沸洒嗤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渔隶。三九已至,卻和暖如春洁奈,著一層夾襖步出監(jiān)牢的瞬間间唉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工利术, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留终吼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓氯哮,卻偏偏與公主長得像际跪,于是被迫代替她去往敵國和親商佛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,868評(píng)論 6 13
  • 一姆打、基礎(chǔ)知識(shí):1良姆、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,365評(píng)論 0 4
  • tags:io categories:總結(jié) date: 2017-03-28 22:49:50 不僅僅在JAVA領(lǐng)...
    行徑行閱讀 2,168評(píng)論 0 3
  • 每當(dāng)過年過節(jié)的時(shí)候幔戏,家里都會(huì)做起蛋餃玛追。做蛋餃最好用舊式的煤餅爐子,拿一個(gè)球型底的大勺闲延,用一塊凝固了的豬油在勺子底上...
    持明院主閱讀 9,733評(píng)論 0 16
  • 不知道從什么時(shí)候開始垒玲,喜歡上了梵高的畫陆馁。而且,喜歡得不得了合愈。 至于為什么會(huì)喜歡叮贩,不知道,完全沒有理由佛析,就是單純的喜...
    彩蝶百合閱讀 480評(píng)論 1 9