지난 글에서 버퍼 형식인 바이너리 데이터를 보았는데 오늘은 버퍼와 스트림에 대해서 알아볼 것이다.
버퍼 : 일정한 크기로 모아두는 데이터
- 일정한 크기가 되면 한 번에 처리
- 버퍼링 : 버퍼에 데이터가 찰 때까지 모으는 작업
스트림 : 데이터의 흐름
- 일정한 크기로 나눠서 여러 번에 걸쳐서 처리
- 버퍼(또는 청크)의 크기를 작게 만들어서 주기적으로 데이터를 전달
- 스트리밍 : 일정한 크기의 데이터를 지속적으로 전달하는 작업
사용 방법
1. 버퍼 방식
buffer.js
const buffer = Buffer.from('저를 버퍼로 바꿔보세요');
console.log('from():', buffer);
console.log('length:', buffer.length);
console.log('toString():', buffer.toString());
const array = [Buffer.from('띄엄 '), Buffer.from('띄엄 '), Buffer.from('띄어쓰기')];
const buffer2 = Buffer.concat(array);
console.log('concat():', buffer2.toString());
const buffer3 = Buffer.alloc(5); // 5바이트짜리 빈 버퍼를 만듬
console.log('alloc():', buffer3);
콘솔 결과
2. 스트림 방식
2-1 파일 읽기
readme3.txt
저는 조금씩 조금씩 나눠서 전달됩니다. 나눠진 조각을 chunk라고 부릅니다.
createReadStream.js
const fs = require('fs');
const readStream = fs.createReadStream('./readme3.txt', { highWaterMark: 16 });
const data = [];
readStream.on('data', (chunk) => {
data.push(chunk);
console.log('data :', chunk, chunk.length);
});
readStream.on('end', () => {
console.log('end :', Buffer.concat(data).toString());
});
readStream.on('error', (err) => {
console.log('error :', err);
});
createReadStream.js 파일에서 readme2.txt를 읽을 때 스트림 방식으로 데이터를 나눠서 받는다.
읽기가 끝났으면 데이터를 concat으로 합쳐서 결과를 출력한다.
만약 createReadStream 함수에서 highWaterMark를 16으로 설정해주지 않는다면 162바이트를 한번에 읽어올 것이다.
왜냐하면 createReadStream은 한번에 읽는 버퍼 조각이 64KB이기 때문에 162바이트인 readm2.txt 파일을 한번에 읽는 것이다.
콘솔 결과
2-2 파일 쓰기
파일을 읽는 것 뿐만이 아니라 쓰는 것도 스트림 방식으로 할 수 있다.
createWriteStream.js
const fs = require('fs');
const writeStream = fs.createWriteStream('./writeme2.txt');
writeStream.on('finish', () => {
console.log('파일 쓰기 완료');
});
writeStream.write('이 글을 씁니다.\n');
writeStream.write('한 번 더 씁니다.');
writeStream.end();
writeme2.txt
이 글을 씁니다.
한 번 더 씁니다.
파이프(pipe)
데이터를 잘라서 보내고 받는 스트림 방식의 모양이 파이프에 액체가 흘러가는 것과 같다고 해서 파이프(pipe)라고 한다.
스트림과 스트림을 연결해서 파이프를 연결할 수 있다.
pipe.js
const fs = require('fs');
const readStream = fs.createReadStream('readme4.txt', { highWaterMark: 16 });
const writeStream = fs.createWriteStream('writeme3.txt');
readStream.pipe(writeStream);
파이프를 사용해서 스트림끼리 연결한다.
readme4.txt를 16byte씩 읽어오는 것을 writeme3.txt 파일에 16byte 씩 작성한다.
파일을 스트림 방식으로 압축할 수도 있다.
gzip.js
const zlib = require('zlib');
const fs = require('fs');
const readStream = fs.createReadStream('./readme4.txt');
const zlibStream = zlib.createGzip();
const writeStream = fs.createWriteStream('./readme4.txt.gz');
readStream.pipe(zlibStream).pipe(writeStream);
스트림 방식의 경우 파이프끼리 연결할 수도 있다.
결론
대부분의 경우 스트림이 효율적이다.
버퍼의 경우 만약 100기가의 데이터를 한 번에 다 채워서 보내려면 서버의 메모리가 부족한 경우 서버가 터질 수도 있기 때문이다.
(스트림 방식으로 작업할 경우 서버의 메모리를 적게 차지하기 때문에 효율적으로 데이터를 보낼 수 있다.)
'Node.js' 카테고리의 다른 글
Node.js 내장 모듈 - fs (0) | 2023.05.16 |
---|---|
Node.js 내장 모듈 - child_process (0) | 2023.05.15 |
Node.js 내장 모듈 - worker_threads (2) | 2023.05.12 |
Node.js 내장 모듈 - util (0) | 2023.05.10 |
Node.js 내장 모듈 - crypto (0) | 2023.05.06 |