Non-blocking write(2) / writev(2) for Lua file handles and file descriptors.
luarocks install io-write
The following functions return the error object created by https://github.com/mah0x211/lua-errno module.
Writes a string or a table of strings to a file handle or file descriptor.
- When
datais a string, useswrite(2)orpwrite(2)(ifoffsetis given). - When
datais a table, useswritev(2)orpwritev(2)(ifoffsetis given) for vectorized I/O. Only positive-integer keys with non-empty string values are written;nilvalues, empty strings, and non-positive-integer keys are ignored. The number of writable entries is limited to the effectiveIOV_MAX, determined as follows:- If
IOV_MAXis not defined by the system headers at compile time,_XOPEN_IOV_MAXis used if available; otherwise it falls back to16. - At module load time,
sysconf(_SC_IOV_MAX)is called to get the runtime limit. If it fails or returns a value larger than the compile-timeIOV_MAX, the compile-timeIOV_MAXis used instead.
- If
NOTE: If the non-blocking flag is not set on file, the write will block until completion.
Parameters
file:file*|integer: a file handle or a raw file descriptor.data:string|table: a string, or a table of strings to be written. In a table,nilvalues, empty strings, and non-positive-integer keys are silently skipped.offset:integer(optional): byte offset at which to write (pwrite(2)/pwritev(2)). The file-handle position is not changed. Omit (or passnil) to write at the current position.
Returns
n:integer: number of bytes written, ornilon error.err:any: error object, ornilon success.again:boolean:trueif the write could not complete due toEAGAIN,EWOULDBLOCK, orEINTR. Retry after the fd becomes writable.remain:table: (only whendatais a table andagainistrue) the data not yet written:- If no bytes were written (pure
EAGAIN/EWOULDBLOCK/EINTR), returns the originaldatatable unchanged. - If a partial write occurred, returns a new table with the unwritten suffix of the partially-written entry followed by all subsequent entries. The original
datatable is not modified.
- If no bytes were written (pure
Return value summary
| Situation | Returns |
|---|---|
| Full write | n |
| Partial write / EAGAIN (string) | n, nil, true |
| Partial write (table) | n, nil, true, remain |
| EAGAIN with no bytes written (table) | 0, nil, true, data |
| Error | nil, err |
local write = require('io.write')
-- write a string to a tmpfile
local f = assert(io.tmpfile())
local n, err = write(f, 'hello world')
assert(n == 11 and err == nil)
-- write a table of strings
n, err = write(f, {'hello', ' ', 'world'})
assert(n == 11 and err == nil)
-- write at a specific byte offset (pwrite/pwritev); FILE* position is unchanged
f:seek('set')
n, err = write(f, 'WORLD', 6) -- overwrites bytes 6-10
assert(n == 5 and f:seek() == 0)
-- non-blocking write with retry (pipe example)
local pipe = require('os.pipe')
local r, w = pipe(true) -- O_NONBLOCK
local data = {'hello', ' ', 'world'}
local again, remain
n, err, again, remain = write(w:fd(), data)
while again do
-- wait until the fd is writable (select/poll/epoll/kqueue ...)
n, err, again, remain = write(w:fd(), remain)
end
assert(err == nil)