基于node-gyp的C++ Node Addon二进制文件读写失败问题解决
Node Addon集成fstream二进制文件写入失败的解决方案
我有一个用fstream实现二进制文件读写的C++类Controller.h,单独用gcc编译运行时,Insert函数能正常在data目录生成二进制文件。但把它集成到基于node-gyp开发的Node Addon后,调用Insert方法始终返回失败,其余逻辑都正常。相关代码如下:
相关代码
Controller.h
#pragma once #include <iostream> #include <fstream> #include <cstring> #include <string> #include <stdio.h> using namespace std; template <typename T> class Controller { private: T buf; char name[40]{}; public: explicit Controller(char *name) { strcpy(this->name, name); } char *GetName() { return name; } bool Insert(T model); // int Search(T &bus); // int Delete(T model); }; template <typename T> bool Controller<T>::Insert(T model) { fstream file; string db_dir = "data//"; string file_path = db_dir + name; file.open(file_path.c_str(), ios::out | ios::binary); if (file.fail() || file.bad()) { cout << "Failed" << endl; return false; } file.write((char *)&model, sizeof(model)); file.close(); cout << "Successfully wrote" << endl; return true; }
binding.gyp
{ "targets": [{ "target_name": "TDS", "cflags!": ["-fno-exceptions"], "cflags_cc!": ["-fno-exceptions"], "sources": [ "modules/src/main.cpp" ], "include_dirs": [ # "node_modules/node-addon-api", "<!(node -e \"require('nan')\")", "<!(node -p \"require('node-addon-api').include_dir\")" ], 'libraries': [], 'dependencies': [ "<!(node -p \"require('node-addon-api').gyp\")" ], 'defines': ['NAPI_DISABLE_CPP_EXCEPTIONS'] }] }
modules/src/main.cpp
#include <napi.h> #include "controller/Controller.h" #include "auth/Login.cpp" #include "model/Structs.h" using namespace Napi; using namespace std; Value InsertProducto(const CallbackInfo &info) { Env env = info.Env(); if (!info[0].IsObject()) { TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); return env.Null(); } Object obj = info[0].ToObject(); Array props = obj.GetPropertyNames(); Producto producto = *new Producto(); producto.id = obj.Get("id").ToNumber().Int32Value(); producto.id_proveedor = obj.Get("id_proveedor").ToNumber().Int32Value(); producto.stock = obj.Get("stock").ToNumber().Int64Value(); producto.precio = obj.Get("precio").ToNumber().FloatValue(); string descripcion = obj.Get("descripcion").ToString().Utf8Value(); if (descripcion.length() > sizeof(producto.descripcion)) { string mssg = "Excedeed maximum size: " + sizeof(producto.descripcion); cout << mssg << endl; TypeError::New(env, mssg).ThrowAsJavaScriptException(); return env.Null(); } strcpy(producto.descripcion, descripcion.c_str()); producto.stock_min = obj.Get("stock_min").ToNumber().Int64Value(); cout << "Producto id: " << producto.id << endl; cout << "Producto id_proveedor: " << producto.id_proveedor << endl; cout << "Producto stock: " << producto.stock << endl; cout << "Producto precio: " << producto.precio << endl; cout << "Producto descripcion: " << producto.descripcion << endl; cout << "Producto stock_min: " << producto.stock_min << endl; Controller<Producto> controller((char *)"Cliente.dat"); if (!controller.Insert(producto)) { return String::New(env, "Failed"); } return String::New(env, "Successfully inserted"); } Object Init(Env env, Object exports) { exports.Set(String::New(env, "InsertProducto"), Function::New<InsertProducto>(env)); return exports; } // Register and initialize native add-on NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init);
JavaScript调用代码
var TDS = require('../build/Release/TDS.node'); const producto = { "id": "1", "id_proveedor": "1", "stock": "5", "precio": "50.0", "descripcion": "Un producto", "stock_min": "500" } console.log(TDS); console.log(TDS.InsertProducto(producto)); module.exports = TDS;
解决方案
1. 自动创建data目录
Node Addon运行时,fstream不会自动创建不存在的目录,需要手动添加目录创建逻辑,兼容跨平台:
// 在Controller.h顶部添加头文件 #include <sys/stat.h> #include <errno.h> template <typename T> bool Controller<T>::Insert(T model) { fstream file; string db_dir = "data/"; // 改用单斜杠兼容跨平台 // 创建目录,已存在时不会报错 #ifdef _WIN32 _mkdir(db_dir.c_str()); #else mkdir(db_dir.c_str(), 0755); #endif string file_path = db_dir + name; file.open(file_path.c_str(), ios::out | ios::binary); if (!file.is_open()) { // 打印具体错误原因,方便排查 cout << "Open failed: " << strerror(errno) << endl; return false; } file.write((char *)&model, sizeof(model)); file.close(); cout << "Successfully wrote" << endl; return true; }
2. 修正相对路径问题
Node.js运行时的当前工作目录可能不是项目根目录,导致data/路径指向错误。可以先打印当前工作目录确认:
// 在main.cpp的InsertProducto函数中添加 #include <unistd.h> // Unix/Linux // Windows替换为#include <direct.h> Value InsertProducto(const CallbackInfo &info) { // ... 其他代码 char cwd[1024]; if (getcwd(cwd, sizeof(cwd)) != NULL) { cout << "Current working dir: " << cwd << endl; } else { perror("getcwd error"); } // ... 其他代码 }
如果路径不符,可以改用绝对路径,或者在JavaScript端通过process.cwd()传递正确的根目录给Addon。
3. 修复内存泄漏问题
原代码中Producto producto = *new Producto();会造成内存泄漏,直接声明栈对象即可:
// 替换为 Producto producto;
4. 优化错误判断逻辑
原代码用file.fail() || file.bad()判断不够准确,改用!file.is_open()更直接,同时结合strerror(errno)输出具体错误信息,快速定位问题(比如权限不足、路径不存在等)。
内容的提问来源于stack exchange,提问作者Jesus Jimenez
相关产品推荐
相关产品推荐

