Web/javascript

Node.js buffer, stream, pipe

dustKim 2024. 4. 25. 00:14
버퍼(buffer)

- 메모리에 저장되는 일부의 공간이다.

- 바이트 단위로 저장되며 integer 형태의 배열이다.

더보기
const buf = Buffer.from('Hi');
console.log(buf);
console.log(buf.length);
console.log(buf[0]);
console.log(buf[1]);
console.log(buf.toString());


const buf2 = Buffer.alloc(2);
buf2[0] = 72;
buf2[1] = 105;
console.log(buf2.toString());



// nodejs 를 메모리 버퍼에 문자열 사이즈 만큼 메모리를 할당하고 문자를 저장

const buf3 = Buffer.from('nodejs');
console.log(buf3[0]);
console.log(buf3[1]);
console.log(buf3[2]);
console.log(buf3[3]);
console.log(buf3[4]);
console.log(buf3[5]);


const buf4 = Buffer.alloc(6);
buf3[0] = 110;
buf3[1] = 111;
buf3[2] = 100;
buf3[3] = 101;
buf3[4] = 106;
buf3[5] = 115;
console.log(buf3.toString());


const newbuf = Buffer.concat([buf, buf2, buf3]);
console.log(newbuf.toString());
결과

 

Buffer에 기본적으로 utf-8을 인코딩 값으로 갖는다. 그래서 맨 처음에 나오는 값이 16진수로 표현이 된 것이다.

값을 string으로 표현하기 위해서 toString()함수를 사용하면 원하는 "Hi" string값이 나온다. 다른 방법으로는 alloc()함수를 사용하는 것이다. alloc은 숫자를 인수로 받으면 받은 숫자만큼의 빈 사이즈의 버퍼를 생성한다. 빈 버퍼에 각 인덱스 값을 채워서 toString()함수를 이용하여 바꿔주는 방식이다.

nodejs의 값을 표현하는 방식도 똑같이 하면된다. alloc을 사용하여 빈 버퍼에 데이터를 채우고 toString()함수를 사용하여 바꿔준다.

concat으로 각 버퍼를 이어줄 수도 있다.

 

스트림(stream)

- 데이터의 흐름을 나타내며 데이터를 읽는 스트림, 데이터를 쓰는 스트임, 데이터를 읽고 쓰는 스트림 등이 있다.

- 일반적으로 데이터를 효율적으로 처리하고 메모리 사용량을 최적화하기 위해 사용한다.

더보기
const fs = require('fs');

const beforeMem = process.memoryUsage().rss;
console.log(beforeMem);


fs.readFile('./test.html', (_, data) => {
    fs.writeFile('./file.txt', data, () => {
        console.log('파일 저장 완료.');
    });
    const afterMem = process.memoryUsage().rss;
    const diff = afterMem - beforeMem;
    const result = diff / 1024 / 1024;
    console.log(diff);
    console.log(`메모리 사용:  ${result} MB`);
});
결과

 

fs는 File System으로 파일을 관리할 수 있다.

process.memoryUsage()는 메모리 사용량을 확인할 수 있는 명령어다.

process.memoryUsage()

 

process.memoryUsage()를 사용하면 위와 같은 결과가 나온다. 우리는 저기서 rss부분만 뽑아준 것이다.

 

그 이후 부분에서 fs.reaFile()과 fs.writeFile() 부분은 파일을 읽고 써주는 것이다. readFile(경로, 옵션, callback)의 형태로 3가지 인자를 넘겨줄 수 있다. 위 코드에서는 경로와 callback만 사용했고, callback 함수에서 err는 받지 않고 data만 받아주는 구조로 만든 것이다. test 파일에서 내부 데이터만 받아온다. 

writeFile(경로, data, 옵션, callback)의 형태로 readFile() 함수와 같이 옵션을 넣어줄 필요는 없다. writeFile() 함수로 받아온 data를 경로에 넣어준다. 만약 파일이 존재하지 않는다면 파일을 만들어 넣어준다.

(이 두 함수는 비동기식이고 뒤에 Sync를 붙이면 동기식으로 바뀐다.)

 

중간에 파일을 다루고 다시 메모리 사용량을 확인하면 사용량이 늘어난 것을 알 수 있다.

뒷부분은 얼만큼의 메모리를 사용한 지 확인하는 부분을 표현한 것이다.

 

pipe

- 스트림을 연결하고 데이터를 한 스트림에서 다른 스트림으로 자동으로 전달하는 메서드이다. 

- 데이터를 효율적으로 처리하고 복사하지 않고도 한 스트림에서 다른 스트림으로 데이터를 전달할 수 있다.

더보기
const fs = require("fs");
const zlib = require("zlib");

const readStream = fs.createReadStream("./file.txt");
const zlibStream = zlib.createGzip();
const writeStream = fs.createWriteStream("./file2.txt.gz");

const piping = readStream.pipe(zlibStream).pipe(writeStream);
piping.on("finish", () => {
  console.log("끝");
});
결과

 

pipe() 함수는 스트림을 연결하고 데이터를 전달하기에 위 코드를 보면 file.txt 를 file2.txt.gz로 압축한다는 것을 알 수 있다. 압축한 스트림의 내부 내용은 전달해 준 스트림의 내부 내용과 같다.

(zlib는 압축할 수 있게 도와주는 라이브러리이다.)