1. 개방 분석
스트림은 노드의 많은 객체에서 구현 한 추상 인터페이스입니다. 예를 들어, HTTP 서버에 대한 요청은 스트림이며 stdout도 스트림입니다. 스트림은 읽을 수 있거나 쓰기 가능합니다.
스트림과의 첫 접촉은 초기 유닉스에서 시작되었습니다. 수십 년의 연습은 스트림의 아이디어가 단순히 큰 시스템을 개발할 수 있음을 증명했습니다.
유닉스에서 스트림은 "|"를 통해 구현됩니다. 노드에서는 내장 스트림 모듈로서 많은 코어 모듈과 3 자 모듈이 사용됩니다.
UNIX와 마찬가지로 노드 스트림의 주요 작업은 .pipe ()이며, 사용자는 대책 메커니즘을 사용하여 읽기와 쓰기 간의 균형을 제어 할 수 있습니다.
스트림은 개발자에게 초록 스트림 인터페이스를 통해 스트림 간의 읽기 및 쓰기 균형을 재사용하고 제어 할 수있는 통합 인터페이스를 제공 할 수 있습니다.
TCP 연결은 읽기 쉬운 스트림 및 쓰기 가능한 스트림이며 HTTP 연결은 다릅니다. HTTP 요청 객체는 읽기 쉬운 스트림이고 HTTP 응답 객체는 쓰기 가능한 스트림입니다.
스트림 전송 프로세스는 기본적으로 버퍼 형태로 전송됩니다. 다른 인코딩 양식을 설정하지 않는 한 다음이 예입니다.
코드 사본은 다음과 같습니다.
var http = 요구 ( 'http');
var server = http.createserver (function (req, res) {
res.writeHeader (200, { 'content-type': 'text/plain'});
res.end ( "안녕하세요, 큰 곰!");
});
Server.Listen (8888);
Console.log ( "포트 8888에서 실행되는 HTTP 서버 ...");
실행 후 "UTF-8"과 같은 지정된 문자 세트가 설정되지 않기 때문에 차량 코드가 나타납니다.
그냥 수정하십시오 :
코드 사본은 다음과 같습니다.
var http = 요구 ( 'http');
var server = http.createserver (function (req, res) {
res.writeHeader (200, {
'content-type': 'text/plain; charset = utf-8'// charset = utf-8을 추가합니다
});
res.end ( "안녕하세요, 큰 곰!");
});
Server.Listen (8888);
Console.log ( "포트 8888에서 실행되는 HTTP 서버 ...");
실행 결과 :
스트림을 사용하는 이유
노드의 I/O는 비동기식이므로 디스크 및 네트워크에 대한 읽기 및 쓰기에는 콜백 기능을 통해 데이터를 읽고 읽어야합니다. 다음은 파일 다운로드의 예입니다
코드 :
코드 사본은 다음과 같습니다.
var http = 요구 ( 'http');
var fs = 요구 ( 'fs');
var server = http.createserver (function (req, res) {
fs.readfile (__ dirname + '/data.txt', function (err, data) {
res.end (데이터);
});
});
Server.Listen (8888);
코드는 필요한 기능을 구현할 수 있지만 서비스는 파일 데이터를 전송하기 전에 전체 파일 데이터를 메모리에 캐시해야합니다. "data.txt"파일이 매우
그것이 크고 동시성이 크면 많은 기억이 낭비됩니다. 사용자는 파일 데이터를 수락하기 위해 전체 파일이 메모리로 캐시 될 때까지 기다려야하므로
사용자 경험은 상당히 나쁩니다. 다행스럽게도 두 매개 변수 (req, res)는 스트림이므로 fs.ReadFile () 대신 fs.CreateReadStream ()을 사용할 수 있습니다. 다음과 같이 :
코드 사본은 다음과 같습니다.
var http = 요구 ( 'http');
var fs = 요구 ( 'fs');
var server = http.createserver (function (req, res) {
var stream = fs.createreadstream (__ dirname + '/data.txt');
stream.pipe (res);
});
Server.Listen (8888);
.pipe () 메소드는 fs.createreadstream ()의 'data'및 'end'이벤트를 듣고 "data.txt"파일을 캐시 할 필요가 없습니다.
클라이언트 연결이 완료된 직후 파일을 클라이언트에게 전송할 수 있습니다. .pipe ()를 사용하는 또 다른 이점은 고객이 할 때 해결할 수 있다는 것입니다.
매우 큰 종료 지연으로 인한 불균형을 읽고 쓰십시오.
읽기 가능, 쓰기 가능, 변환, 이중 및 "클래식"의 5 가지 기본 스트림이 있습니다. (자세한 내용은 API를 확인하십시오)
2. 예제를 소개합니다
처리 해야하는 데이터를 한 번에 메모리로로드 할 수 없거나 읽기 중에 처리가 더 효율적일 때 데이터 스트림을 사용해야합니다. Nodejs는 다양한 스트림을 통해 데이터 스트림에 대한 작업을 제공합니다.
대형 파일 복사 프로그램을 예로 들어 데이터 소스에 대한 읽기 전용 데이터 스트림을 만들 수 있습니다. 예는 다음과 같습니다.
코드 사본은 다음과 같습니다.
var rs = fs.createreadstream (pathname);
rs.on ( 'data', function (chunk) {
복용량 (청크); // 원하는대로 특정 세부 정보를 사용하십시오
});
rs.on ( 'end', function () {
정리 ();
});
복용량 기능을 처리 할 수 있는지 여부에 관계없이 코드의 데이터 이벤트는 지속적으로 트리거됩니다. 이 문제를 해결하기 위해 코드를 다음과 같이 수정할 수 있습니다.
코드 사본은 다음과 같습니다.
var rs = fs.createreadstream (SRC);
rs.on ( 'data', function (chunk) {
rs.Pause ();
dosomething (청크, function () {
Rs.Resume ();
});
});
rs.on ( 'end', function () {
대청소();
});
콜백이 Dosomething 기능에 추가되므로 데이터를 처리하기 전에 데이터 읽기를 일시 중지하고 데이터를 처리 한 후에 데이터를 계속 읽을 수 있습니다.
또한 다음과 같이 데이터 대상에 대한 쓰기 전용 데이터 스트림을 만들 수도 있습니다.
코드 사본은 다음과 같습니다.
var rs = fs.createreadstream (SRC);
var ws = fs.createWritestream (DST);
rs.on ( 'data', function (chunk) {
ws.Write (청크);
});
rs.on ( 'end', function () {
ws.end ();
});
DoSomething을 쓰기 전용 스트림으로 작성하여 DOSOMething을 대체 한 후 위의 코드는 파일 복사 프로그램처럼 보입니다. 그러나 위의 코드에는 위에서 언급 한 문제가 있습니다. 쓰기 속도가 읽기 속도를 따라 잡을 수없는 경우 데이터 스트림 내부에 캐시를 쓰는 경우 만 있습니다. 당사는 .write 메소드의 반환 값에 따라 들어오는 데이터가 대상에 기록되었거나 캐시에 일시적으로 배치되었는지 여부를 판단 할 수 있으며, 쓰기 데이터 만 배수 이벤트를 기반으로 대상에 기록 된시기를 판단하고 다음 데이터를 전달할 수 있습니다. 따라서 코드는 다음과 같습니다.
코드 사본은 다음과 같습니다.
var rs = fs.createreadstream (SRC);
var ws = fs.createWritestream (DST);
rs.on ( 'data', function (chunk) {
if (ws.write (chunk) === false) {
rs.Pause ();
}
});
rs.on ( 'end', function () {
ws.end ();
});
ws.on ( '배수', function () {
Rs.Resume ();
});
마지막으로, 읽기 전용 데이터 스트림에서 쓰기 전용 데이터 스트림으로의 데이터 전송이 실현되고 폭발 방지 창고 제어가 포함됩니다. 위의 대형 파일 복사 프로그램과 같은 많은 사용 시나리오가 있기 때문에 Nodejs는 .pipe 메소드를 직접 제공하며 내부 구현 방법은 위 코드와 유사합니다.
다음은 파일을 복사하는보다 완전한 프로세스입니다.
코드 사본은 다음과 같습니다.
var fs = 요구 ( 'fs'),
경로 = 요구 사항 ( 'Path'),
out = process.stdout;
var filepath = '/bb/bigbear.mkv';
var readstream = fs.createreadstream (Filepath);
var writestream = fs.createWritestream ( 'file.mkv');
var stat = fs.statsync (filepath);
Var Totalsize = stat.size;
var passedlength = 0;
var lastsize = 0;
var starttime = date.now ();
readstream.on ( 'data', function (chunk) {
PassedLength += Chunk.Length;
if (writestream.write (chunk) === false) {
readStream.Pause ();
}
});
readstream.on ( 'end', function () {
writestream.end ();
});
writestream.on ( '배수', function () {
readstream.resume ();
});
settimeout (function show () {
var % = math.ceil ((PassedLength / TotalSize) * 100);
var size = math.ceil (PassedLength / 10000000);
var diff = 크기 - 최소 크기;
마지막 크기 = 크기;
out.clearline ();
out.cursorto (0);
out.write ( '완료' + size + 'mb,' +% + '%, 속도 :' + diff * 2 + 'mb/s');
if (passedLength <TotalSize) {
settimeout (show, 500);
} 또 다른 {
var endtime = date.now ();
console.log ();
console.log ( '공유 할 때 :' + (endtime -starttime) / 1000 + 'seconds.');
}
}, 500);
위의 코드를 "copy.js"로 저장할 수 있습니다. 실험 : 재귀 세트 타임 아웃 (또는 직접 setInterval을 사용)을 방관자로 추가했습니다.
500ms마다 완료 진행 상황을 관찰하고 완성 된 크기, 백분율 및 복사 속도를 콘솔에 함께 작성하십시오. 복사가 완료되면 총 시간이 계산됩니다.
셋째, 요약합시다
(1) 스트림의 개념을 이해합니다.
(2) 관련 스트림 API를 사용하는 데 능숙합니다
(3) Sharding에 "청크 데이터"형식을 사용하여 큰 파일 복사와 같은 세부 사항의 제어에주의를 기울입니다.
(4), 파이프 사용
(5), 개념을 다시 강조하십시오 : TCP 연결은 읽기 쉬운 스트림이자 쓰기 가능한 스트림이며 HTTP 연결은 다릅니다. HTTP 요청 객체는 읽기 쉬운 스트림이고 HTTP 응답 객체는 쓰기 가능한 스트림입니다.