求助: NodeJS 使用第三方库 返回值 乱码的问题 如何解决?

代码实现 解析 window的 lnk文件 得到实际指向的文件.解析的结果中 出现了乱码.
请问如何解决这个乱码?

let ws = require("windows-shortcuts");
var iconv = require("iconv-lite");
const chinese_encoding = "cp936";

const path3 =
  "C:/Users/40294/AppData/Roaming/Microsoft/Windows/Recent/说明.txt.lnk";
ws.query(path3, function (err, lnk) {
  console.log(err);
  console.log(lnk);//乱码
});

依赖

  "dependencies": {
    "iconv-lite": "^0.6.3",
    "win-lnk-parser": "^1.1.2",
    "windows-shortcuts": "^0.1.6"
  }

输出:

PS D:\program\recentfiles> node b.js    
null
{
  expanded: {
    target: 'D:\\DevTools\\nacos-server-2.2.2\\nacos\\bin\\˵��.txt',
    args: '',
    workingDir: 'D:\\DevTools\\nacos-server-2.2.2\\nacos\\bin',
    icon: ''
  },
  target: 'D:\\DevTools\\nacos-server-2.2.2\\nacos\\bin\\˵��.txt',
  args: '',
  workingDir: 'D:\\DevTools\\nacos-server-2.2.2\\nacos\\bin',
  runStyle: 1,
  icon: '',
  iconIndex: '0',
  hotkey: 0,
  desc: ''
}

尝试的方案:

  1. let buf = new Buffer.from(lnk.expanded.target);
    let data = iconv.decode(buf, "cp936");
  2. let data2= iconv.decode(lnk.target,"GBK")
    这两种方式解码出来也都是乱码.
阅读 1.8k
avatarAI BotBETA

您遇到的问题是 .lnk 文件中包含的文件路径使用的是非标准编码(可能是 UTF-16LE),而 windows-shortcuts 库在解析 .lnk 文件时没有正确处理这种编码。对于 Windows 快捷方式中的字符串,特别是当它们包含非 ASCII 字符时(如中文字符),通常使用的是 UTF-16LE 编码。

由于 iconv-lite 和直接操作 Buffer 的方法都没有成功,我们可以考虑直接在 windows-shortcuts 或其依赖库中查找是否有相关的配置或补丁来处理这个问题。但是,由于 windows-shortcuts 似乎是一个比较老的库(根据版本号),它可能不包含对 UTF-16LE 编码的内置支持。

作为替代方案,您可以尝试使用其他更现代或更活跃维护的库,如 win-lnk-parser(尽管您已经列出了它作为依赖,但您实际使用的代码示例中使用的是 windows-shortcuts)。不过,如果 win-lnk-parser 也不直接支持 UTF-16LE,您可能需要自己实现解析 UTF-16LE 编码字符串的逻辑。

以下是一个使用 BufferTextDecoder(Node.js 11+ 中内置)来尝试解析 UTF-16LE 编码字符串的示例(请注意,这只是一个概念性的示例,并且可能需要根据实际的 .lnk 文件格式进行调整):

let ws = require("windows-shortcuts"); // 或者尝试使用 win-lnk-parser

const path3 = "C:/Users/40294/AppData/Roaming/Microsoft/Windows/Recent/说明.txt.lnk";
ws.query(path3, function (err, lnk) {
  if (err) {
    console.error(err);
    return;
  }

  // 假设 lnk.expanded.target 或 lnk.target 包含的是 UTF-16LE 编码的 Buffer
  // 这里需要确认实际的 Buffer 来源和格式
  let targetBuffer = Buffer.from(lnk.expanded.target, 'hex'); // 如果不是 hex 格式,则可能需要其他方式获取 Buffer
  let decoder = new TextDecoder('utf-16le');
  let targetPath = decoder.decode(targetBuffer);

  console.log(targetPath); // 应该输出正确的文件路径
});

注意:这个示例假设 lnk.expanded.targetlnk.target 是一个以某种方式(可能是十六进制字符串)表示的 Buffer。但是,根据 windows-shortcuts 的文档或实现,这可能并不总是正确的。您需要查看该库的实际输出,并确定如何从它那里获取包含文件路径的原始 Buffer。

如果 windows-shortcuts 不提供这样的 Buffer,或者它内部以某种方式错误地处理了编码,那么您可能需要寻找一个更合适的库,或者自己编写代码来解析 .lnk 文件的二进制结构。这通常涉及对 Windows 快捷方式文件格式的深入了解,这可能会相当复杂。

2 个回答

就你这个问题而言,很简单,因为你用的 windows-shortcuts 这个包,他实际上是调用了一个 Shortcut.exe 然后获取这个 exe 的标准输出作为结果处理后给到了你的回调函数中。

而这里的问题就在于,他在内部调用 Shortcut.exe 的时候,使用 utf8 读取了标准输出,变成了。

EF BF BD EF BF BD EF BF BD EF BF BD

而这个就是一个替换字符(),而已这时候再传给你的时候,他就已经丢失了原有的信息了,自然,你再怎么转码,都无法得到你原本的字符,进而以为是乱码了。

我们不妨改写一下脚本验证一下

ws.query(path3, function (err, { target }) {
  fs.writeFile('./a.txt', target, console.error);
});

然后使用 imhex 打开 a.txt,就能看到,他已经是一个无效字符的占位符了。

image.png


所以,有没有解法?

我试了一下,你列出的另一个包 win-lnk-parser ,他在正确设置了编码的时候是可以取到的

const lnkParser = require('win-lnk-parser')

lnkParser(path3, 936).then(console.log)

我这边打印是可以的,看了一下原理,是利用了 cscript ,这个兼容性应该会更好一些。

然后我还看到了一个包 windows-shortcut-ps,这个是利用的 powershell,兼容性相比前一个要差一些(不过我这里安装不上这个包)

或者,你也可以去 Shortcut.exe 官网下载一下最新的,然后自己手动调用命令

Shortcut.exe /F:"测试.txt.lnk" /A:Q

再把 stdout 读入为 gbk 再转为 utf8,你可以直接参考 windows-shortcut 的代码,也没多少的。

这样写试试看 iconv.decode(Buffer.from(lnk.expanded.target,"binary"), "cp936");

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