1. 소개
이 기사는 node.js 스트림을 사용하여 프로그램을 개발하는 기본 방법을 소개합니다.
<code> "우리는 정원 호스와 같은 프로그램을 연결하는 방법이 있어야합니다. 1964 년 10 월 11 일 </code>
스트림과 처음 접촉 한 것은 초기 유닉스에서 시작된 수십 년의 연습으로 스트림 아이디어가 단순히 거대한 시스템을 개발할 수 있음을 증명했습니다. 유닉스에서 스트림은 |; 노드에서는 내장 스트림 모듈로서 많은 코어 모듈과 3 자 모듈이 사용됩니다. UNIX와 마찬가지로 노드 스트림의 주요 작업은 .pipe ()이며, 사용자는 대책 메커니즘을 사용하여 읽기와 쓰기 간의 균형을 제어 할 수 있습니다.
스트림은 개발자에게 초록 스트림 인터페이스를 통해 스트림 간의 읽기 및 쓰기 균형을 재사용하고 제어 할 수있는 통합 인터페이스를 제공 할 수 있습니다.
2. 스트림을 사용하는 이유
노드의 I/O는 비동기식이므로 디스크 및 네트워크에 대한 읽기 및 쓰기에는 콜백 기능을 통해 데이터를 읽고 읽어야합니다. 다음은 파일 다운로드 서버의 간단한 코드입니다.
<code> var http = require ( 'http'); var fs = require ( 'fs'); var server = http.createserver (function (req, res) {fs. Readfile (__ dirname + '/data.txt', function (err, data) {res.end (data);}); Server.listen (8000);이 코드는 필요한 기능을 구현할 수 있지만 서비스는 파일 데이터를 보내기 전에 전체 파일 데이터를 메모리에 캐시해야합니다. "data.txt"파일이 크고 동시성이 크면 많은 메모리가 낭비됩니다. 파일 데이터를 수락하기 전에 전체 파일이 메모리로 캐시 될 때까지 사용자가 기다려야하므로 이는 매우 나쁜 사용자 경험으로 이어집니다. 다행스럽게도 두 매개 변수 (req, res)는 스트림이므로 fs.readfile () 대신 fs.createreadstream ()을 사용할 수 있습니다.
<code> var http = require ( 'http'); var fs = require ( 'fs'); var server = http.createserver (function (req, res) {var stream = fs.createreadstream (__ dirname + '/data.txt'); pipe (res); <</code.listen (8,000);.pipe () 메소드는 fs.createreadstream ()의 'data'및 'end'이벤트를 듣고 "data.txt"파일이 전체 파일을 캐시 할 필요가 없도록합니다. 클라이언트 연결이 완료되면 데이터 블록을 즉시 클라이언트로 전송할 수 있습니다. .pipe ()를 사용하는 또 다른 이점은 매우 큰 클라이언트 대기 시간으로 인한 읽기 및 쓰기 불균형을 해결할 수 있다는 것입니다. 파일을 압축하고 보내려면 3 자 모듈을 사용하여 구현할 수 있습니다.
<code> var http = require ( 'http'); var fs = require ( 'fs'); var 압제자 = 요구 ( '압제자'); var server = http.createserver (function (req, res) {var stream = fs.createreadstream (__ dirname + '/data.txt'); stream.pipe (압제자 (req)). 파이프 (res);}); server.listen (8000); </code>이런 식으로 파일은 GZIP 및 Deflate를 지원하는 브라우저를 압축합니다. 압제자 모듈은 모든 컨텐츠 인코딩을 처리합니다.
스트림은 개발 프로그램 개발을 간단하게 만듭니다.
3. 기본 개념
읽기 가능, 쓰기 가능, 변환, 이중 및 "클래식"의 5 가지 기본 스트림이 있습니다.
3-1, 파이프
모든 유형의 스트림을 사용하여 .pipe ()를 사용하여 입력 및 출력 쌍을 생성하고 읽기 쉬운 스트림 SRC를 수신하고 다음과 같이 데이터를 쓰기 쉬운 스트림 DST에 출력합니다.
<code> src.pipe (dst) </code>
.pipe (dst) 메소드는 DST 스트림을 반환하여 다음과 같이 다중 .pipe ()를 연속적으로 사용할 수 있도록합니다.
<code> a.pipe (b) .pipe (c) .pipe (d) </code>
함수는 다음 코드와 동일합니다.
<code> a.pipe (b); b.pipe (c); c.pipe (d); </code>
3-2. 읽기 쉬운 스트림
읽기 쉬운 스트림의 .pipe () 메소드를 호출하면 읽기 쉬운 스트림의 데이터를 쓰기 가능, 변환 또는 이중 스트림에 쓸 수 있습니다.
<code> readableStream.pipe (dst) </code>
1> 읽기 쉬운 스트림을 만듭니다
여기서 우리는 읽을 수있는 스트림을 만듭니다!
<code> var readable = require ( 'stream'). 읽기 가능; var rs = new readable; rs.push ( 'beep'); rs.push ( 'boop/n'); rs.push (null); rs.pipe (process.stdout); $ node read0.jsbeep boop </code>
Rs.Push (NULL)는 데이터 수신자에게 데이터가 전송되었음을 알립니다.
Rs.Pipe (Process.stdout)를 호출하지 않았습니다. 모든 데이터를 읽을 수있는 스트림으로 푸시하기 전에 읽기 쉬운 스트림은 수신기가 데이터를 읽기 전에 모든 누름 데이터를 캐시하기 때문에 모든 데이터가 읽을 수있는 스트림으로 완전히 출력됩니다. 그러나 많은 경우에 더 좋은 방법은 데이터가 전체 데이터를 캐시 대신 요청 된 데이터를 수신 할 때 데이터를 읽을 수있는 스트림으로 만 누르는 것입니다. 아래 ._READ () 함수를 다시 작성해 봅시다.
<code> var readable = requible ( 'stream'). readable; var rs = readable (); var c = 97; rs._read = function () {rs.push (string.fromcharcode (c ++)); if (c> 'z'.charcodeat (0)) rs.push (null); rs.stdout (code.stdout); read1.jsabcdefghijklmnopqrstuvwxyz </code>위의 코드는 데이터 수신자가 데이터를 요청하는 경우에만 데이터를 읽을 수있는 스트림으로 푸시하기 위해 _READ () 메소드의 재 작성을 구현합니다. _READ () 메소드는 데이터의 요청 된 데이터 크기를 나타내는 크기 매개 변수를받을 수 있지만 읽기 쉬운 스트림은 필요에 따라이 매개 변수를 무시할 수 있습니다.
util.inherits ()를 사용하여 읽기 쉬운 스트림을 상속 할 수도 있습니다. _READ () 메소드가 데이터 수신자가 데이터를 요청할 때만 호출되는 것을 설명하기 위해 다음과 같이 읽기 쉬운 스트림으로 데이터를 푸시 할 때 지연됩니다.
<code> var readable = requible ( 'stream'). readable; var rs = readable (); var c = 97-1; rs._read = function () {if (c> = 'z'.charcodeat (0)) return rs.push (null); settimeout (function () {rs.push (string.fromchode (++ c)); 100);}; rs.pipe (process.stdout); process.on ( 'exit', function () {console.error ( '/n_read (') '' + (c -97) + 'times'); access.stdout.on ( 'error', process.exit); </code>다음 명령으로 프로그램을 실행할 때 _Read () 메소드가 5 번만 호출된다는 것을 발견했습니다.
<code> $ 노드 read2.js | HEAD -C5ABCDE_READ () 5 회 </code>
타이머를 사용하는 이유는 시스템이 신호를 보내서 프로그램에 파이프 라인을 닫으려는 정보를 보내는 데 시간이 걸리기 때문입니다. Process.stdout.on ( 'Error', FN)을 사용하여 SIGPIPE 신호를 보내는 시스템을 처리하려면 헤더 명령이 파이프 라인을 닫으므로 Process.Stdout이 Epipe 이벤트를 트리거하기 때문에 SIGPIPE 신호를 보내십시오. 모든 형태의 데이터로 누를 수있는 읽기 쉬운 스트림을 만들려면 스트림을 만들 때 파라미터 객체 모드를 true로 설정하기 만하면됩니다 ({objectMode : true}).
2> 읽을 수있는 스트림 데이터
대부분의 경우 파이프 방법을 사용하여 읽기 가능한 스트림의 데이터를 다른 형태의 스트림으로 리디렉션하지만 경우에 따라 읽기 쉬운 스트림에서 데이터를 직접 읽는 것이 더 유용 할 수 있습니다. 다음과 같이 :
<code> process.stdin.on ( 'readable', function () {var buf = process.stdin.read (); console.dir (buf);}); $ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | 노드 소비 0.js <buffer 0a = ""61 = ""63 = ""> <버퍼 0a = "64 ="64 = ""65 = ""66 = ""> <buffer 0a = ""67 = ""68 = "68 ="69 = "> null </buffer> </code> </code>읽기 쉬운 스트림에서 읽을 데이터가 있으면 스트림이 '읽기 쉬운'이벤트를 트리거하여 .read () 메소드를 호출하여 관련 데이터를 읽을 수 있습니다. 읽을 수있는 스트림에서 읽을 데이터가 없으면 .read ()가 null을 반환하여 .read ()의 호출을 종료하고 다음 '읽기 가능한'이벤트가 트리거 될 때까지 기다릴 수 있습니다. 다음은 표준 입력에서 매번 .read (n)을 사용하여 3 바이트를 읽는 예입니다.
<code> process.stdin.on ( 'readable', function () {var buf = process.stdin.read (3); console.dir (buf);}); </code>다음과 같이 프로그램을 실행하면 출력 결과가 완료되지 않았 음을 보여줍니다!
<code> $ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | 노드 소비 1.js <버퍼 61 = "62 ="62 = "63 =" "> <버퍼 0a ="64 = ""65 = ""> <buffer 0a = ""66 = ""67 = ""> </buffer> </buffer> </buffer> </code>
이는 추가 데이터가 스트림의 내부 버퍼에 남겨 두려면 수행해야하며 스트림에 더 많은 데이터를 읽으려는 것을 알려야합니다. 읽기 (0)은 이것을 달성 할 수 있습니다.
<code> process.stdin.on ( 'readable', function () {var buf = process.stdin.read (3); console.dir (buf); process.stdin.read (0);}); </code>이 실행 결과는 다음과 같습니다.
<code> $ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | Node Sopcomption2.js <buffer 0a = ""64 = ""65 = "" "> <buffer 0a =" "68 =" "69 =" "> </buffer> </buffer> </code>
.unshift ()를 사용하여 스트리밍 데이터 큐의 헤드로 데이터를 다시 크기를 조정하여 스테이크 데이터를 계속 읽을 수 있습니다. 다음 코드에서와 같이 표준 입력 컨텐츠는 라인별로 출력됩니다.
<code> var offset = 0; process.stdin.on ( 'readable', function () {var buf = process.stdin.read (); if (! buf) return; for (; offset <buf.length; offset ++) {if (buf [offset] == 0x0a) {console.dir (buf.slice (0, offset)); buf.slice (오프셋 + 1); 오프셋 = 0; process.stdin.unshift (buf); return;}} process.stdin.unshift (buf);}); $ tail -n +50000/usr/share/dict/American -English | 헤드 -n10 | Node lines.js 'hearties''hearties'heartily'heartiness'heartiness'heartiness'heartiness/'s'''Heartland'Heartland/'S''Heartlands'Heartless'Heartless'</code>물론 분할과 같은이 기능을 구현할 수있는 많은 모듈이 있습니다.
3-3. 쓰기 가능한 스트림
쓰기 가능한 스트림은 .pipe () 함수의 대상 매개 변수로만 사용할 수 있습니다. 다음 코드 :
<code> src.pipe (WritableStream); </code>
1> 쓰기 가능한 스트림을 만듭니다
읽을 수있는 스트림에서 데이터를 수락하기 위해 ._write (Chunk, Enc, Next) 메소드를 다시 작성하십시오.
<code> var writable = require ( 'stream'). 쓰기 가능; var ws = writable (); ws._write = function (chunk, enc, next) {console.dir (chunk); next ();}; process.stdin.pipe (ws); $ (echo beep; sleep 1; echo boop) | Node write0.js <buffer 0a = ""62 = ""65 = ""70 = ""> <buffer 0a = "62 =" "6f =" "70 =" "> </buffer> </code>첫 번째 매개 변수 청크는 Data Inputer가 작성한 데이터입니다. 두 번째 매개 변수 끝은 데이터의 인코딩 형식입니다. 세 번째 매개 변수 다음 (ERR)은 콜백 함수를 통해 더 많은 시간을 쓸 수 있음을 알립니다. 읽기 쉬운 스트림이 문자열을 쓰면 문자열이 기본적으로 버퍼로 변환됩니다. 스트림을 만들 때 쓸 수있는 ({decodestrings : false}) 매개 변수가 설정되면 변환이 수행되지 않습니다. 데이터가 읽기 쉬운 스트림에 의해 작성되면이 방법으로 쓰기 가능한 스트림을 만들어야합니다.
<code> 쓰기 가능 ({ObjectMode : True}) </code>2> 쓰기 가능한 스트림에 데이터를 쓰십시오
데이터 작성을 완료하려면 .write (data) 메소드의 쓰기 가능한 스트림 방법을 호출하십시오.
<code> process.stdout.write ( 'beep boop/n'); </code>
.end () 메소드를 호출하면 데이터가 작성된 쓰기 스트림을 알 수 있습니다.
<code> var fs = require ( 'fs'); var ws = fs.createWritestream ( 'message.txt'); ws.write ( 'beep'); settimeout (function () {ws.end ( 'boop/n');}, 1000); $ node writing1.js $ cat message.txtep boo </code>쓰기 가능한 스트림의 버퍼 크기를 설정 해야하는 경우 스트림을 만들 때 Opts.HighWaterMark를 설정하여 버퍼의 데이터가 Opts.HighWaterMark를 초과하면 .water (data) 메소드가 False를 반환합니다. 버퍼가 쓸 수 있으면 쓰기 가능한 스트림이 '배수'이벤트를 트리거합니다.
3-4. 클래식 스트림
Classic Streams는 오래된 인터페이스로 Node 0.4 버전으로 처음 나타 났지만 작동 원리를 이해하는 것이 여전히 좋습니다.
어디. 스트림이 "데이터"이벤트에 함수로 다시 등록되면 스트림은 이전 버전 모드에서 작동합니다. 즉, 이전 API가 사용됩니다.
1> 클래식 읽기 쉬운 스트림
클래식 읽기 쉬운 스트림 이벤트는 이벤트 트리거입니다. 클래식 읽기 쉬운 스트림에 데이터를 읽을 수있는 경우 "데이터"이벤트가 트리거됩니다. 데이터를 읽으면 "END"이벤트가 트리거됩니다. .pipe () 메소드는 스트림에 스트림 값을 확인하여 스트림에 읽을 데이터가 있는지 여부를 결정합니다. 다음은 클래식 읽기 가능한 스트림을 사용하여 AJ 문자를 인쇄하는 예입니다.
<code> var stream = 요구 ( 'stream'); var stream = new Stream; stream.Readable = true; var c = 64; var iv = setInterVal (function () {if (++ c> = 75) {clearInterVal (iv; stream.emit ( 'end');} else stream.emit ( 'data', string.friptd (c);};};};};}; Node Classic0.jsabcdefghij </code>클래식 읽기 가능한 스트림에서 데이터를 읽으려면 두 이벤트 "데이터"및 "END"이벤트의 콜백 기능을 등록하면 코드는 다음과 같습니다.
<code> process.stdin.on ( 'data', function (buf) {console.log (buf);}); process.stdin.on ( 'end', function () {console.log ( '__ end __');}); $ (echo beep; sleep 1; etecho boop) | Node Classic1.js <buffer 0a = ""62 = ""65 = ""70 = ""> <buffer 0a = "62 =" "6f =" "70 =" "> __ end __ </buffer> </code>이 방법을 사용하여 데이터를 읽으면 새 인터페이스 사용의 이점을 잃게됩니다. 예를 들어, 대기 시간이 매우 높은 스트림에 데이터를 작성할 때 데이터를 읽고 데이터를 읽는 것 사이의 균형에주의를 기울여야합니다. 그렇지 않으면 많은 양의 데이터가 메모리에 캐싱되어 많은 메모리를 낭비하게됩니다. 일반적으로 스트림의 .pipe () 메소드를 사용하는 것이 좋습니다. 따라서 "데이터"및 "종료"이벤트를 직접들을 필요가 없으며 불균형 읽기 및 쓰기 문제에 대해 걱정할 필요가 없습니다. 물론 다음 코드와 같은 "데이터"및 "END"이벤트를 듣는 대신 사용할 수도 있습니다.
<code> var toash = require ( 'throw'); process.stdin.pipe (work (write, end)); function write (buf) {console.log (buf);} function end () {console.log ( '__ end __');} $ (echo beep; sleep 1; echo boop) | Node through.js <buffer 0a = ""62 = ""65 = ""70 = ""> <buffer 0a = ""62 = ""6f = ""70 = ""> __ end __ </buffer> </code>또는 Concat-Stream을 사용하여 전체 스트림의 내용을 캐시 할 수도 있습니다.
<code> var concat = require ( 'concat-stream'); process.stdin.pipe (concat (body) {console.log (json.parse (body));}); $ echo '{ "beep": "boop"}'| node concat.js {beep : 'boop'} </code>물론, "데이터"및 "종료"이벤트를 직접 들어야하는 경우 .pause () 메소드를 사용하여 클래식 읽기 가능한 스트림을 일시 중지하고 쓰기 데이터 스트림을 쓰지 않을 때 "데이터"이벤트를 계속 트리거 할 수 있습니다. .Resume () 메서드를 사용하기 전에 스트림 쓰기 데이터가 쓸 수있을 때까지 기다리십시오. 스트림에 계속 읽기 위해 "데이터"이벤트를 계속 트리거하도록 알립니다.
데이터.
2> 클래식 쓰기 가능한 스트림
클래식 쓰기 가능한 스트림은 매우 간단합니다. .write (buf), .end (buf) 및 .destroy ()의 세 가지 방법 만 있습니다. .end (BUF) 메소드의 BUF 매개 변수는 선택 사항입니다. 이 매개 변수를 선택하면 stream.write (buf)와 같습니다. stream.end (). 스트림의 버퍼가 가득 차면 스트림을 쓸 수 없습니다. WRITE (BUF) 메소드는 False를 반환합니다. 스트림이 다시 쓸 수 있으면 스트림이 드레인 이벤트를 트리거합니다.
4. 변환
변환은 읽기 데이터의 출력을 필터링하는 스트림입니다.
5. 이중
이중 스트림은 읽을 수 있거나 쓸 수있는 양방향 스트림입니다. 예를 들어 아래는 이중 스트림입니다.
<code> a.pipe (b) .pipe (a) </code>
위의 내용은 편집자가 소개 한 Nodejs 스트림 데이터 흐름 사용자 설명서입니다. 나는 그것이 당신에게 도움이되기를 바랍니다!