저자는 COVID-19 구호 기금을 기부를 받을 단체로 선정했습니다.
소개
A buffer is a space in memory (typically RAM) that stores binary data. In Node.js, we can access these spaces of memory with the built-in Buffer
class. Buffers store a sequence of integers, similar to an array in JavaScript. Unlike arrays, you cannot change the size of a buffer once it is created.
이미 Node.js 코드를 작성한 적이 있다면 암묵적으로 버퍼를 사용해 본 적이 있을 것입니다. 예를 들어, fs.readFile()
로 파일을 읽을 때, 콜백 또는 Promise으로 반환되는 데이터는 버퍼 객체입니다. 또한, Node.js에서 HTTP 요청을 보낼 때, 클라이언트가 스트림을 한 번에 처리할 수 없는 경우에는 내부 버퍼에 일시적으로 저장된 데이터 스트림을 반환합니다.
버퍼는 일반적으로 하위 네트워킹 수준에서 바이너리 데이터와 상호 작용할 때 유용합니다. 또한 Node.js에서 세밀한 데이터 조작을 수행할 수 있는 능력을 제공합니다.
이 튜토리얼에서는 Node.js REPL을 사용하여 버퍼의 다양한 예제를 실행합니다. 버퍼 생성, 버퍼에서 읽기, 버퍼에 쓰기 및 복사, 그리고 이진 및 인코딩된 데이터 간의 변환에 버퍼 사용 등이 포함됩니다. 이 튜토리얼의 끝에는 이진 데이터를 처리하는 데 Buffer
클래스를 사용하는 방법을 배울 것입니다.
전제 조건
- 개발 환경에 Node.js가 설치되어 있어야 합니다. 이 튜토리얼은 버전 10.19.0을 사용합니다. macOS 또는 Ubuntu 18.04에 이를 설치하려면 macOS에 Node.js 설치 및 로컬 개발 환경 만들기 또는 Ubuntu 18.04에 Node.js 설치하는 방법의 PPA를 사용한 설치 섹션의 단계를 따르십시오.
- 이 튜토리얼에서는 Node.js REPL(Read-Evaluate-Print-Loop)에서 버퍼와 상호 작용합니다. Node.js REPL을 효과적으로 사용하는 방법을 상기하고 싶다면 Node.js REPL 사용 방법 가이드를 읽어보십시오.
- 이 문서에서는 사용자가 기본 JavaScript와 해당 데이터 유형에 익숙하다고 가정합니다. 이러한 기본 사항은 Javascript 시리즈에서 코드 작성 방법을 배울 수 있습니다.
단계 1 — 버퍼 생성
이 첫 번째 단계에서는 Node.js에서 버퍼 객체를 생성하는 두 가지 기본 방법을 보여줍니다.
어떤 방법을 사용할지 결정하려면 다음 질문에 답해야합니다: 새 버퍼를 만들고 있습니까, 아니면 기존 데이터에서 버퍼를 추출하고 있습니까? 아직 수신하지 않은 메모리에 데이터를 저장할 예정이라면 새 버퍼를 만들어야합니다. Node.js에서는 이를 위해 Buffer
클래스의 alloc()
함수를 사용합니다.
자세히 보기 위해 Node.js REPL을 엽니다. 터미널에서 node
명령을 입력하십시오:
프롬프트가 >
로 시작되는 것을 볼 수 있습니다.
alloc()
함수는 버퍼의 크기를 첫 번째 및 유일한 필수 인수로 취합니다. 크기는 버퍼 객체가 사용할 메모리 바이트 수를 나타내는 정수입니다. 예를 들어, 1KB(킬로바이트) 크기의 버퍼를 만들고 싶다면 콘솔에 다음을 입력하면 됩니다:
새로운 버퍼를 생성하기 위해 전역으로 사용 가능한 Buffer
클래스를 사용했으며, 이 클래스에는 alloc()
메서드가 있습니다. alloc()
에 1024
를 인수로 제공하여 1KB 크기의 버퍼를 생성했습니다.
기본적으로 alloc()
을 사용하여 버퍼를 초기화할 때 나중에 데이터를 위한 자리 표시자로 이진 0으로 채워집니다. 그러나 원하는 경우 기본 값을 변경할 수 있습니다. 만약 0
대신 1
로 채워진 새로운 버퍼를 만들고 싶다면, alloc()
함수의 두 번째 매개변수인 fill
을 설정합니다.
터미널에서 REPL 프롬프트에서 1
로 채워진 새로운 버퍼를 생성하세요:
우리는 방금 메모리에 1KB의 1
을 저장하는 새로운 버퍼 객체를 생성했습니다. 정수를 입력했지만, 버퍼에 저장된 모든 데이터는 이진 데이터입니다.
이진 데이터는 여러 가지 형식으로 나타날 수 있습니다. 예를 들어, 바이트 데이터를 나타내는 바이너리 시퀀스를 고려해 봅시다: 01110110
. 이진 시퀀스가 영어 문자열을 나타내고 있다면 ASCII 인코딩 표준을 사용하면 문자 v
가 됩니다. 그러나 컴퓨터가 이미지를 처리하는 경우 이진 시퀀스는 픽셀의 색상에 대한 정보를 포함할 수 있습니다.ASCII 인코딩 표준
컴퓨터는 바이트가 다른 방식으로 인코딩되어 있기 때문에 그것들을 다르게 처리할 수 있습니다. 바이트 인코딩은 바이트의 형식입니다. 노드.js의 버퍼는 문자열 데이터로 초기화되었다면 기본적으로 UTF-8 인코딩 체계를 사용합니다. UTF-8의 바이트는 숫자, 영어 및 다른 언어의 문자 또는 기호를 나타냅니다. UTF-8은 정보 교환용 미국 표준 코드 (ASCII)의 슈퍼셋입니다. ASCII는 대문자 및 소문자 영어 알파벳, 숫자 0-9 및 느낌표 (!) 또는 앰퍼샌드 기호 (&)와 같은 몇 가지 다른 기호를 바이트로 인코딩할 수 있습니다.
ASCII 문자만 처리할 수 있는 프로그램을 작성한다면 버퍼에서 사용되는 인코딩을 alloc()
함수의 세 번째 인자인 encoding
을 사용하여 변경할 수 있습니다.
다음은 다섯 바이트로 이루어진 새로운 버퍼를 만들어 ASCII 문자만 저장하는 예입니다:
이 버퍼는 ASCII 표현을 사용하여 문자 a
의 다섯 바이트로 초기화됩니다.
참고: 기본적으로 노드.js는 다음과 같은 문자 인코딩을 지원합니다:
- ASCII,
ascii
로 표시됨 - UTF-8,
utf-8
또는utf8
로 표시됨 - UTF-16,
utf-16le
또는utf16le
로 표시됨 - UCS-2는
ucs-2
또는ucs2
로 표시됩니다. - Base64는
base64
로 표시됩니다. - 16진수는
hex
로 표시됩니다. - ISO/IEC 8859-1는
latin1
또는binary
로 표시됩니다.
모든 이러한 값은 encoding
매개변수를 허용하는 Buffer 클래스 함수에서 사용할 수 있습니다. 따라서 이러한 값은 모두 alloc()
메서드에 유효합니다.
지금까지 alloc()
함수로 새 버퍼를 생성했습니다. 그러나 때로는 문자열이나 배열과 같이 이미 존재하는 데이터에서 버퍼를 만들고 싶을 수 있습니다.
기존 데이터에서 버퍼를 만들려면 from()
메서드를 사용합니다. 다음과 같은 데이터에서 버퍼를 만들 수 있습니다:
- 정수 배열: 정수 값은
0
에서255
사이여야 합니다. ArrayBuffer
: 이는 바이트의 고정 길이를 저장하는 JavaScript 객체입니다.- A string.
- 다른 버퍼.
- 다른 JavaScript 객체들도
Symbol.toPrimitive
속성을 가지고 있습니다. 이 속성은 객체를 기본 데이터 유형으로 변환하는 방법을 JavaScript에 알려줍니다:boolean
,null
,undefined
,number
,string
, 또는symbol
. Symbols에 대해 더 알아보려면 Mozilla의 JavaScript 문서를 참조하세요.
이제 문자열에서 버퍼를 생성하는 방법을 살펴보겠습니다. Node.js 프롬프트에서 다음을 입력하십시오:
이제 문자열 My name is Paul
에서 생성된 버퍼 객체가 있습니다. 이전에 만든 다른 버퍼에서 새 버퍼를 만들어 봅시다:
이제 asciiBuf
와 동일한 데이터를 포함하는 새로운 버퍼 asciiCopy
가 생성되었습니다.
이제 버퍼를 생성하는 경험이 있으므로, 데이터를 읽는 예제로 진입해보겠습니다.
단계 2 — 버퍼에서 읽기
버퍼에서 데이터에 액세스하는 방법은 여러 가지가 있습니다. 버퍼에서 개별 바이트에 액세스하거나 전체 내용을 추출할 수 있습니다.
버퍼의 하나의 바이트에 액세스하려면, 우리는 원하는 바이트의 인덱스나 위치를 전달합니다. 버퍼는 배열처럼 데이터를 순차적으로 저장합니다. 또한 배열처럼 데이터를 인덱싱하며, 0
부터 시작합니다. 개별 바이트를 얻으려면 버퍼 객체에 배열 표기법을 사용할 수 있습니다.
이것이 REPL에서 문자열을 기반으로 버퍼를 생성하여 어떻게 보이는지 살펴보겠습니다:
이제 버퍼의 첫 번째 바이트를 읽어 봅시다:
ENTER
를 누르면 REPL에서 다음이 표시됩니다:
Output72
정수 72
는 글자 H
의 UTF-8 표현에 해당합니다.
참고: 바이트의 값은 0
에서 255
사이의 숫자일 수 있습니다. 바이트는 8개의 비트로 구성됩니다. 비트는 이진이므로 0
또는 1
중 하나의 값만 가질 수 있습니다. 8개의 비트의 시퀀스가 있고 각 비트 당 두 가지 가능한 값이 있다면, 바이트에 대한 가능한 값은 최대 2⁸입니다. 이것은 최대 256개의 값으로 나타납니다. 우리는 0부터 카운트하기 때문에, 최대 숫자는 255입니다.
이제 두 번째 바이트에 대해 동일한 작업을 수행해 보겠습니다. REPL에 다음을 입력하십시오:
REPL은 소문자 i
를 나타내는 105
를 반환합니다.
마지막으로 세 번째 문자를 가져와 봅시다:
REPL에서 33
이 표시됩니다. 이는 !
에 해당합니다.
유효하지 않은 인덱스에서 바이트를 검색해 보겠습니다:
REPL은 다음을 반환합니다:
Outputundefined
이는 배열에서 잘못된 인덱스로 요소에 액세스하려고 시도한 것과 마찬가지입니다.
이제 버퍼의 모든 데이터를 한 번에 검색하는 옵션을 살펴보겠습니다. 버퍼 객체에는 전체 내용을 두 가지 다른 형식으로 반환하는 toString()
및 toJSON()
메서드가 있습니다.
그 이름에서 알 수 있듯이 toString()
메서드는 버퍼의 바이트를 문자열로 변환하여 사용자에게 반환합니다. 이 메서드를 hiBuf
에 사용하면 문자열 Hi!
을 얻게 됩니다. 한번 시도해 보죠!
프롬프트에서 다음을 입력하십시오:
REPL은 다음을 반환합니다:
Output'Hi!'
그 버퍼는 문자열에서 생성되었습니다. 이번에는 문자열 데이터가 아닌 버퍼에서 toString()
을 사용할 경우 어떻게 되는지 살펴보겠습니다.
빈 버퍼를 생성하고 크기를 10
바이트로 지정해 보겠습니다:
이제 toString()
메서드를 사용해 보겠습니다:
다음 결과를 볼 수 있습니다:
'\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'
문자열 \u0000
은 NULL
에 대한 유니코드 문자입니다. 이것은 숫자 0
에 해당합니다. 버퍼의 데이터가 문자열로 인코딩되지 않은 경우, toString()
메서드는 바이트의 UTF-8 인코딩을 반환합니다.
toString()
은 선택적 매개변수인 encoding
을 가지고 있습니다. 이 매개변수를 사용하여 반환되는 버퍼 데이터의 인코딩을 변경할 수 있습니다.
예를 들어, hiBuf
의 16진수 인코딩을 원하는 경우 다음을 프롬프트에 입력하면 됩니다:
해당 문장은 다음으로 평가됩니다:
Output'486921'
486921
은 문자열 Hi!
를 나타내는 바이트의 16진수 표현입니다. Node.js에서 사용자가 데이터의 인코딩을 한 형식에서 다른 형식으로 변환하려고 할 때, 일반적으로 문자열을 버퍼에 넣고 원하는 인코딩으로 toString()
을 호출합니다.
toJSON()
메서드의 동작이 다릅니다. 버퍼가 문자열에서 만들어졌는지 여부에 관계없이 항상 바이트의 정수 표현으로 데이터를 반환합니다.
hiBuf
와 tenZeroes
버퍼를 재사용하여 toJSON()
을 사용하는 연습을 해보겠습니다. 프롬프트에 다음을 입력하십시오:
REPL은 다음을 반환합니다:
Output{ type: 'Buffer', data: [ 72, 105, 33 ] }
JSON 객체에는 항상 Buffer
인 type
속성이 있습니다. 이렇게 함으로써 프로그램이 이러한 JSON 객체를 다른 JSON 객체와 구별할 수 있습니다.
data
속성에는 바이트의 정수 표현 배열이 포함되어 있습니다. 개별적으로 바이트를 가져올 때 받은 값들에 해당하는 72
, 105
, 및 33
를 주목하실 수 있을 겁니다.
tenZeroes
와 함께 toJSON()
메서드를 시도해 봅시다:
REPL에서 다음을 볼 수 있습니다:
Output{ type: 'Buffer', data: [
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
] }
type
은 이전에 언급한 것과 동일합니다. 그러나 데이터는 이제 열 개의 제로로 구성된 배열입니다.
이제 버퍼에서 읽는 주요 방법을 다루었으니, 버퍼의 내용을 수정하는 방법을 살펴보겠습니다.
단계 3 — 버퍼 수정
기존 버퍼 객체를 수정하는 여러 가지 방법이 있습니다. 읽는 것과 마찬가지로 배열 구문을 사용하여 버퍼 바이트를 개별적으로 수정할 수 있습니다. 또한 기존 데이터를 대체하여 새로운 내용을 버퍼에 쓸 수도 있습니다.
시작하기 전에 버퍼의 개별 바이트를 어떻게 변경할 수 있는지 살펴보겠습니다. 우리가 기억해야 할 버퍼 변수 hiBuf
는 문자열 Hi!
를 포함하고 있습니다. 각 바이트를 Hey
로 변경해 봅시다.
REPL에서 먼저 hiBuf
의 두 번째 요소를 e
로 설정해 보겠습니다:
이제 이 버퍼를 문자열로 표시하여 올바른 데이터를 저장하는지 확인해 봅시다. toString()
메서드를 호출하여 확인합니다:
이것은 다음과 같이 평가됩니다:
Output'H\u0000!'
우리는 이상한 출력을 받았습니다. 왜냐하면 버퍼는 정수값만 허용하기 때문입니다. 우리는 문자 e
를 할당할 수 없습니다. 대신, e
를 나타내는 이진 동등체를 가진 숫자를 할당해야 합니다:
이제 toString()
메서드를 호출하면:
REPL에서 이 출력을 받게 됩니다:
Output'He!'
버퍼의 마지막 문자를 변경하려면, 세 번째 요소를 y
의 바이트에 해당하는 정수로 설정해야 합니다:
다시 한 번 toString()
메서드를 사용하여 확인해 봅시다:
당신의 REPL은 다음을 표시할 것입니다:
Output'Hey'
만약 버퍼의 범위를 벗어난 바이트를 쓰려고 하면, 무시되고 버퍼의 내용은 변경되지 않습니다. 예를 들어, 버퍼의 존재하지 않는 네 번째 요소를 o
로 설정해 보겠습니다:
toString()
메서드를 사용하여 버퍼가 변경되지 않았는지 확인할 수 있습니다:
출력은 여전히 이와 같습니다:
Output'Hey'
전체 버퍼의 내용을 변경하려면 write()
메서드를 사용할 수 있습니다. write()
메서드는 버퍼의 내용을 대체할 문자열을 받습니다.
write()
메서드를 사용하여 hiBuf
의 내용을 다시 Hi!
로 변경해 봅시다. Node.js 셸에서 다음 명령을 입력하세요:
write()
메서드는 REPL에서 3
을 반환했습니다. 이는 세 개의 바이트 데이터를 작성했기 때문입니다. 각 문자는 한 바이트 크기를 가지며, 이 버퍼는 문자마다 한 바이트를 사용하는 UTF-8 인코딩을 사용합니다. 만약 버퍼가 문자당 최소 두 바이트를 사용하는 UTF-16 인코딩을 사용했다면 write()
함수는 6
을 반환했을 것입니다.
이제 toString()
을 사용하여 버퍼의 내용을 확인하세요:
REPL에서는 다음을 출력합니다:
Output'Hi!'
이는 각 요소를 바이트 단위로 변경하는 것보다 빠릅니다.
버퍼의 크기보다 더 많은 바이트를 작성하려고 시도하면 버퍼 개체는 맞는 바이트만 허용합니다. 설명하기 위해 세 개의 바이트를 저장하는 버퍼를 만들어 봅시다:
이제 이것에 Cats
를 작성하려고 시도해 봅시다:
write()
호출이 평가될 때 REPL은 버퍼에 세 개의 바이트만 작성되었다는 것을 나타내는 3
을 반환합니다. 이제 버퍼에 처음 세 개의 바이트가 포함되어 있는지 확인해 보세요:
REPL은 다음을 반환합니다:
Output'Cat'
write()
함수는 바이트를 순차적으로 추가하므로 첫 세 바이트만 버퍼에 배치됩니다.
그에 대비하여, 4바이트를 저장하는 Buffer
를 만들어보겠습니다:
동일한 내용을 그것에 기록해보겠습니다:
그런 다음 원래의 내용보다 공간을 적게 차지하는 새로운 내용을 추가해보겠습니다:
버퍼는 0에서 시작하여 순차적으로 쓰기 때문에, 버퍼의 내용을 출력하면:
우리는 다음과 같은 내용을 볼 수 있습니다:
Output'Hits'
첫 두 글자가 덮어쓰여지지만, 나머지 버퍼는 그대로 유지됩니다.
가끔 우리가 기존 버퍼에 원하는 데이터가 문자열에 있지 않고 다른 버퍼 객체에 있다면 어떻게 할까요. 이런 경우에는 copy()
함수를 사용하여 버퍼가 저장하는 내용을 수정할 수 있습니다.
두 개의 새로운 버퍼를 만들어보겠습니다:
wordsBuf
와 catchphraseBuf
버퍼 모두 문자열 데이터를 포함하고 있습니다. catchphraseBuf
를 Not sure Turtle!
대신 Nananana Turtle!
로 수정하려고 합니다. wordsBuf
에서 Nananana
를 catchphraseBuf
로 복사하기 위해 copy()
를 사용할 것입니다.
한 버퍼에서 다른 버퍼로 데이터를 복사하려면 정보를 제공하는 버퍼에서 copy()
메서드를 사용해야 합니다. 따라서 wordsBuf
에 복사할 문자열 데이터가 있으므로 다음과 같이 복사해야 합니다:
이 경우의 target
매개변수는 catchphraseBuf
버퍼입니다.
그것을 REPL에 입력하면 15
가 반환되어 15바이트가 쓰였음을 나타냅니다. 문자열 Nananana
은 데이터의 8바이트만 사용하므로 우리는 즉시 우리의 복사가 의도한 대로 되지 않았음을 알 수 있습니다. toString()
메서드를 사용하여 catchphraseBuf
의 내용을 확인합니다:
REPL이 반환하는 것은:
Output'Banana Nananana!'
copy()
가 기본적으로 wordsBuf
의 전체 내용을 가져와 catchphraseBuf
에 넣었습니다. 우리의 목표에 더 맞게 선택적으로 동작하려면 Nananana
만 복사하면 됩니다. 계속하기 전에 catchphraseBuf
의 원래 내용을 다시 작성해 봅시다:
copy()
함수에는 다른 버퍼로 데이터를 복사하는 데 사용할 수 있는 몇 가지 추가 매개변수가 있습니다. 이 함수의 모든 매개변수 목록은 다음과 같습니다:
target
–copy()
의 유일한 필수 매개변수입니다. 이전 사용 사례에서 보았듯이 복사할 버퍼입니다.targetStart
– 이는 복사를 시작해야 할 대상 버퍼의 바이트 인덱스입니다. 기본적으로0
으로 설정되어 있으므로 버퍼의 시작부터 데이터를 복사합니다.sourceStart
– 이는 복사를 시작해야 할 소스 버퍼의 바이트 인덱스입니다.sourceEnd
– 이는 복사를 중지해야 할 소스 버퍼의 바이트 인덱스입니다. 기본적으로 버퍼의 길이입니다.
그래서, wordsBuf
에서 Nananana
를 catchphraseBuf
로 복사하려면, 우리의 target
은 이전과 마찬가지로 catchphraseBuf
여야 합니다. targetStart
는 Nananana
가 catchphraseBuf
의 시작 부분에 나타나길 원하기 때문에 0
이어야 합니다. sourceStart
는 Nananana
가 wordsBuf
에서 시작하는 인덱스인 7
이어야 합니다. sourceEnd
는 버퍼의 길이와 같은 값이어야 합니다.
REPL 프롬프트에서 wordsBuf
의 내용을 다음과 같이 복사하십시오:
REPL은 8
바이트가 쓰여졌음을 확인합니다. wordsBuf.length
가 sourceEnd
매개변수의 값으로 사용되는 방식에 유의하십시오. 배열과 마찬가지로 length
속성은 버퍼의 크기를 제공합니다.
이제 catchphraseBuf
의 내용을 확인해 봅시다:
REPL은 다음을 반환합니다:
Output'Nananana Turtle!'
성공입니다! 우리는 wordsBuf
의 내용을 복사하여 catchphraseBuf
의 데이터를 수정할 수 있었습니다.
노드.js REPL을 종료하고 싶다면 종료할 수 있습니다. 그러나 종료하면 생성된 모든 변수가 더 이상 사용할 수 없음을 유의하십시오:
결론
이 튜토리얼에서는 버퍼가 메모리에 고정 길이 할당으로 이진 데이터를 저장하는 것을 배웠습니다. 먼저 버퍼를 메모리의 크기를 정의하고 기존 데이터로 초기화하여 생성했습니다. 그런 다음 버퍼에서 데이터를 읽어 각각의 바이트를 검사하고 toString()
및 toJSON()
메서드를 사용했습니다. 마지막으로 버퍼에 저장된 데이터를 수정하기 위해 각 바이트를 변경하고 write()
및 copy()
메서드를 사용했습니다.
버퍼를 통해 이진 데이터가 Node.js에서 어떻게 조작되는지에 대한 통찰력을 얻을 수 있습니다. 이제 버퍼와 상호 작용할 수 있으므로 문자 인코딩이 데이터 저장에 어떻게 영향을 미치는지 다양한 방법을 관찰할 수 있습니다. 예를 들어, UTF-8 또는 ASCII 인코딩이 아닌 문자열 데이터에서 버퍼를 생성하고 크기의 차이를 관찰할 수 있습니다. 또한 UTF-8로 된 버퍼를 가져와 toString()
을 사용하여 다른 인코딩 체계로 변환할 수 있습니다.
Node.js에서 버퍼에 대해 배우려면 Node.js 문서의 Buffer
개체를 읽어보십시오. Node.js를 계속 학습하고 싶다면 Node.js에서 코딩하는 방법 시리즈로 돌아가거나 Node 주제 페이지에서 프로그래밍 프로젝트 및 설정을 찾아보십시오.
Source:
https://www.digitalocean.com/community/tutorials/using-buffers-in-node-js