Java NIO學(xué)習(xí)筆記-通道&緩沖區(qū)

Java NIO是什么

Java NIO( New IO) 是從Java 1.4版本開(kāi)始引入的一個(gè)新的IO API执庐,可以替代標(biāo)準(zhǔn)的Java IO API。NIO與原來(lái)的IO有同樣的作用和目的导梆,但是使用的方式完全不同轨淌, NIO支持面向緩沖區(qū)的、基于通道的IO操作看尼。 NIO將以更加高效的方式進(jìn)行文件的讀寫(xiě)操作递鹉。

Java NIO 與 IO 的主要區(qū)別

IO NIO
面向流(Stream Oriented) 面向緩沖區(qū)(Buffer Oriented)
阻塞IO(Blocking IO) 非阻塞IO(Non Blocking IO)
(無(wú)) 選擇器(Selectors)

緩沖區(qū)( Buffer)

一個(gè)用于特定基本數(shù)據(jù)類(lèi)型的容器。由 java.nio 包定義的藏斩,所有緩沖區(qū)都是 Buffer 抽象類(lèi)的子類(lèi)躏结。Buffer 主要用于與 NIO 通道進(jìn)行交互,數(shù)據(jù)是從通道讀入緩沖區(qū)灾茁,從緩沖區(qū)寫(xiě)入通道中的窜觉。Buffer 就像一個(gè)數(shù)組,可以保存多個(gè)相同類(lèi)型的數(shù)據(jù)北专。根據(jù)數(shù)據(jù)類(lèi)型不同(boolean 除外) 禀挫,有以下 Buffer 常用子類(lèi):

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

上述 Buffer 類(lèi) 他們都采用相似的方法進(jìn)行管理數(shù)據(jù),只是各自管理的數(shù)據(jù)類(lèi)型不同而已拓颓。

緩沖區(qū)的基本屬性
  • 容量 (capacity) :表示 Buffer 最大數(shù)據(jù)容量语婴,緩沖區(qū)容量不能為負(fù),并且創(chuàng)建后不能更改.
  • 限制 (limit):第一個(gè)不應(yīng)該讀取或?qū)懭氲臄?shù)據(jù)的索引驶睦,即位于 limit 后的數(shù)據(jù)不可讀寫(xiě)砰左。緩沖區(qū)的限制不能為負(fù),并且不能大于其容量场航。
  • 位置 (position):下一個(gè)要讀取或?qū)懭氲臄?shù)據(jù)的索引缠导。緩沖區(qū)的位置不能為負(fù),并且不能大于其限制.
  • 標(biāo)記 (mark)與重置 (reset):標(biāo)記是一個(gè)索引溉痢,通過(guò) Buffer 中的 mark() 方法指定 Buffer 中一個(gè)特定的 position僻造,之后可以通過(guò)調(diào)用 reset()方法恢復(fù)到這個(gè) position.

標(biāo)記、 位置孩饼、 限制髓削、 容量遵守以下不變式: 0 <= mark <= position <= limit <= capacity

緩沖區(qū)的數(shù)據(jù)操作

Buffer 所有子類(lèi)提供了兩個(gè)用于數(shù)據(jù)操作的方法: get()與 put() 方法

獲取 Buffer 中的數(shù)據(jù)
  • get() :讀取單個(gè)字節(jié)
  • get(byte[] dst):批量讀取多個(gè)字節(jié)到 dst 中
  • get(int index):讀取指定索引位置的字節(jié)(不會(huì)移動(dòng) position)
放入數(shù)據(jù)到 Buffer 中
  • put(byte b):將給定單個(gè)字節(jié)寫(xiě)入緩沖區(qū)的當(dāng)前位置
  • put(byte[] src):將 src 中的字節(jié)寫(xiě)入緩沖區(qū)的當(dāng)前位置
  • put(int index, byte b):將指定字節(jié)寫(xiě)入緩沖區(qū)的索引位置(不會(huì)移動(dòng) position)
public class TestBuffer {

    @Test
    public void test1() {
        //分配指定大小的緩沖區(qū)
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        System.out.println(buffer.position());//0 返回緩沖區(qū)的當(dāng)前位置 position
        System.out.println(buffer.limit());//1024 返回 Buffer 的界限(limit) 的位置
        System.out.println(buffer.capacity());//1024 返回Buffer的capacity 大小
        //將數(shù)據(jù)存入緩沖區(qū)
        buffer.put("abcde".getBytes());
        
        System.out.println(buffer.position());//5
        System.out.println(buffer.limit());//1024
        System.out.println(buffer.capacity());//1024
        //切換到讀取數(shù)據(jù)的模式
        buffer.flip();
        
        System.out.println(buffer.position());//0
        System.out.println(buffer.limit());//5
        System.out.println(buffer.capacity());//1024
        //讀取緩沖區(qū)的數(shù)據(jù)
        byte[] bs = new byte[buffer.limit()];
        buffer.get(bs);
        System.out.println(new String(bs, 0, bs.length));//abcde
        
        System.out.println(buffer.position());//5
        System.out.println(buffer.limit());//5
        System.out.println(buffer.capacity());//1024
        //回到讀模式,可重復(fù)讀數(shù)據(jù)
        buffer.rewind();//將位置設(shè)為為 0镀娶, 取消設(shè)置的 mark
        
        System.out.println(buffer.position());//0
        System.out.println(buffer.limit());//5
        System.out.println(buffer.capacity());//1024
        //清空緩沖區(qū)立膛,回到最初狀態(tài)。但是緩沖區(qū)的數(shù)據(jù)還在梯码,處于被遺忘狀態(tài)宝泵。
        buffer.clear();//清空緩沖區(qū)并返回對(duì)緩沖區(qū)的引用
        System.out.println(buffer.position());//0
        System.out.println(buffer.limit());//1024
        System.out.println(buffer.capacity());//1024
    }
    
    @Test
    public void test2() {
        String str = "abcde";
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(str.getBytes());
        
        System.out.println(buffer.position());//5
        System.out.println(buffer.limit());//1024
        System.out.println(buffer.capacity());//1024
        
        buffer.flip();
        
        byte[] bs = new byte[buffer.limit()];
        buffer.get(bs, 0, 2);
        System.out.println(new String(bs, 0, 2));//ab
        
        System.out.println(buffer.position());//2
        System.out.println(buffer.limit());//5
        System.out.println(buffer.capacity());//1024
        //標(biāo)記position的位置
        buffer.mark();
        
        buffer.get(bs, 2, 2);
        System.out.println(new String(bs, 2, 2));//cd
        
        System.out.println(buffer.position());//4
        //重置position的位置到標(biāo)記的地方
        buffer.reset();
        
        System.out.println(buffer.position());//2
        //緩沖區(qū)中是否還有課操作的字節(jié)
        if (buffer.hasRemaining()) {
            //剩余可操作的字節(jié)數(shù)
            System.out.println(buffer.remaining());//3 返回 position 和 limit 之間的元素個(gè)數(shù)
        }
    }
    
    @Test
    public void test3() {
        //創(chuàng)建直接緩沖區(qū)
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        //判斷是否為直接緩沖區(qū)
        System.out.println(buffer.isDirect());//true
    }
}

直接與非直接緩沖區(qū)

  1. 字節(jié)緩沖區(qū)要么是直接的好啰,要么是非直接的。如果為直接字節(jié)緩沖區(qū)鲁猩,則 Java 虛擬機(jī)會(huì)盡最大努力直接在此緩沖區(qū)上執(zhí)行本機(jī) I/O操作坎怪。也就是說(shuō)罢坝,在每次調(diào)用基礎(chǔ)操作系統(tǒng)的一個(gè)本機(jī) I/O 操作之前(或之后)廓握,虛擬機(jī)都會(huì)盡量避免將緩沖區(qū)的內(nèi)容復(fù)制到中間緩沖區(qū)中(或從中間緩沖區(qū)中復(fù)制內(nèi)容)。
  2. 直接字節(jié)緩沖區(qū)可以通過(guò)調(diào)用此類(lèi)的 allocateDirect() 工廠方法來(lái)創(chuàng)建嘁酿。此方法返回的緩沖區(qū)進(jìn)行分配和取消分配所需成本通常高于非直接緩沖區(qū)隙券。直接緩沖區(qū)的內(nèi)容可以駐留在常規(guī)的垃圾回收堆之外,因此闹司,它們對(duì)應(yīng)用程序的內(nèi)存需求量造成的影響可能并不明顯娱仔。所以,建議將直接緩沖區(qū)主要分配給那些易受基礎(chǔ)系統(tǒng)的本機(jī) I/O 操作影響的大型游桩、持久的緩沖區(qū)牲迫。一般情況下,最好僅在直接緩沖區(qū)能在程序性能方面帶來(lái)明顯好處時(shí)分配它們借卧。
  3. 直接字節(jié)緩沖區(qū)還可以通過(guò) FileChannel 的 map() 方法將文件區(qū)域直接映射到內(nèi)存中來(lái)創(chuàng)建盹憎。該方法返回MappedByteBuffer。Java 平臺(tái)的實(shí)現(xiàn)有助于通過(guò) JNI從本機(jī)代碼創(chuàng)建直接字節(jié)緩沖區(qū)铐刘。如果以上這些緩沖區(qū)中的某個(gè)緩沖區(qū)實(shí)例指的是不可訪(fǎng)問(wèn)的內(nèi)存區(qū)域陪每,則試圖訪(fǎng)問(wèn)該區(qū)域不會(huì)更改該緩沖區(qū)的內(nèi)容,并且將會(huì)在訪(fǎng)問(wèn)期間或稍后的某個(gè)時(shí)間導(dǎo)致拋出不確定的異常镰吵。
  4. 字節(jié)緩沖區(qū)是直接緩沖區(qū)還是非直接緩沖區(qū)可通過(guò)調(diào)用其 isDirect() 方法來(lái)確定檩禾。提供此方法是為了能夠在性能關(guān)鍵型代碼中執(zhí)行顯式緩沖區(qū)管理。

通道Channel

通道表示打開(kāi)到 IO 設(shè)備(例如:文件疤祭、套接字)的連接盼产。若需要使用 NIO 系統(tǒng),需要獲取用于連接 IO 設(shè)備的通道以及用于容納數(shù)據(jù)的緩沖區(qū)勺馆。然后操作緩沖區(qū)戏售,對(duì)數(shù)據(jù)進(jìn)行處理。Channel 負(fù)責(zé)傳輸谓传, Buffer 負(fù)責(zé)存儲(chǔ)蜈项。通道是由 java.nio.channels 包定義的。 Channel 表示 IO 源與目標(biāo)打開(kāi)的連接续挟。Channel 類(lèi)似于傳統(tǒng)的“流”紧卒。只不過(guò) Channel本身不能直接訪(fǎng)問(wèn)數(shù)據(jù), Channel 只能與Buffer 進(jìn)行交互诗祸。

Java 為 Channel 接口提供的最主要實(shí)現(xiàn)類(lèi)
  • FileChannel:用于讀取跑芳、寫(xiě)入轴总、映射和操作文件的通道。
  • DatagramChannel:通過(guò) UDP 讀寫(xiě)網(wǎng)絡(luò)中的數(shù)據(jù)通道博个。
  • SocketChannel:通過(guò) TCP 讀寫(xiě)網(wǎng)絡(luò)中的數(shù)據(jù)怀樟。
  • ServerSocketChannel:可以監(jiān)聽(tīng)新進(jìn)來(lái)的 TCP 連接,對(duì)每一個(gè)新進(jìn)來(lái)的連接都會(huì)創(chuàng)建一個(gè) SocketChannel盆佣。
獲取通道

獲取通道的一種方式是對(duì)支持通道的對(duì)象調(diào)用getChannel() 方法往堡。支持通道的類(lèi)如下:

  • FileInputStream
  • FileOutputStream
  • RandomAccessFile
  • DatagramSocket
  • Socket
  • ServerSocket

獲取通道的其他方式是使用 Files 類(lèi)的靜態(tài)方法 newByteChannel() 獲取字節(jié)通道」菜#或者通過(guò)通道的靜態(tài)方法 open() 打開(kāi)并返回指定通道虑灰。

通道的數(shù)據(jù)傳輸
//通道用于源節(jié)點(diǎn)與目標(biāo)節(jié)點(diǎn)之間的連接,在NIO中負(fù)責(zé)緩沖區(qū)中數(shù)據(jù)的傳輸痹兜。
//Channel本身不存儲(chǔ)數(shù)據(jù)穆咐,需要配合緩沖區(qū)進(jìn)行數(shù)據(jù)傳輸
/**
 * 通道的主要實(shí)現(xiàn)類(lèi)
 * java.nio.channels.Channel接口
 *      |--FileChannel
 *      |--SocketChannel
 *      |--ServerSocketChannel
 *      |--DatagramChannel
 *
 * 獲取通道
 * 1.Java針對(duì)支持通道的類(lèi)提供了getChannel()方法
 *      本地IO:
 *          FileInputStream/FileOutputStream
 *          RandomAccessFile
 * 
 *      網(wǎng)絡(luò)IO:
 *          Socket
 *          ServerSocket
 *          DatagramSocket
 * 
 * 2.在JDK1.7中NIO.2針對(duì)各個(gè)通道提供了靜態(tài)方法open()
 * 3.在JDK1.7中NIO.2的Files工具類(lèi)的newByteChannel()
 */


public class TestChannel {
    //利用通道完成文件的復(fù)制(非直接緩沖區(qū))
    @Test
    public void test1() {
        //26088
        //6479
        //6587
        //6464
        long start = System.currentTimeMillis();
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            fileInputStream = new FileInputStream("E:\\BaiduYunDownload\\juc.zip");
            fileOutputStream = new FileOutputStream("F:\\juc_copy2.zip");
            //獲取通道
            inChannel = fileInputStream.getChannel();
            outChannel = fileOutputStream.getChannel();
            //分配指定大小的緩沖區(qū)
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //將通道中的數(shù)據(jù)存入緩沖區(qū)
            while (inChannel.read(buffer) != -1) {
                //切換成讀取數(shù)據(jù)模式
                buffer.flip();
                //將緩沖區(qū)中的數(shù)據(jù)寫(xiě)入通道中
                outChannel.write(buffer);
                //清空緩沖區(qū)
                buffer.clear();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            //關(guān)閉通道 省略if判斷
            outChannel.close();
            inChannel.close();
            //關(guān)閉流
            fileOutputStream.close();
            fileInputStream.close();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
    
    @Test
    public void test2() throws IOException {
        //1190
        //5144
        //5932
        //1316
        //1126
        //998
        //1242
        long start = System.currentTimeMillis();
        //使用直接緩沖區(qū)完成文件的復(fù)制(內(nèi)存映射文件)
        //只有ByteBuffer支持直接緩沖區(qū)
        FileChannel inChannel = FileChannel.open(Paths.get("E:\\BaiduYunDownload\\", "juc.zip"), StandardOpenOption.READ);
        //StandardOpenOption.CREATE_NEW若存在則報(bào)錯(cuò)
        //StandardOpenOption.CREATE若存在則覆蓋
        FileChannel outChannel = FileChannel.open(Paths.get("F:/", "juc-3.zip"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //內(nèi)存映射文件。緩沖區(qū)在物理內(nèi)存中字旭。
        MappedByteBuffer inMappedByteBuffer = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMappedByteBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
        
        //直接對(duì)緩沖區(qū)進(jìn)行數(shù)據(jù)讀寫(xiě)操作
        byte[] dst = new byte[inMappedByteBuffer.limit()];
        inMappedByteBuffer.get(dst);
        outMappedByteBuffer.put(dst);
        
        inChannel.close();
        outChannel.close();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
    
    @Test
    public void test3() throws IOException {
    //將數(shù)據(jù)從源通道傳輸?shù)狡渌?Channel 中
        //729
        //684
        //601
        //706
        //625
        long start = System.currentTimeMillis();
        FileChannel inChannel = FileChannel.open(Paths.get("E:\\BaiduYunDownload\\", "juc.zip"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("F:/", "juc-4.zip"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //通道之間的數(shù)據(jù)傳輸
        //inChannel.transferTo(0, inChannel.size(), outChannel);
        outChannel.transferFrom(inChannel, 0, inChannel.size());
        inChannel.close();
        outChannel.close();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
    
    @Test
    public void test4() throws IOException {
        RandomAccessFile randomAccessFile1 = new RandomAccessFile("E:/a.txt", "rw");
        //獲取通道
        FileChannel fileChannel1 = randomAccessFile1.getChannel();
        //分配指定大小的緩沖區(qū)
        ByteBuffer buffer1 = ByteBuffer.allocate(100);
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);
        //分散讀取,從 Channel 中讀取的數(shù)據(jù)“分散” 到多個(gè) Buffer 中
        ByteBuffer[] buffers = {buffer1, buffer2};
        fileChannel1.read(buffers);
        for (int i = 0; i < buffers.length; i++) {
            buffers[i].flip();
        }
        System.out.println(new String(buffers[0].array(), 0, buffers[0].limit()));
        System.out.println("-------------------");
        System.out.println(new String(buffers[1].array(), 0, buffers[1].limit()));
        //聚集寫(xiě)入,將多個(gè) Buffer 中的數(shù)據(jù)“聚集”到 Channel
        RandomAccessFile randomAccessFile2 = new RandomAccessFile("E:/b.txt", "rw");
        FileChannel fileChannel2 = randomAccessFile2.getChannel();
        fileChannel2.write(buffers);
    }
    
    @Test
    public void test5() {
        /**
         * 編碼:字符串->字節(jié)數(shù)組
         * 解碼:字節(jié)數(shù)組->字符串
         */
        //獲取所有支持的字符集
        SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
        Set<Entry<String, Charset>> set = availableCharsets.entrySet();
        for (Entry<String, Charset> entry: set) {
            System.out.println(entry.getKey() + "--" + entry.getValue());
        }
    }
    
    @Test
    public void test6() throws CharacterCodingException {
        Charset charset = Charset.forName("GBK");
        //編碼器
        CharsetEncoder charsetEncoder = charset.newEncoder();
        //解碼器
        CharsetDecoder charsetDecoder = charset.newDecoder();
        CharBuffer charBuffer = CharBuffer.allocate(1024);
        charBuffer.put("你好");
        charBuffer.flip();
        //編碼
        ByteBuffer byteBuffer = charsetEncoder.encode(charBuffer);
        
        for (int i = 0; i < 4; i++) {
            //字節(jié)數(shù)組
            System.out.println(byteBuffer.get());
        }
        //切換到讀模式
        byteBuffer.flip();
        //解碼
        CharBuffer charBuffer2 = charsetDecoder.decode(byteBuffer);
        System.out.println(charBuffer2.toString());
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末另假,一起剝皮案震驚了整個(gè)濱河市棚壁,隨后出現(xiàn)的幾起案子巍耗,更是在濱河造成了極大的恐慌令哟,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洲脂,死亡現(xiàn)場(chǎng)離奇詭異斤儿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)恐锦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)往果,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人一铅,你說(shuō)我怎么就攤上這事陕贮。” “怎么了潘飘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵肮之,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我卜录,道長(zhǎng)戈擒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任艰毒,我火速辦了婚禮筐高,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己柑土,他們只是感情好蜀肘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著稽屏,像睡著了一般扮宠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狐榔,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天坛增,我揣著相機(jī)與錄音,去河邊找鬼荒叼。 笑死轿偎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的被廓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼萝玷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嫁乘!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起球碉,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜓斧,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后睁冬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挎春,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年豆拨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了直奋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡施禾,死狀恐怖脚线,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弥搞,我是刑警寧澤邮绿,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站攀例,受9級(jí)特大地震影響船逮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粤铭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一挖胃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦冠骄、人聲如沸伪煤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抱既。三九已至,卻和暖如春扁誓,著一層夾襖步出監(jiān)牢的瞬間防泵,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蝗敢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捷泞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓寿谴,卻偏偏與公主長(zhǎng)得像锁右,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子讶泰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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