수색…


매개 변수

매개 변수 정의
읽을 수있는 스트림 데이터를 읽을 수있는 스트림 유형
쓰기 가능한 스트림 데이터를 쓸 수있는 스트림 유형
이중 스트림 스트림은 읽기 쉽고 쓸 수 있습니다.
스트림 변환 읽기 및 쓰기가 진행되는 동안 데이터를 변환 할 수있는 양방향 스트림 유형

스트림이있는 TextFile의 데이터 읽기

노드의 I / O는 비동기식이므로 디스크 및 네트워크와 상호 작용하려면 콜백을 함수에 전달해야합니다. 다음과 같이 디스크에서 파일을 제공하는 코드를 작성해야 할 수도 있습니다.

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 파일을 메모리에 버퍼링합니다. data.txt가 매우 큰 경우, 특히 느린 연결을 사용하는 사용자의 경우 많은 사용자가 동시에 사용할 수 있기 때문에 프로그램에서 많은 메모리를 먹을 수 있습니다.

사용자가 전체 파일을 서버의 메모리에 버퍼링하여 내용을 받기 시작할 때까지 기다려야하기 때문에 사용자 환경이 좋지 않습니다.

다행히도 (req, res) 인수는 스트림이므로 fs.readFile () 대신 fs.createReadStream ()을 사용하여 훨씬 더 좋은 방법으로이 코드를 작성할 수 있습니다.

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
});
server.listen(8000);

여기 .pipe ()는 fs.createReadStream ()에서 'data'및 'end'이벤트를 수신 대기합니다. 이 코드는 더 깨끗하지만, 이제는 data.txt 파일이 디스크에서 수신 될 때 즉시 한 번에 하나의 청크에 기록됩니다.

파이프 스트림

읽을 수있는 스트림은 쓰기 가능한 스트림에 "파이프"되거나 연결될 수 있습니다. 따라서 많은 노력을하지 않고 소스 스트림에서 대상 스트림으로 데이터를 흐르게합니다.

var fs = require('fs')

var readable = fs.createReadStream('file1.txt')
var writable = fs.createWriteStream('file2.txt')

readable.pipe(writable) // returns writable

쓰기 가능한 스트림이 읽을 수있는 스트림 인 경우 (예 : 양방향 스트림 인 경우) 다른 쓰기 가능한 스트림으로 계속 파이프 연결할 수 있습니다.

var zlib = require('zlib')

fs.createReadStream('style.css')
  .pipe(zlib.createGzip()) // The returned object, zlib.Gzip, is a duplex stream.
  .pipe(fs.createWriteStream('style.css.gz')

읽을 수있는 스트림을 여러 스트림으로 파이프 할 수도 있습니다.

var readable = fs.createReadStream('source.css')
readable.pipe(zlib.createGzip()).pipe(fs.createWriteStream('output.css.gz'))
readable.pipe(fs.createWriteStream('output.css')

데이터 흐름 전에 동 기적으로 (동시에) 출력 스트림으로 파이프해야합니다. 그렇지 않으면 불완전한 데이터가 스트리밍 될 수 있습니다.

또한 스트림 객체는 error 이벤트를 error 시킬 수 있습니다. 필요에 따라 모든 스트림에서 이러한 이벤트를 책임있게 처리해야합니다.

var readable = fs.createReadStream('file3.txt')
var writable = fs.createWriteStream('file4.txt')
readable.pipe(writable)
readable.on('error', console.error)
writable.on('error', console.error)

독자적인 읽기 / 쓰기 가능 스트림 만들기

우리는 스트림 객체가 fs와 같은 모듈에 의해 반환되는 것을 보게 될 것이지만 우리 자신의 streamable 객체를 만들고 싶다면 어떻게 될 것인가?

Stream 객체를 만들려면 NodeJs에서 제공하는 스트림 모듈을 사용해야합니다.

    var fs = require("fs");
    var stream = require("stream").Writable;
    
    /* 
     *  Implementing the write function in writable stream class.
     *  This is the function which will be used when other stream is piped into this 
     *  writable stream.
     */
    stream.prototype._write = function(chunk, data){
        console.log(data);
    }
    
    var customStream = new stream();
    
    fs.createReadStream("am1.js").pipe(customStream);

이렇게하면 우리 자신 만의 쓰기 가능한 스트림을 얻을 수 있습니다. 우리는 _write 함수 내에서 아무 것도 구현할 수 있습니다. 위의 메소드는 NodeJs 4.xx 버전에서 작동하지만 NodeJs 6.x ES6 에서는 클래스가 도입되어 구문이 변경되었습니다. 다음은 NodeJs의 6.x 버전 코드입니다.

    const Writable = require('stream').Writable;
    
    class MyWritable extends Writable {
      constructor(options) {
        super(options);
      }
    
      _write(chunk, encoding, callback) {
        console.log(chunk);
      }
    }

왜 스트림?

파일의 내용을 읽는 두 가지 예제를 살펴 보겠습니다.

첫 번째는 파일을 읽는 데 비동기 메서드를 사용하고 파일이 메모리에 완전히 읽혀지면 호출되는 콜백 함수를 제공합니다.

fs.readFile(`${__dirname}/utils.js`, (err, data) => {
  if (err) {
    handleError(err);
  } else {
    console.log(data.toString());
  }
})

두 번째는 파일 내용을 읽기 위해 streams 을 사용 streams .

var fileStream = fs.createReadStream(`${__dirname}/file`);
var fileContent = '';
fileStream.on('data', data => {
  fileContent += data.toString();
})

fileStream.on('end', () => {
  console.log(fileContent);
})

fileStream.on('error', err => {
  handleError(err)
})

두 예제 모두 똑같은 것을 언급 할 가치가 있습니다. 그 때의 차이점은 무엇입니까?

  • 첫 번째 것은 더 짧고 더 우아 해 보입니다.
  • 두 번째는 파일 읽는 동안 파일에 대한 일부 처리를 수행 할 수있게 해줍니다 (!).

처리 할 파일이 작 으면 streams 사용할 때 실제 효과가 없지만 파일이 클 때 어떤 일이 발생합니까? (너무 커서 메모리에 읽는 데 10 초가 걸린다)

streams 이 없다면 10 초가 지나고 파일이 완전히 읽힐 때까지 아무것도하지 않으면 서 기다릴 것입니다. (프로세스가 다른 작업을하지 않는 한) 파일 처리가 시작될 수 있습니다.

streams 사용하면 파일 콘텐츠를 사용할 수있을 때 바로 가져올 수 있습니다.이 기능을 사용하면 파일 읽는 동안 파일 처리 할 수 ​​있습니다.


위의 예에서는 콜백 방식으로 갈 때 수행 할 수없는 작업에 streams 을 활용하는 방법을 보여주지 않으므로 다른 예제를 살펴보십시오.

gzip 파일을 다운로드하고 압축을 풀어 내용을 디스크에 저장하고 싶습니다. 파일의 url 감안할 때 이것이 필요한 것입니다 :

  • 파일 다운로드
  • 파일의 압축을 풉니 다.
  • 디스크에 저장하십시오.

여기 내 S3 저장소에 저장되어있는 [작은 파일] [1]이 있습니다. 다음 코드는 콜백 방식으로 위의 작업을 수행합니다.

var startTime = Date.now()
s3.getObject({Bucket: 'some-bucket', Key: 'tweets.gz'}, (err, data) => {
  // here, the whole file was downloaded

  zlib.gunzip(data.Body, (err, data) => {
    // here, the whole file was unzipped

    fs.writeFile(`${__dirname}/tweets.json`, data, err => {
      if (err) console.error(err)

      // here, the whole file was written to disk
      var endTime = Date.now()
      console.log(`${endTime - startTime} milliseconds`) // 1339 milliseconds
    })
  })
})

// 1339 milliseconds

다음은 streams 사용하는 방법입니다.

s3.getObject({Bucket: 'some-bucket', Key: 'tweets.gz'}).createReadStream()
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream(`${__dirname}/tweets.json`));

// 1204 milliseconds

네, 작은 파일을 다룰 때는 더 빠르지 않습니다. 테스트 된 파일의 무게는 80KB 입니다. 더 큰 파일 인 71MB 압축 파일 (압축되지 382MB ) 382MB 파일을 테스트하면 streams 버전이 훨씬 빠릅니다.

  • 그것은 다운로드 20,925 밀리 초를했다 71MB , 압축을 풀고 다음 쓰기 382MB 콜백 방식을 사용하여 - 디스크를.
  • 비교해 보면 streams 버전을 사용할 때도 동일한 작업을 수행하는 데 13434 밀리 초가 걸렸습니다 (크지 않은 파일의 경우 35 % 빨라짐)


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow