Node核心模塊(1):Buffer

## 模塊概覽

Buffer是node的核心模塊且预,開發(fā)者可以利用它來(lái)處理二進(jìn)制數(shù)據(jù)槽袄,比如文件流的讀寫、網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)的處理等锋谐。

Buffer的API非常多遍尺,本文僅挑選 比較常用/容易理解 的API進(jìn)行講解,包括Buffer實(shí)例的創(chuàng)建涮拗、比較狮鸭、連接、拷貝多搀、查找歧蕉、遍歷、類型轉(zhuǎn)換康铭、截取惯退、編碼轉(zhuǎn)換等。

WritableReadable 流都會(huì)將數(shù)據(jù)存儲(chǔ)到內(nèi)部的緩存(buffer)中从藤。這些緩存可以 通過(guò)相應(yīng)的 writable._writableState.getBuffer() 或 readable._readableState.buffer來(lái)獲取催跪。
緩存的大小取決于傳遞給流構(gòu)造函數(shù)的 highWaterMark選項(xiàng)。 對(duì)于普通的流夷野, highWaterMark 選項(xiàng)指定了總共的字節(jié)數(shù)懊蒸。對(duì)于工作在對(duì)象模式的流, highWaterMark 指定了對(duì)象的總數(shù)悯搔。當(dāng)可讀流的實(shí)現(xiàn)調(diào)用 stream.push(chunk) 方法時(shí)骑丸,數(shù)據(jù)被放到緩存中。如果流的消費(fèi)者 沒有調(diào)用 stream.read() 方法妒貌, 這些數(shù)據(jù)會(huì)始終存在于內(nèi)部隊(duì)列中通危,直到被消費(fèi)。
當(dāng)內(nèi)部可讀緩存的大小達(dá)到 highWaterMark指定的閾值時(shí)灌曙,流會(huì)暫停從底層資源讀取數(shù)據(jù)菊碟,直到當(dāng)前 緩存的數(shù)據(jù)被消費(fèi) (也就是說(shuō), 流會(huì)在內(nèi)部停止調(diào)用 readable._read()來(lái)填充可讀緩存)在刺∧婧Γ可寫流通過(guò)反復(fù)調(diào)用 writable.write(chunk) 方法將數(shù)據(jù)放到緩存头镊。 當(dāng)內(nèi)部可寫緩存的總大小小于 highWaterMark 指定的閾值時(shí), 調(diào)用 writable.write() 將返回true魄幕。 一旦內(nèi)部緩存的大小達(dá)到或超過(guò) highWaterMark 相艇,調(diào)用 writable.write() 將返回 false。
stream API 的關(guān)鍵目標(biāo)梅垄, 尤其對(duì)于 stream.pipe() 方法, 就是限制緩存數(shù)據(jù)大小输玷,以達(dá)到可接受的程度队丝。這樣,對(duì)于讀寫速度不匹配的源頭和目標(biāo)欲鹏,就不會(huì)超出可用的內(nèi)存大小机久。DuplexTransform 都是可讀寫的。 在內(nèi)部赔嚎,它們都維護(hù)了 兩個(gè) 相互獨(dú)立的緩存用于讀和寫膘盖。 在維持了合理高效的數(shù)據(jù)流的同時(shí),也使得對(duì)于讀和寫可以獨(dú)立進(jìn)行而互不影響尤误。 例如侠畔, net.Socket 就是 Duplex 的實(shí)例,它的可讀端可以消費(fèi)從套接字(socket)中接收的數(shù)據(jù)损晤, 可寫端則可以將數(shù)據(jù)寫入到套接字软棺。 由于數(shù)據(jù)寫入到套接字中的速度可能比從套接字接收數(shù)據(jù)的速度快或者慢, 在讀寫兩端使用獨(dú)立緩存尤勋,并進(jìn)行獨(dú)立操作就顯得很重要了喘落。

創(chuàng)建

  • new Buffer(array)
  • Buffer.alloc(length)
  • Buffer.allocUnsafe(length)
  • Buffer.from(array)

通過(guò) new Buffer(array)

// Creates a new Buffer containing the ASCII bytes of the string 'buffer'
const buf = new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);

驗(yàn)證下:

var array = 'buffer'.split('').map(function(v){
    return '0x' + v.charCodeAt(0).toString(16)
});

console.log( array.join() );
// 輸出:0x62,0x75,0x66,0x66,0x65,0x72

通過(guò) Buffer.alloc(length)

var buf1 = Buffer.alloc(10);  // 長(zhǎng)度為10的buffer,初始值為0x0
var buf2 = Buffer.alloc(10, 1);  // 長(zhǎng)度為10的buffer最冰,初始值為0x1
var buf3 = Buffer.allocUnsafe(10);  // 長(zhǎng)度為10的buffer瘦棋,初始值不確定
var buf4 = Buffer.from([1, 2, 3])  // 長(zhǎng)度為3的buffer,初始值為 0x01, 0x02, 0x03

通過(guò)Buffer.from()

例子一:Buffer.from(array)

// [0x62, 0x75, 0x66, 0x66, 0x65, 0x72] 為字符串 "buffer" 
// 0x62 為16進(jìn)制暖哨,轉(zhuǎn)成十進(jìn)制就是 98赌朋,代表的就是字母 b
var buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
console.log(buf.toString());

例子二:Buffer.from(string[, encoding])

通過(guò)string創(chuàng)建buffer,跟將buffer轉(zhuǎn)成字符串時(shí)篇裁,記得編碼保持一致箕慧,不然會(huì)出現(xiàn)亂碼,如下所示茴恰。

var buf = Buffer.from('this is a tést');  // 默認(rèn)采用utf8

// 輸出:this is a tést
console.log(buf.toString());  // 默認(rèn)編碼是utf8颠焦,所以正常打印

// 輸出:this is a tC)st
console.log(buf.toString('ascii'));  // 轉(zhuǎn)成字符串時(shí),編碼不是utf8往枣,所以亂碼

對(duì)亂碼的分析如下:

var letter = 'é';
var buff = Buffer.from(letter);  // 默認(rèn)編碼是utf8伐庭,這里占據(jù)兩個(gè)字節(jié) <Buffer c3 a9>
var len = buff.length;  // 2
var code = buff[0]; // 第一個(gè)字節(jié)為0xc3粉渠,即195:超出ascii的最大支持范圍
var binary = code.toString(2);  // 195的二進(jìn)制:10101001
var finalBinary = binary.slice(1);  // 將高位的1舍棄,變成:0101001
var finalCode = parseInt(finalBinary, 2);  // 0101001 對(duì)應(yīng)的十進(jìn)制:67
var finalLetter = String.fromCharCode(finalCode);  // 67對(duì)應(yīng)的字符:C

// 同理 0xa9最終轉(zhuǎn)成的ascii字符為)
// 所以圾另,最終輸出為 this is a tC)st

例子三:Buffer.from(buffer)

創(chuàng)建新的Buffer實(shí)例霸株,并將buffer的數(shù)據(jù)拷貝到新的實(shí)例子中去。

var buff = Buffer.from('buffer');
var buff2 = Buffer.from(buff);

console.log(buff.toString());  // 輸出:buffer
console.log(buff2.toString());  // 輸出:buffer

buff2[0] = 0x61;

console.log(buff.toString());  // 輸出:buffer
console.log(buff2.toString());  // 輸出:auffer

buffer比較

buf.equals(otherBuffer)

判斷兩個(gè)buffer實(shí)例存儲(chǔ)的數(shù)據(jù)是否相同集乔,如果是去件,返回true,否則返回false扰路。

// 例子一:編碼一樣尤溜,內(nèi)容相同
var buf1 = Buffer.from('A');
var buf2 = Buffer.from('A');

console.log( buf1.equals(buf2) );  // true

// 例子二:編碼一樣,內(nèi)容不同
var buf3 = Buffer.from('A');
var buf4 = Buffer.from('B');

console.log( buf3.equals(buf4) );  // false

// 例子三:編碼不一樣汗唱,內(nèi)容相同
var buf5 = Buffer.from('ABC');  // <Buffer 41 42 43>
var buf6 = Buffer.from('414243', 'hex');

console.log(buf5.equals(buf6));

buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])

同樣是對(duì)兩個(gè)buffer實(shí)例進(jìn)行比較宫莱,不同的是:

  1. 可以指定特定比較的范圍(通過(guò)start、end指定)
  2. 返回值為整數(shù)哩罪,達(dá)標(biāo)buf授霸、target的大小關(guān)系

假設(shè)返回值為

  • 0:buf、target大小相同际插。
  • 1:buf大于target碘耳,也就是說(shuō)buf應(yīng)該排在target之后。
  • -1:buf小于target框弛,也就是說(shuō)buf應(yīng)該排在target之前藏畅。

看例子,官方的例子挺好的功咒,直接貼一下:

const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');

// Prints: 0
console.log(buf1.compare(buf1));

// Prints: -1
console.log(buf1.compare(buf2));

// Prints: -1
console.log(buf1.compare(buf3));

// Prints: 1
console.log(buf2.compare(buf1));

// Prints: 1
console.log(buf2.compare(buf3));

// Prints: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
// (This result is equal to: [buf1, buf3, buf2])
console.log([buf1, buf2, buf3].sort(Buffer.compare));

Buffer.compare(buf1, buf2)

buf.compare(target) 大同小異愉阎,一般用于排序。直接貼官方例子:

const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');
const arr = [buf1, buf2];

// Prints: [ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]
// (This result is equal to: [buf2, buf1])
console.log(arr.sort(Buffer.compare));

從Buffer.from([62])談起

這里稍微研究下Buffer.from(array)力奋。下面是官方文檔對(duì)API的說(shuō)明榜旦,也就是說(shuō),每個(gè)array的元素對(duì)應(yīng)1個(gè)字節(jié)(8位)景殷,取值從0到255溅呢。

Allocates a new Buffer using an array of octets.

數(shù)組元素為數(shù)字

首先看下,傳入的元素為數(shù)字的場(chǎng)景猿挚。下面分別是10進(jìn)制咐旧、8進(jìn)制、16進(jìn)制绩蜻,跟預(yù)期中的結(jié)果一致铣墨。

var buff = Buffer.from([62])
// <Buffer 3e>
// buff[0] === parseInt('3e', 16) === 62
var buff = Buffer.from([062])
// <Buffer 32>
// buff[0] === parseInt(62, 8) === parseInt(32, 16) === 50
var buff = Buffer.from([0x62])
// <Buffer 62>
// buff[0] === parseInt(62, 16) === 98

數(shù)組元素為字符串

再看下,傳入的元素為字符串的場(chǎng)景办绝。

  1. 0開頭的字符串伊约,在parseInt('062')時(shí)姚淆,可以解釋為62,也可以解釋為50(八進(jìn)制)屡律,這里看到采用了第一種解釋腌逢。
  2. 字符串的場(chǎng)景,跟parseInt()有沒有關(guān)系超埋,暫未深入探究搏讶,只是這樣猜想。TODO(找時(shí)間研究下)
var buff = Buffer.from(['62'])
// <Buffer 3e>
// buff[0] === parseInt('3e', 16) === parseInt('62') === 62
var buff = Buffer.from(['062'])
// <Buffer 3e>
// buff[0] === parseInt('3e', 16) === parseInt('062') === 62
var buff = Buffer.from(['0x62'])
// <Buffer 62>
// buff[0] === parseInt('62', 16) === parseInt('0x62') === 98

數(shù)組元素大小超出1個(gè)字節(jié)

感興趣的同學(xué)自行探究霍殴。

var buff = Buffer.from([256])
// <Buffer 00>

Buffer.from('1')

一開始不自覺的會(huì)將Buffer.from('1')[0]"1"劃等號(hào)媒惕,其實(shí)"1"對(duì)應(yīng)的編碼是49。

var buff = Buffer.from('1')  // <Buffer 31>
console.log(buff[0] === 1)  // false

這樣對(duì)比就知道了繁成,編碼為1的是個(gè)控制字符吓笙,表示 Start of Heading淑玫。

console.log( String.fromCharCode(49) )  // '1'
console.log( String.fromCharCode(1) )  // '\u0001'

buffer連接:Buffer.concat(list[, totalLength])

備注:個(gè)人覺得totalLength這個(gè)參數(shù)挺多余的巾腕,從官方文檔來(lái)看,是處于性能提升的角度考慮絮蒿。不過(guò)內(nèi)部實(shí)現(xiàn)也只是遍歷list尊搬,將length累加得到totalLength,從這點(diǎn)來(lái)看土涝,性能優(yōu)化是幾乎可以忽略不計(jì)的佛寿。

var buff1 = Buffer.alloc(10);
var buff2 = Buffer.alloc(20);

var totalLength = buff1.length + buff2.length;

console.log(totalLength);  // 30

var buff3 = Buffer.concat([buff1, buff2], totalLength);

console.log(buff3.length);  // 30

除了上面提到的性能優(yōu)化,totalLength還有兩點(diǎn)需要注意但壮。假設(shè)list里面所有buffer的長(zhǎng)度累加和為length

  • totalLength > length:返回長(zhǎng)度為totalLength的Buffer實(shí)例冀泻,超出長(zhǎng)度的部分填充0。
  • totalLength < length:返回長(zhǎng)度為totalLength的Buffer實(shí)例蜡饵,后面部分舍棄弹渔。
var buff4 = Buffer.from([1, 2]);
var buff5 = Buffer.from([3, 4]);

