buf.write()
Writes a string into an existing Buffer at an offset and returns how many bytes it wrote.
buf.write(string[, offset[, length]][, encoding])- Added in Node.js v0.1.90
Parameters
| Parameter | Type | Description |
|---|---|---|
$string | string | String to write to buf. |
$offsetoptional | integer= 0 | The number of bytes to skip before starting to write string. |
$lengthoptional | integer= buf.length - offset | The number of bytes to write. |
$encodingoptional | string= 'utf8' | The character encoding of string. |
Return value
integerThe number of bytes written. This is fewer than the byte length of string if there was not enough space.
Errors
Throws ERR_BUFFER_OUT_OF_BOUNDS if offset is outside the buffer, and ERR_UNKNOWN_ENCODING for an unsupported encoding name. Running out of space does not throw.
Changelog
- PHP v14.0.0Changed behaviour for incomplete UTF-8 sequences: a multi-byte character that does not fit is no longer written partially.
- PHP v5.7.0The encoding parameter is now supported alongside offset and length.
buf.write() encodes a string into a buffer you already own, at the offset you choose. It is the counterpart to Buffer.alloc(): allocate the fixed-size region once, then write fields into it.
The return value is the point
It returns bytes written, which can be fewer than the string needs. A buffer that is too short is not an error — the string is truncated and you are expected to notice by checking the return value. Ignoring it is how half-written data reaches the wire.
It will not split a character
Since Node 14, a multi-byte UTF-8 sequence that does not fit is skipped entirely rather than written partially, so Buffer.alloc(4).write('café') returns 3, not 4. That keeps the buffer decodable, but it also means the return value can be smaller than the space remaining.
Argument order
encoding may be given in place of offset or of length, so buf.write(s, 'hex') and buf.write(s, 2, 'hex') both work. Compare the return value against Buffer.byteLength(string, encoding) to know whether everything fit; anything past what you wrote still holds the buffer's previous contents.
Example
When to use it
- Fill fixed-width text fields in a binary or flat-file record.
- Write a magic string or version tag into a pre-allocated header.
- Place a hex or base64 value into a known offset of a frame.
- Reuse one scratch buffer across iterations instead of allocating per string.
Frequently asked questions
What does buf.write return in Node.js?
It returns the number of bytes written, which may be fewer than the string needs when the buffer runs out of room. Compare it against Buffer.byteLength(string, encoding) to detect truncation.
Why did buf.write only write part of my string?
Because the remaining space was smaller than the string's byte length, and write truncates instead of throwing. Since Node 14 it also refuses to write a partial multi-byte character, so the count can stop one or two bytes short of the space available.
How do I write a string at a specific offset in a Buffer?
Pass the offset as the second argument, as in buf.write('AMS', 2). Add a length third argument to cap how many bytes may be written, which is how fixed-width fields are kept from overrunning the next one.
More examples
Checking for a short write
Comparing the return value with Buffer.byteLength is the only way to distinguish a complete write from a truncated one, since write itself never signals the difference. Note the first field wrote 5 bytes for 4 characters, which is why the length must be measured rather than assumed.
function writeField(buf, offset, size, text) {
const needed = Buffer.byteLength(text, 'utf8');
const written = buf.write(text, offset, size, 'utf8');
if (written < needed) {
throw new RangeError(`"${text}" needs ${needed} bytes, field holds ${size}`);
}
return written;
}
const rec = Buffer.alloc(16, 0x20);
writeField(rec, 0, 8, 'Köln');
console.log(JSON.stringify(rec.toString())); // "Köln "
try {
writeField(rec, 8, 4, 'Frankfurt');
} catch (err) {
console.log(err.message);
// "Frankfurt" needs 9 bytes, field holds 4
}Building a record with mixed encodings
Each write returns its byte count, so accumulating that into offset walks the cursor forward correctly even when encodings differ — the hex field consumes six characters but only three bytes. Sending frame.subarray(0, offset) rather than the whole buffer avoids shipping the seven unused trailing bytes.
const frame = Buffer.alloc(20, 0);
let offset = 0;
offset += frame.write('MSG', offset, 'ascii'); // 3-byte magic
frame.writeUInt8(1, offset++); // version
frame.writeUInt32BE(0xdeadbeef, offset); offset += 4; // id
offset += frame.write('cafe00', offset, 'hex'); // 3 bytes from 6 hex chars
offset += frame.write('ok', offset, 'utf8');
console.log(frame.toString('hex'));
// 4d534701deadbeefcafe006f6b00000000000000
console.log('used', offset, 'of', frame.length, 'bytes'); // used 13 of 20 bytes
console.log(frame.subarray(0, offset).toString('hex'));Where the string does not fit
The third case is the Node 14 behaviour: with one byte of space left and a three-byte character to write, write stops at 5 rather than emitting a partial sequence, leaving the original fill byte in place. Only an out-of-range offset throws; running out of room never does.
const buf = Buffer.alloc(6, 0x2e); // filled with '.'
console.log(buf.write('abcdefghij')); // 6 - truncated silently
console.log(buf.toString()); // abcdef
buf.fill(0x2e);
console.log(buf.write('日本語')); // 6 - exactly two characters... no, three
console.log(buf.toString()); // 日本
buf.fill(0x2e);
console.log(buf.write('ab日本')); // 5 - the second kanji did not fit
console.log(JSON.stringify(buf.toString())); // "ab日."
try { buf.write('x', 99); } catch (err) { console.log(err.code); }
// ERR_BUFFER_OUT_OF_BOUNDS
Discussion