使用dockerode读取文件返回多余编码字符,如何正确获取内容?
解决Dockerode读取容器文件时的流前缀字符问题
你看到的\x01\x00\x00\x00\x00\x00\x00\x02是Docker exec流的多路复用头部,每个输出块前都会附带8字节标识:
- 第1字节:流类型(
0x01代表标准输出stdout,0x02代表标准错误stderr) - 后续7字节:以大端序表示的当前块数据长度
不需要用substring硬截字符,有两种标准处理方式:
方案一:用Dockerode内置分流工具
Dockerode的modem模块提供了demuxStream方法,可自动拆分stdout和stderr流,直接获取纯净的标准输出内容:
const { Modem } = require('dockerode'); const modem = new Modem(); container.exec({ Cmd: ['cat', '/myfile.json'], // 直接执行cat,无需通过sh -c中转 AttachStdin: false, // 不需要输入流时关闭,减少资源占用 AttachStdout: true, AttachStderr: true, }, (err, exec) => { if (err) { return res.status(500).json({ success: false, message: '创建exec实例失败' }); } exec.start({}, (err, stream) => { if (err) { return res.status(500).json({ success: false, message: '读取文件失败' }); } let stdoutContent = ''; // 处理标准输出的流 const stdoutStream = new require('stream').Writable({ write(chunk, encoding, callback) { stdoutContent += chunk.toString(); callback(); } }); // 处理标准错误的流(可按需记录日志) const stderrStream = new require('stream').Writable({ write(chunk, encoding, callback) { callback(); } }); // 自动拆分多路复用流 modem.demuxStream(stream, stdoutStream, stderrStream); stream.on('end', () => { return res.status(200).json({ success: true, data: stdoutContent }); }); }); });
方案二:手动解析流头部
如果不想额外创建流,也可以直接跳过固定长度的头部,提取有效数据:
container.exec({ Cmd: ['cat', '/myfile.json'], AttachStdin: false, AttachStdout: true, AttachStderr: true, }, (err, exec) => { exec.start({}, (err, stream) => { if (err) { return res.status(500).json({ success: false, message: '读取文件失败' }); } let data = ''; stream.on('data', (chunk) => { // 跳过固定8字节的头部,提取后续有效内容 const content = chunk.slice(8); data += content.toString(); }); stream.on('end', () => { return res.status(200).json({ success: true, data }); }); }); });
注意:Docker会保证每个数据块的头部与内容完整发送,因此跳过固定8字节头部的方式比硬截字符串更可靠,不会因内容长度变化出现错误。
内容的提问来源于stack exchange,提问作者Finbar
相关产品推荐
相关产品推荐

