1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| 'use strict';
const fs = require('fs');
/** * tailf * * @param {String} filename 文件名 * @param {Number} delay 读取不到内容时等待的时间,ms * @param {Function} onError 操作出错时的回调函数,onError(err) * @param {Function} onData 读取到文件内容时的回调函数,onData(data) */ function tailf(filename, delay, onError, onData) {
// 每次读取文件块大小,16K const CHUNK_SIZE = 16 * 1024; // 打开文件,获取文件句柄 fs.open(filename, 'r', (err, fd) => { if (err) return onError(err);
// 文件开始位置 fs.fstat(fd, (err, stats) => { if (err) return onError(err);
// 文件开始位置 let position = stats.size; // 循环读取 const loop = () => {
const buf = Buffer.alloc(CHUNK_SIZE); fs.read(fd, buf, 0, CHUNK_SIZE, position, (err, bytesRead, buf) => { if (err) return onError(err);
// 实际读取的内容长度以 bytesRead 为准 // 并且更新 position 位置 position += bytesRead; onData(buf.slice(0, bytesRead));
if (bytesRead < CHUNK_SIZE) { // 如果当前已到达文件末尾,则先等待一段时间再继续 // setTimeout(loop, delay); } else { loop(); } }); }; loop(); // 监听文件变化,如果收到 change 事件则尝试读取文件内容 fs.watch(filename, (event, filename) => { if (event === 'change') { loop(); } }); }); }); }
const filename = process.argv[2]; if (filename) { tailf(filename, 100, err => { if (err) console.error(err); }, data => { process.stdout.write(data); }); } else { console.log('使用方法: node tailf <文件名>'); }
|