Skip to content

Instantly share code, notes, and snippets.

@osdrv
Created April 6, 2020 08:17
Show Gist options
  • Save osdrv/e000165edeb14981f783ce4758fa6541 to your computer and use it in GitHub Desktop.
Save osdrv/e000165edeb14981f783ce4758fa6541 to your computer and use it in GitHub Desktop.
const fs = require("fs")
const DefaultBlockSize = 4096
function tail(fileName, nLines) {
return new Promise((resolve, reject) => {
fs.stat(fileName, (err, stat) => {
if (err != null) {
return reject(err)
}
if (nLines <= 0) {
return resolve([])
}
let blksize = stat.blksize || DefaultBlockSize,
size = stat.size
fs.open(fileName, "r", (err, fd) => {
if (err != null) {
return reject(err)
}
let thumbstones = [size],
buf = Buffer.alloc(blksize)
let readNextBlock = (until) => {
if (until < 0) {
thumbstones.push(0)
return readNormal(fd, thumbstones, resolve, reject)
}
let toRead = Math.min(until, blksize),
from = until - toRead
fs.read(fd, buf, 0, toRead, from, (err, nBytes, buf) => {
if (err != null) {
return reject(err)
}
let i = nBytes - 1
while (i >= 0) {
if (buf[i] == 10) { // \n
if (i > 0 && buf[i - 1] == 13) { // \r
i--
}
if (thumbstones.length == 1 &&
thumbstones[0] - (from + i) <= 1) {
thumbstones[0] = from + i
} else {
thumbstones.push(from + i)
}
if (thumbstones.length > nLines) {
return readNormal(fd, thumbstones, resolve, reject)
}
}
i--
}
readNextBlock(from > 0 ? from : -1)
})
}
readNextBlock(size)
})
})
})
}
// eslint-disable-next-line
function readNormal(fd, thumbstones, resolve, reject) {
thumbstones = thumbstones.reverse()
let maxLen = 0
for (let i = 0; i < thumbstones.length - 1; i++) {
let len = thumbstones[i + 1] - thumbstones[i]
if (len > maxLen) {
maxLen = len
}
}
let buf = Buffer.alloc(maxLen),
lines = []
let readNextBlock = (ix) => {
if (ix >= thumbstones.length-1) {
return resolve(lines)
}
fs.read(
fd,
buf,
0,
thumbstones[ix + 1] - thumbstones[ix],
thumbstones[ix],
(err, nBytes, buf) => {
if (err != null) {
return reject(err)
}
let off = 0,
until = nBytes
while (off < nBytes - 1 && (buf[off] == 10 || buf[off] == 13)) {
off++
}
while (until > off && (buf[off] == 10 || buf[off] == 13)) {
until--
}
let line = buf.slice(off, until).toString("utf8")
lines.push(line)
readNextBlock(ix + 1)
}
)
}
readNextBlock(0)
}
module.exports.tail = tail
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment