Java IO總結(jié)

Java中IO的內(nèi)容非常豐富,相信第一次學(xué)習(xí)的時(shí)候,所有人都會被一大堆API繞暈,今天我們就來系統(tǒng)的總結(jié)一下.

Java的IO體系主要包括流式部分(各種IO流的操作)及非流式部分(文件的實(shí)體)。

IO流

Java中的IO流實(shí)際上用起來都非常方便簡單,為我們封裝了大量實(shí)用性的接口,同時(shí)采用了裝飾器設(shè)計(jì)模式,所以看起來很龐大,但還是比較清晰的,總覽見下圖(圖片來源于網(wǎng)絡(luò))



可見分為字符流和字節(jié)流兩大部分,每部分又有輸入輸出之分,首先先了解一下字符流和字節(jié)流的區(qū)別:

字符流處理的單元為2個(gè)字節(jié)的Unicode字符,主要是操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個(gè)字節(jié),操作字節(jié)和字節(jié)數(shù)組。所以字符流是由Java虛擬機(jī)將字節(jié)轉(zhuǎn)化為2個(gè)字節(jié)的Unicode字符為單位的字符而成的。一般而言,音頻文件、圖片、歌曲之類的使用字節(jié)流,如果是涉及到中文(文本)的,用字符流好點(diǎn)

1.字節(jié)流

1.1 FileInputStreamFileOutputStream

這兩個(gè)類是專門操作文件的。這兩個(gè)類是直接繼承于裝飾器模式的頂層類:InputStream和OutputStream。是字節(jié)流體系中文件操作的核心。由于是裝飾器模式,所以他們的功能也最簡單。

單從方法上看,他們都只有寥寥幾個(gè)方法,主要是讀和寫(詳細(xì)APi可以參考官方文檔,標(biāo)題的超鏈接就是每個(gè)類的文檔,這里不復(fù)述了,每各類只記錄關(guān)鍵用法,下面也一樣)下面我們舉一個(gè)拷貝文件的例子:

        try (FileInputStream inputStream = new FileInputStream(new File("file/test.png"));
             FileOutputStream outputStream = new FileOutputStream(new File("file/copy.png"))){
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = inputStream.read(b))!=-1){
                    outputStream.write(b,0,len);
                }
            } catch (Exception e) {
            e.printStackTrace();
        }

這算是IO操作的標(biāo)準(zhǔn)寫法了。上面代碼中應(yīng)用了try-with-resources語法,這時(shí)Java1.7的新特性。主要是為了幫我們在IO操作或與之類似的操作中,擺脫無盡的try-catch語句,想一想,之前若沒有這樣寫法,上面代碼應(yīng)該是這樣的:

        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(new File("file/test.png"));
                outputStream = new FileOutputStream(new File("file/copy.png"));
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = inputStream.read(b))!=-1){
                    outputStream.write(b,0,len);
                }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream!=null)
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if (outputStream!=null)
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

try-with-resources語法只是自動(dòng)幫我們調(diào)用了close方法,不僅僅是用在流上,所有實(shí)現(xiàn)了AutoCloseable接口的類都可以。而AutoCloseable只有一個(gè)close方法。下面的實(shí)例我都會采用這種語法。

最后還有比較重要的一點(diǎn),在FileOutputStream中,默認(rèn)對文件操作是覆蓋形式的,也就是打開一個(gè)文件后不管寫不寫東西都會講文件內(nèi)容清空,若想追加的形式操作,可利用他的兩參數(shù)構(gòu)造,第二個(gè)布爾型參數(shù)傳入true即可。后面類中對文件操作需要傳入FileOutputStream參數(shù)時(shí),也是一樣。另外字符流也有類似操作,可參看API,下面就不多說了。

1.2 ObjectInputStreamObjectOutputStream

這兩個(gè)類用的也很多,用于存儲對象。曾經(jīng)有過一次開發(fā)經(jīng)驗(yàn),就是從一個(gè)xml文件中解析內(nèi)容,如果解析完之后序列化存儲到文件中,下次再反序列化時(shí)用的時(shí)間遠(yuǎn)遠(yuǎn)少于從xml文件中直接解析。

接下來我們就來認(rèn)識一下他們,以O(shè)bjectInputStream為例(ObjectOutputStream也一樣,對應(yīng)讀方法都有相應(yīng)的寫方法),他除了有基本的read方法,還有許多如readInt,readBoolean等直接讀出對應(yīng)類型的方法,另外還有一個(gè)很重要的readObject()方法,這個(gè)是通用的,可以讀一切對象,下面簡單舉一個(gè)例子:

public static void write(){
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("file/obj")))){
            out.writeObject(list);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void read(){
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("file/obj")))){
            ArrayList<String> list = (ArrayList<String>) in.readObject();
            System.out.println(list.get(1));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

這里有兩個(gè)問題需要額外關(guān)注一下:

  • 1.寫的時(shí)候,所有對象都必須可序列化,如集合內(nèi)的所有對象。序列化知識參考這里

  • 2.關(guān)于如何判斷讀完的問題。首先如果不加限制的讀,一個(gè)文件中所有對象都讀完后,再讀是不會讀到null之類的,而是直接拋出java.io.EOFException異常,所以我們要加以控制。第一個(gè)辦法可以在寫的時(shí)候最后添加一個(gè)空對象,每讀一個(gè)對象判斷一次,讀到null的時(shí)候不再讀了。第二個(gè)辦法是將所有要存東西添加到集合中,讀的時(shí)候永遠(yuǎn)只讀一次。最后一個(gè)辦法是利用異常判斷,捕獲到異常后在finally代碼塊中處理,不過這種方法影響性能,不提倡。

1.3 DataInputStreamDataOutputStream

這一對更像是上面的簡化版,他只能讀寫基本數(shù)據(jù)類型,示例:

    public static void write(){
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        try (DataOutputStream out = new DataOutputStream(new FileOutputStream(new File("file/obj")))){
            for (String str : list)
                out.writeUTF(str);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void read(){
        try (DataInputStream in = new DataInputStream(new FileInputStream(new File("file/obj")))){
            System.out.println(in.readUTF());
            System.out.println(in.readUTF());
            System.out.println(in.readUTF());
            System.out.println(in.readUTF());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

由于是讀寫基本數(shù)據(jù)類型,所以不用擔(dān)心序列化問題,但是還是要處理EOFException異常,和上面類似,只不過不能寫集合了,可以在第一個(gè)位置寫入對象數(shù),后面根據(jù)數(shù)量取對象。或者寫入特殊標(biāo)志位也可以。

1.4 ByteArrayInputStreamByteArrayOutputStream

這兩個(gè)類的共同點(diǎn)都是有一個(gè)字節(jié)數(shù)組作為緩沖區(qū)。

先看ByteArrayInputStream,該類主要是從一個(gè)字節(jié)數(shù)組中讀內(nèi)容,他的兩個(gè)構(gòu)造都需要傳入字節(jié)數(shù)組,示例

        try(ByteArrayInputStream bi = new ByteArrayInputStream("adsd".getBytes())){
            System.out.println((char)bi.read());
            System.out.println(bi.available());
        }catch (Exception e){
            e.printStackTrace();
        }

再看ByteArrayOutputStream,它有兩個(gè)構(gòu)造方法:

public ByteArrayOutputStream()
public ByteArrayOutputStream(int size)

第一個(gè)默認(rèn)創(chuàng)建長度為32的數(shù)組,第二個(gè)指定數(shù)組大小。該類所有寫方法,都是把內(nèi)容寫到字節(jié)緩沖區(qū)中,最后可以調(diào)用toString或者toByteArray()取出,還可以查詢寫入的長度。示例:

        try(ByteArrayOutputStream bo = new ByteArrayOutputStream()){
            bo.write("adsd".getBytes());
            System.out.println(bo.toString());
            System.out.println(bo.size());
        }catch (Exception e){
            e.printStackTrace();
        }

這兩個(gè)類可以和FileInputStream與FileOutputStream 類比,F(xiàn)ileInputStream與FileOutputStream 是讀寫文件,ByteArrayInputStream和ByteArrayOutputStream則是讀寫內(nèi)存,也就是內(nèi)存中的字節(jié)數(shù)組,可以把字節(jié)數(shù)組看做虛擬文件。

1.5 BufferedInputStreamBufferedOutputStream

我們在學(xué)習(xí)FileInputStream與FileOutputStream時(shí)就考慮到了,如果一字節(jié)一字節(jié)的從硬盤中讀寫,由于每次都需要啟動(dòng)硬盤尋找數(shù)據(jù),效率很低,所以我們設(shè)置了一個(gè)數(shù)組作為緩沖。而這兩個(gè)類自帶緩沖,默認(rèn)大小為8192,可以自己設(shè)定。每次讀的時(shí)候他會一次讀滿緩沖,然后再從緩沖中取數(shù)據(jù),寫的時(shí)候也類似。

基本用法和FileInputStream與FileOutputStream類似,我們這里對二者做一個(gè)比較,看緩沖有沒有用:

long start = System.currentTimeMillis();
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream("file/test.png"));
             BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("file/copy.png"))){
            int a;
            do {
                a = in.read();
                if (a!=-1)
                    out.write(a);
                else
                    break;
            }while(true);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis()-start);
        Runtime.getRuntime().gc();
        start = System.currentTimeMillis();
        try (FileInputStream in = new FileInputStream("file/test1.png");
             FileOutputStream out = new FileOutputStream("file/copy1.png")){
            int a;
            do {
                a = in.read();
                if (a!=-1)
                    out.write(a);
                else
                    break;
            }while(true);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis()-start);
        Runtime.getRuntime().gc();
        start = System.currentTimeMillis();
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream("file/test2.png"));
             BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("file/copy2.png"))){
            byte[] b = new byte[8192];
            int len = 0;
            while ((len = in.read(b))!=-1){
                out.write(b,0,len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis()-start);

第一次用的是帶緩沖的,但是每次只讀一個(gè)字節(jié)和寫一個(gè)字節(jié),第二次是用不帶緩沖的,也是每次只讀一個(gè)字節(jié)和寫一個(gè)字節(jié),第三次使用的帶緩沖的,但是每次讀寫為一整個(gè)數(shù)組,運(yùn)行時(shí)間如下:

61
3840
5

可見差距還是很大的,首先說明了緩沖的確有作用,另外即使有緩沖,也不建議一字節(jié)一字節(jié)的操作,還是要借助數(shù)據(jù)成塊讀寫。

1.6 SequenceInputStream

這個(gè)類的作用是合并多個(gè)輸入流,它有兩個(gè)構(gòu)造函數(shù),若是合并兩個(gè)流,直接用雙參數(shù)構(gòu)造,若是多余兩個(gè)。需要以Enumeration實(shí)例的形式傳入。不多說,看代碼:

try (FileInputStream in = new FileInputStream("file/test.txt");
             FileInputStream in1 = new FileInputStream("file/test1.txt");
             FileInputStream in2 = new FileInputStream("file/test2.txt");
             FileOutputStream out = new FileOutputStream("file/out.txt")){
                Vector<InputStream> vector = new Vector<>();
                vector.add(in);
                vector.add(in1);
                vector.add(in2);
            SequenceInputStream sis = new SequenceInputStream(vector.elements());
            byte[] b = new byte[1024];
            int len;
            while ((len = sis.read(b))!=-1){
                out.write(b,0,len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

有一點(diǎn)需要注意,雖然是合并,但輸出是還是有順序的,就是添加的順序。

1.7 PushbackInputStream

這個(gè)類有個(gè)緩存,可以將從流中讀取到的數(shù)據(jù),回退到流中。為什么特意說有何緩存,其實(shí)回退操作是借助與緩存實(shí)現(xiàn)的,并不是流中真的有回退數(shù)據(jù)。它有兩個(gè)構(gòu)造,除了都要穿輸入流外,一個(gè)可以指定緩存的大小,也就是最大回退的大小,另外一個(gè)默認(rèn)為1,示例

        try (PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream("asdfertghuji".getBytes()),7)){
            byte[] buffer = new byte[7];
            pis.read(buffer);
            System.out.println(new String(buffer));
            pis.unread(buffer,0,4);
            pis.read(buffer);
            System.out.println(new String(buffer));
        }catch (Exception e){
            e.printStackTrace();
        }

輸出

asdfert
asdfghu

簡單解釋一下,第一次讀了7個(gè)字節(jié),asdfert,然后回退4個(gè)字節(jié),也就是上次讀的前四個(gè),回退的邏輯上放在流的前方,下一次在讀7字節(jié),首先讀到的是回退的asdf,然后從流中在讀3字節(jié)ghu,組成asdfghu。

除了回退已讀到的,還可以回退任意數(shù)據(jù)

        try (PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream("asdfertghuji".getBytes()),7)){
            byte[] buffer = new byte[7];
            pis.read(buffer);
            System.out.println(new String(buffer));
            pis.unread("1234".getBytes(),0,4);
            pis.read(buffer);
            System.out.println(new String(buffer));
        }catch (Exception e){
            e.printStackTrace();
        }

但是回退的長度不能超過我們在構(gòu)造中指定的長度,因?yàn)榛赝耸腔诰彺鏀?shù)組的,放不下就會拋異常java.io.IOException: Push back buffer is full

1.8 PipedInputStreamPipedOutputStream

這兩個(gè)類比較特殊,他們是溝通兩個(gè)線程用的,根據(jù)名字很好理解,在兩個(gè)線程中架設(shè)一個(gè)管道。這兩個(gè)類必須成對使用,因?yàn)橐趦蓚€(gè)線程間傳輸?shù)那疤崾荘ipedInputStream與PipedOutputStream建立連接,可以利用構(gòu)造或者connect方法。其實(shí)在線程中傳輸也是利用緩存實(shí)現(xiàn)的,默認(rèn)大小是1024,可以指定。簡單示例

public class Receiver extends Thread{
    private PipedInputStream in = new PipedInputStream();

    public PipedInputStream getIn(){
        return in;
    }
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("receiver start");
            System.out.println((char)in.read());
            System.out.println("receiver end");
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class Sender extends Thread{
    private PipedOutputStream out = new PipedOutputStream();

    public PipedOutputStream getOut(){
        return out;
    }
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("sender start");
            out.write('d');
            System.out.println("sender end");
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    public static void main(String[] args) throws IOException {
        Receiver receiver = new Receiver();
        Sender sender = new Sender();
        receiver.getIn().connect(sender.getOut());
        receiver.start();
        sender.start();
    }

不必?fù)?dān)心說先啟動(dòng)Receiver 會收不到消息,首先兩個(gè)線程是并行的,其次read方法也是有阻塞的,除非PipedOutputStream 關(guān)閉了,否則會一直等待另一端寫入內(nèi)容。

關(guān)于connect方法,不管是input取綁定output,還是output綁定input都是一樣的效果。另外可以利用構(gòu)造方法綁定,詳見API介紹

2.字符流

2.1 FileReaderFileWriter

這是字符流中一對文件操作類,它是按字符從文件中讀寫,基本用法和FileInputStream/FileOutputStream類似,示例

    public static void main(String[] args) throws IOException {
        try (FileReader reader = new FileReader("file/test.txt");
             FileWriter writer = new FileWriter("file/copy.txt")){
            char[] c = new char[1024];
            int len;
            while ((len = reader.read(c)) != -1){
                writer.write(c,0,len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

那么這兩個(gè)類和FileInputStream/FileOutputStream有什么區(qū)別呢?主要一點(diǎn)是字符上,這兩個(gè)類是以字符為單位讀的,簡單演示一下區(qū)別:

    public static void main(String[] args) throws IOException {
        try (FileReader reader = new FileReader("file/test.txt");
             FileInputStream in = new FileInputStream("file/test.txt")){
            System.out.println((char)reader.read());
            System.out.println((char)in.read());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

讀一個(gè)中文字符,結(jié)果如下:

陳
é

具體字符和字節(jié)的區(qū)別,可以自行學(xué)習(xí)。

2.2 BufferedReaderBufferedWriter

同字節(jié)流一樣,這里也給我們提供了自帶緩沖的類,默認(rèn)大小也是8192,原理不多講了,但是這里有一個(gè)特殊方法,就是能一次讀一行readLine(),以及插入換行符newLine()。

2.3 CharArrayReaderCharArrayWriter

和 ByteArrayInputStream與ByteArrayOutputStream很類似,只不過這里操作的是字符數(shù)組而已,連方法都很類似。

2.4 PushbackReader

字符版的回退流,操作和字節(jié)流對應(yīng)的一樣

        try (PushbackReader pis = new PushbackReader(new CharArrayReader("asdfertghuji".toCharArray()),7)){
            char[] buffer = new char[7];
            pis.read(buffer);
            System.out.println(new String(buffer));
            pis.unread("1234".toCharArray(),0,4);
            pis.read(buffer);
            System.out.println(new String(buffer));
        }catch (Exception e){
            e.printStackTrace();
        }

2.5 PipedReaderPipedWriter

字符版的線程間傳輸,用法和字節(jié)版的一樣,甚至都不用改代碼,只需替換對應(yīng)的類即可,不再舉例。

2.6 StringReaderStringWriter

和CharArrayReader與CharArrayWriter類似,主不過被操作的是字符串而不是字符數(shù)組。

文件

主要有FileRandomAccessFile

File是文件的實(shí)體類,包含了大量對文件的操作,RandomAccessFile則可以對文件內(nèi)容進(jìn)行操作。File類一般都很熟悉,它相當(dāng)于一個(gè)工具類,這里不多講,主要看RandomAccessFile。

RandomAccessFile有兩個(gè)構(gòu)造:

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

都是需要指定文件和操作模式。一般有以下4種模式

r 代表以只讀方式打開指定文件 。
rw 以讀寫方式打開指定文件 。
rws 讀寫方式打開,并對內(nèi)容或元數(shù)據(jù)都同步寫入底層存儲設(shè)備 。
rwd 讀寫方式打開,對文件內(nèi)容的更新同步更新至底層存儲設(shè)備 。

與流式操作每種類只能讀或?qū)懳募煌@個(gè)以既可以讀也可以寫,他的一大特點(diǎn)是隨機(jī)讀寫,這也是一些斷點(diǎn)續(xù)傳,多線程下載等技術(shù)的基本。

基本的讀寫操作就不介紹了,主要介紹一些特色方法,如下例在文件末尾追加內(nèi)容:

        try (RandomAccessFile file = new RandomAccessFile("file/test.txt","rw")){
            file.seek(file.length()); //獲取文件長度,設(shè)置指針位置
            file.write('d'); //寫一個(gè)字符
            System.out.println(file.getFilePointer()); //獲取當(dāng)前指針位置
        }catch (Exception e){
            e.printStackTrace();
        }

另外可以設(shè)置文件大小,只占位置,沒有內(nèi)容,適合多線程下載時(shí)配置文件

file.setLength(1024*1024*8); //設(shè)置大小8M
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,089評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,106評論 2 375

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