Having a simple C++ class that uses fstream
to write/read binary files
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;
}
The code above compiled with gcc
works as expected. The Insert
function creates a binary file into db//file.dat
. But How to achieve the same as a Node addon using node-gyp?
Here's my 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']
}]
}
And my 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();
// for (unsigned int j = 0; j < props.Length(); j++)
// {
// // printf("key: %s: value: %s\n",
// // props.Get(j).ToString().Utf8Value().c_str(),
// // obj.Get(props.Get(j)).ToString().Utf8Value().c_str());
// string key = props.Get(j).ToString().Utf8Value();
// cout << obj.Get(key).ToString().Utf8Value().c_str() << endl;
// }
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);
I'm able to use this function in JavaScript this way:
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;
And everything works except for the controller.Insert
call that uses the same Controller.h
from above. I'm always seeing the "Failed"
message.
How can write/read any binary file using C++ node addons?
Here's the source code for anyone looking to give it a try: https://github.com/JesusJimenezG/transactional-system-managemente
The problem was solved by changing the way of accessing the folder on which to write the file:
Instead of:
string db_dir = "data/";
string file_path = db_dir + name;
I'm using filesystem::current_path()
now:
filesystem::path cwd = std::filesystem::current_path() / name;
file.open(cwd.c_str(), ios::out | ios::binary);
This way works!