You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS向C++ node-addon-api模块传递非ASCII文件名失败排查

问题

需从NodeJS向基于node-addon-api开发的C模块传递含ä、ö、ü等非ASCII字符的文件路径。单独运行C代码时可正确识别文件,但通过NodeJS调用C++模块时,含特殊字符的路径会被判定为文件不存在,日志却能写入正确文件名。

相关代码

C++独立测试代码

// PathJSON.h

#pragma once
#include <filesystem>
#include <format>
#include <fstream>
#include <string>

namespace test_json {
  std::string checkPathInJSON(const char* json) {
    std::string pathString = json;
    std::filesystem::path p(pathString);
    std::string outString = "";
    if (std::filesystem::exists(p)) {
      outString = std::format("{};exists", pathString);
    }
    else {
      outString = std::format("{};MISSING", pathString);
    }
    std::filesystem::path logPath("d:/filelog.csv");
    std::ofstream ofs(logPath, std::ios::app);
    if (ofs.is_open()) {
      ofs << outString << std::endl;
      ofs.close();
    }
    return outString;
  }
}

// Central.cpp

#include <iostream>
#include "PathJSON.h"

int main() {
  std::string str = test_json::checkPathInJSON("D:/foo.txt");
  std::cout << str << std::endl;  // D:/foo.txt;exists
  str = test_json::checkPathInJSON("D:/föö.txt");
  std::cout << str << std::endl;  // D:/föö.txt;exists
}

单独运行C++代码的日志输出(正确):

D:/foo.txt;exists  // correct
D:/föö.txt;exists  // correct

NodeJS调用C++模块代码

// hello.cc

#include <iostream>
#include <napi.h>
#include "PathJSON.h"

Napi::String Method(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  std::string str = "";
  if(info.Length() == 1 && info[0].IsString()) {
    std::string par = info[0].As<Napi::String>();
    std::cout << par << std::endl;
    str = test_json::checkPathInJSON(par.c_str());
  }
  return Napi::String::New(env, str);
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, Method));
  return exports;
}

NODE_API_MODULE(node_api_1, Init);

// hello.js

console.log(addon.hello("D:/foo.txt"));
console.log(addon.hello("D:/föö.txt"));

通过NodeJS调用后的日志输出(异常):

D:/foo.txt;exists   // correct
D:/föö.txt;MISSING  // ERROR

尝试过用rapidjson传递数据、修改路径写法(如D:\\föö.txt),问题仍未解决。

解决方案

问题核心是NodeJS字符串为UTF-8编码,而Windows平台下std::filesystem默认使用系统本地编码(如GBK或UTF-16),直接将UTF-8转成std::string传递会导致非ASCII字符编码错乱,文件路径无法被正确识别。

修复步骤

  1. 在C++模块中使用宽字符串处理路径
    Node-API提供Napi::String::Utf16Value()方法可直接获取UTF-16编码的宽字符串,避免编码转换丢失信息。
  2. 修改路径检查函数支持宽字符输入
    调整函数参数为const wchar_t*,使用std::wstring和std::filesystem::path的宽字符构造方法。

修改后的代码

调整PathJSON.h

#pragma once
#include <filesystem>
#include <format>
#include <fstream>
#include <string>
#include <locale>
#include <codecvt>

namespace test_json {
  // 新增宽字符版本的路径检查函数
  std::wstring checkPathInJSONW(const wchar_t* json) {
    std::wstring pathString = json;
    std::filesystem::path p(pathString);
    std::wstring outString = L"";
    if (std::filesystem::exists(p)) {
      outString = std::format(L"{};exists", pathString);
    }
    else {
      outString = std::format(L"{};MISSING", pathString);
    }
    std::filesystem::path logPath(L"d:/filelog.csv");
    std::wofstream ofs(logPath, std::ios::app);
    if (ofs.is_open()) {
      ofs << outString << std::endl;
      ofs.close();
    }
    return outString;
  }

  // 保留原函数兼容其他调用场景(可选)
  std::string checkPathInJSON(const char* json) {
    std::string pathString = json;
    std::filesystem::path p(pathString);
    std::string outString = "";
    if (std::filesystem::exists(p)) {
      outString = std::format("{};exists", pathString);
    }
    else {
      outString = std::format("{};MISSING", pathString);
    }
    std::filesystem::path logPath("d:/filelog.csv");
    std::ofstream ofs(logPath, std::ios::app);
    if (ofs.is_open()) {
      ofs << outString << std::endl;
      ofs.close();
    }
    return outString;
  }
}

修改hello.cc

#include <iostream>
#include <napi.h>
#include "PathJSON.h"
#include <locale>
#include <codecvt>

// 工具函数:将宽字符串转为UTF-8字符串,返回给NodeJS
std::string wstring_to_utf8(const std::wstring& wstr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.to_bytes(wstr);
}

Napi::String Method(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  std::string str = "";
  if(info.Length() == 1 && info[0].IsString()) {
    // 获取NodeJS传递的UTF-16宽字符串
    std::wstring par = info[0].As<Napi::String>().Utf16Value();
    std::wstring w_result = test_json::checkPathInJSONW(par.c_str());
    // 转成UTF-8格式返回给NodeJS
    str = wstring_to_utf8(w_result);
  }
  return Napi::String::New(env, str);
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, Method));
  return exports;
}

NODE_API_MODULE(node_api_1, Init);

关键说明

  • UTF-16是Windows原生路径编码,NodeJS内部字符串也以UTF-16存储,直接用Utf16Value()获取宽字符串可避免编码转换错误。
  • 使用std::wofstream写入日志,确保宽字符能正确输出到文件。
  • 最终将宽字符串转回UTF-8返回给NodeJS,保证JS端能正常显示结果。

内容的提问来源于stack exchange,提问作者Markstar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:34:59