var buff6 = Buffer.concat([buff4, buff5], 5);

console.log(buff6.length);  // 
console.log(buff6);  // <Buffer 01 02 03 04 00>

var buff7 = Buffer.concat([buff4, buff5], 3);

console.log(buff7.length);  // 3
console.log(buff7);  // <Buffer 01 02 03>

拷貝:buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

使用比較簡(jiǎn)單,如果忽略后面三個(gè)參數(shù)溯祸,那就是將buf的數(shù)據(jù)拷貝到target里去肢专,如下所示:

var buff1 = Buffer.from([1, 2]);
var buff2 = Buffer.alloc(2);

buff1.copy(buff2);

console.log(buff2);  // <Buffer 01 02>

另外三個(gè)參數(shù)比較直觀,直接看官方例子

const buf1 = Buffer.allocUnsafe(26);
const buf2 = Buffer.allocUnsafe(26).fill('!');

for (let i = 0 ; i < 26 ; i++) {
  // 97 is the decimal ASCII value for 'a'
  buf1[i] = i + 97;
}

buf1.copy(buf2, 8, 16, 20);

// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
console.log(buf2.toString('ascii', 0, 25));

查找:buf.indexOf(value[, byteOffset][, encoding])

跟數(shù)組的查找差不多焦辅,需要注意的是博杖,value可能是String、Buffer筷登、Integer中的任意類型剃根。

  • String:如果是字符串,那么encoding就是其對(duì)應(yīng)的編碼前方,默認(rèn)是utf8跟继。
  • Buffer:如果是Buffer實(shí)例种冬,那么會(huì)將value中的完整數(shù)據(jù),跟buf進(jìn)行對(duì)比舔糖。
  • Integer:如果是數(shù)字娱两,那么value會(huì)被當(dāng)做無(wú)符號(hào)的8位整數(shù),取值范圍是0到255金吗。

另外十兢,可以通過(guò)byteOffset來(lái)指定起始查找位置。

直接上代碼摇庙,官方例子妥妥的旱物,耐心看完它基本就理解得差不多了。

const buf = Buffer.from('this is a buffer');

// Prints: 0
console.log(buf.indexOf('this'));

// Prints: 2
console.log(buf.indexOf('is'));

// Prints: 8
console.log(buf.indexOf(Buffer.from('a buffer')));

// Prints: 8
// (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(97));

// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example')));

// Prints: 8
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));


const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');

// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));

// Prints: 6
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));

寫:buf.write(string[, offset[, length]][, encoding])

將sring寫入buf實(shí)例卫袒,同時(shí)返回寫入的字節(jié)數(shù)宵呛。

參數(shù)如下:

  • string:寫入的字符串。
  • offset:從buf的第幾位開始寫入夕凝,默認(rèn)是0宝穗。
  • length:寫入多少個(gè)字節(jié),默認(rèn)是 buf.length - offset码秉。
  • encoding:字符串的編碼逮矛,默認(rèn)是utf8。

看個(gè)簡(jiǎn)單例子

var buff = Buffer.alloc(4);
buff.write('a');  // 返回 1
console.log(buff);  // 打印 <Buffer 61 00 00 00>

buff.write('ab');  // 返回 2
console.log(buff);  // 打印 <Buffer 61 62 00 00>

填充:buf.fill(value[, offset[, end]][, encoding])

value填充buf转砖,常用于初始化buf须鼎。參數(shù)說(shuō)明如下:

  • value:用來(lái)填充的內(nèi)容,可以是Buffer府蔗、String或Integer晋控。
  • offset:從第幾位開始填充,默認(rèn)是0姓赤。
  • end:停止填充的位置赡译,默認(rèn)是 buf.length。
  • encoding:如果value是String模捂,那么為value的編碼捶朵,默認(rèn)是utf8。

例子:

var buff = Buffer.alloc(20).fill('a');

console.log(buff.toString());  // aaaaaaaaaaaaaaaaaaaa

轉(zhuǎn)成字符串: buf.toString([encoding[, start[, end]]])

把buf解碼成字符串狂男,用法比較直觀综看,看例子

var buff = Buffer.from('hello');

console.log( buff.toString() );  // hello

console.log( buff.toString('utf8', 0, 2) );  // he

轉(zhuǎn)成JSON字符串:buf.toJSON()

var buff = Buffer.from('hello');

console.log( buff.toJSON() );  // { type: 'Buffer', data: [ 104, 101, 108, 108, 111 ] }

遍歷:buf.values()、buf.keys()岖食、buf.entries()

用于對(duì)buf進(jìn)行for...of遍歷红碑,直接看例子。

var buff = Buffer.from('abcde');

for(const key of buff.keys()){
    console.log('key is %d', key);
}
// key is 0
// key is 1
// key is 2
// key is 3
// key is 4

for(const value of buff.values()){
    console.log('value is %d', value);
}
// value is 97
// value is 98
// value is 99
// value is 100
// value is 101

for(const pair of buff.entries()){
    console.log('buff[%d] === %d', pair[0], pair[1]);
}
// buff[0] === 97
// buff[1] === 98
// buff[2] === 99
// buff[3] === 100
// buff[4] === 101

截取:buf.slice([start[, end]])

用于截取buf析珊,并返回一個(gè)新的Buffer實(shí)例羡鸥。需要注意的是忠寻,這里返回的Buffer實(shí)例,指向的仍然是buf的內(nèi)存地址奕剃,所以對(duì)新Buffer實(shí)例的修改,也會(huì)影響到buf纵朋。

var buff1 = Buffer.from('abcde');
console.log(buff1);  // <Buffer 61 62 63 64 65>

var buff2 = buff1.slice();
console.log(buff2);  // <Buffer 61 62 63 64 65>

var buff3 = buff1.slice(1, 3);
console.log(buff3);  // <Buffer 62 63>

buff3[0] = 97;  // parseInt(61, 16) ==> 97
console.log(buff1);  // <Buffer 62 63>

TODO

  1. 創(chuàng)建、拷貝操软、截取、轉(zhuǎn)換聂薪、查找
  2. buffer、arraybuffer胆建、dataview肘交、typedarray
  3. buffer vs 編碼
  4. Buffer.from()笆载、Buffer.alloc()凉驻、Buffer.alocUnsafe()
  5. Buffer vs TypedArray

文檔摘要

關(guān)于buffer內(nèi)存空間的動(dòng)態(tài)分配

Instances of the Buffer class are similar to arrays of integers but correspond to fixed-sized, raw memory allocations outside the V8 heap. The size of the Buffer is established when it is created and cannot be resized.

相關(guān)鏈接

unicode對(duì)照表
https://unicode-table.com/cn/#control-character

字符編碼筆記:ASCII,Unicode和UTF-8
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涝登,一起剝皮案震驚了整個(gè)濱河市效诅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乱投,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戚炫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)钮惠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)七芭,“玉大人素挽,你說(shuō)我怎么就攤上這事±瓴担” “怎么了毁菱?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)锌历。 經(jīng)常有香客問(wèn)我贮庞,道長(zhǎng),這世上最難降的妖魔是什么究西? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任窗慎,我火速辦了婚禮,結(jié)果婚禮上卤材,老公的妹妹穿的比我還像新娘遮斥。我一直安慰自己如迟,他們只是感情好占键,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著情萤,像睡著了一般帆精。 火紅的嫁衣襯著肌膚如雪较屿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天卓练,我揣著相機(jī)與錄音隘蝎,去河邊找鬼。 笑死襟企,一個(gè)胖子當(dāng)著我的面吹牛嘱么,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽悼,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼曼振,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蔚龙?” 一聲冷哼從身側(cè)響起冰评,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎府蛇,沒想到半個(gè)月后集索,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年妆距,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娱据。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盅惜。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡结啼,死狀恐怖屈芜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情属铁,我是刑警寧澤焦蘑,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布例嘱,位于F島的核電站蝶防,受9級(jí)特大地震影響明吩,放射性物質(zhì)發(fā)生泄漏印荔。R本人自食惡果不足惜详羡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一实柠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧草则,春花似錦、人聲如沸源内。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至焚鲜,卻和暖如春忿磅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葱她。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工吨些, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豪墅,地道東北人黔寇。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓缝裤,卻偏偏與公主長(zhǎng)得像憋飞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子榛做,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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

  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測(cè)試 ...
    KeKeMars閱讀 6,340評(píng)論 0 6
  • Node.js Buffer(緩沖區(qū)) JavaScript 語(yǔ)言自身只有字符串?dāng)?shù)據(jù)類型答倡,沒有二進(jìn)制數(shù)據(jù)類型驴党。但在...
    FTOLsXD閱讀 520評(píng)論 0 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理港庄,服務(wù)發(fā)現(xiàn),斷路器渤涌,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法实蓬,類相關(guān)的語(yǔ)法吊履,內(nèi)部類的語(yǔ)法艇炎,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法居砖,線程的語(yǔ)...
    子非魚_t_閱讀 31,665評(píng)論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,815評(píng)論 0 11