Skip to content

Commit

Permalink
fs, feat: support fs.write.
Browse files Browse the repository at this point in the history
  • Loading branch information
xicilion committed Nov 19, 2022
1 parent 99d7d87 commit 4f9780b
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 3 deletions.
42 changes: 42 additions & 0 deletions fibjs/include/ifs/fs.h
Expand Up @@ -69,6 +69,8 @@ class fs_base : public object_base {
static result_t readFile(exlib::string fname, exlib::string encoding, Variant& retVal, AsyncEvent* ac);
static result_t readFile(exlib::string fname, v8::Local<v8::Object> options, Variant& retVal, AsyncEvent* ac);
static result_t readLines(exlib::string fname, int32_t maxlines, v8::Local<v8::Array>& retVal);
static result_t write(int32_t fd, Buffer_base* buffer, int32_t offset, int32_t length, int32_t position, int32_t& retVal, AsyncEvent* ac);
static result_t write(int32_t fd, exlib::string string, int32_t position, exlib::string encoding, int32_t& retVal, AsyncEvent* ac);
static result_t writeTextFile(exlib::string fname, exlib::string txt, AsyncEvent* ac);
static result_t writeFile(exlib::string fname, Buffer_base* data, AsyncEvent* ac);
static result_t appendFile(exlib::string fname, Buffer_base* data, AsyncEvent* ac);
Expand Down Expand Up @@ -126,6 +128,7 @@ class fs_base : public object_base {
static void s_static_readTextFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_readFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_readLines(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_write(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_writeTextFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_writeFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_static_appendFile(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down Expand Up @@ -169,6 +172,8 @@ class fs_base : public object_base {
ASYNC_STATICVALUE2(fs_base, readTextFile, exlib::string, exlib::string);
ASYNC_STATICVALUE3(fs_base, readFile, exlib::string, exlib::string, Variant);
ASYNC_STATICVALUE3(fs_base, readFile, exlib::string, v8::Local<v8::Object>, Variant);
ASYNC_STATICVALUE6(fs_base, write, int32_t, Buffer_base*, int32_t, int32_t, int32_t, int32_t);
ASYNC_STATICVALUE5(fs_base, write, int32_t, exlib::string, int32_t, exlib::string, int32_t);
ASYNC_STATIC2(fs_base, writeTextFile, exlib::string, exlib::string);
ASYNC_STATIC2(fs_base, writeFile, exlib::string, Buffer_base*);
ASYNC_STATIC2(fs_base, appendFile, exlib::string, Buffer_base*);
Expand Down Expand Up @@ -248,6 +253,8 @@ inline ClassInfo& fs_base::class_info()
{ "readFile", s_static_readFile, true, true },
{ "readFileSync", s_static_readFile, true, false },
{ "readLines", s_static_readLines, true, false },
{ "write", s_static_write, true, true },
{ "writeSync", s_static_write, true, false },
{ "writeTextFile", s_static_writeTextFile, true, true },
{ "writeTextFileSync", s_static_writeTextFile, true, false },
{ "writeFile", s_static_writeFile, true, true },
Expand Down Expand Up @@ -889,6 +896,41 @@ inline void fs_base::s_static_readLines(const v8::FunctionCallbackInfo<v8::Value
METHOD_RETURN();
}

inline void fs_base::s_static_write(const v8::FunctionCallbackInfo<v8::Value>& args)
{
int32_t vr;

METHOD_NAME("fs.write");
METHOD_ENTER();

ASYNC_METHOD_OVER(5, 2);

ARG(int32_t, 0);
ARG(obj_ptr<Buffer_base>, 1);
OPT_ARG(int32_t, 2, 0);
OPT_ARG(int32_t, 3, -1);
OPT_ARG(int32_t, 4, -1);

if (!cb.IsEmpty())
hr = acb_write(v0, v1, v2, v3, v4, cb, args);
else
hr = ac_write(v0, v1, v2, v3, v4, vr);

ASYNC_METHOD_OVER(4, 2);

ARG(int32_t, 0);
ARG(exlib::string, 1);
OPT_ARG(int32_t, 2, -1);
OPT_ARG(exlib::string, 3, "utf8");

if (!cb.IsEmpty())
hr = acb_write(v0, v1, v2, v3, cb, args);
else
hr = ac_write(v0, v1, v2, v3, vr);

METHOD_RETURN();
}

inline void fs_base::s_static_writeTextFile(const v8::FunctionCallbackInfo<v8::Value>& args)
{
METHOD_NAME("fs.writeTextFile");
Expand Down
68 changes: 66 additions & 2 deletions fibjs/src/fs/fs.cpp
Expand Up @@ -232,8 +232,6 @@ result_t fs_base::read(int32_t fd, Buffer_base* buffer, int32_t offset, int32_t
if (offset < 0 || offset >= bufLength)
return Runtime::setError("fs: Offset is out of bounds");

exlib::string strBuf;

if (length < 0 || (offset + length > bufLength)) {
return Runtime::setError("fs: Length extends beyond buffer");
}
Expand All @@ -243,6 +241,7 @@ result_t fs_base::read(int32_t fd, Buffer_base* buffer, int32_t offset, int32_t
return CHECK_ERROR(LastError());
}

exlib::string strBuf;
if (length > 0) {
strBuf.resize(length);
int32_t sz = length;
Expand Down Expand Up @@ -270,6 +269,71 @@ result_t fs_base::read(int32_t fd, Buffer_base* buffer, int32_t offset, int32_t
return buffer->write(strBuf, offset, (int32_t)strBuf.length(), "utf8", retVal);
}

result_t fs_base::write(int32_t fd, Buffer_base* buffer, int32_t offset, int32_t length,
int32_t position, int32_t& retVal, AsyncEvent* ac)
{
if (fd < 0)
return CHECK_ERROR(CALL_E_INVALID_CALL);

if (ac->isSync())
return CHECK_ERROR(CALL_E_NOSYNC);

int32_t bufLength;
buffer->get_length(bufLength);

if (offset < 0 || offset >= bufLength)
return Runtime::setError("fs: Offset is out of bounds");

if (offset + length > bufLength)
return Runtime::setError("fs: Length extends beyond buffer");

if (length < 0)
length = bufLength - offset;

if (position > -1) {
if (_lseeki64(fd, position, SEEK_SET) < 0)
return CHECK_ERROR(LastError());
}

if (length > 0) {
exlib::string strBuf;

buffer->toString(strBuf);
int32_t sz = length;
const char* p = strBuf.c_str() + offset;

while (sz) {
int32_t n = (int32_t)::_write(fd, p, sz > STREAM_BUFF_SIZE ? STREAM_BUFF_SIZE : sz);
if (n < 0)
return CHECK_ERROR(LastError());

sz -= n;
p += n;
}
}

retVal = length;

return 0;
}

result_t fs_base::write(int32_t fd, exlib::string string, int32_t position,
exlib::string encoding, int32_t& retVal, AsyncEvent* ac)
{
if (fd < 0)
return CHECK_ERROR(CALL_E_INVALID_CALL);

if (ac->isSync())
return CHECK_ERROR(CALL_E_NOSYNC);

obj_ptr<Buffer_base> buf = new Buffer();
result_t hr = buf->append(string, encoding);
if (hr < 0)
return CHECK_ERROR(hr);

return write(fd, buf, 0, -1, position, retVal, ac);
}

class AutoReq : public uv_fs_t {
public:
~AutoReq()
Expand Down
19 changes: 19 additions & 0 deletions idl/zh-cn/fs.idl
Expand Up @@ -287,6 +287,25 @@ module fs
*/
static Array readLines(String fname, Integer maxlines = -1);

/*! @brief 根据文件描述符,向文件写入内容
@param fd 文件描述符
@param buffer 待写入的 Buffer 对象
@param offset Buffer 数据读取偏移量, 默认为 0
@param length 文件写入字节数,默认为 -1
@param position 文件写入取位置,默认为当前文件位置
@return 实际写入的字节数
*/
static Integer write(Integer fd, Buffer buffer, Integer offset = 0, Integer length = -1, Integer position = -1) async;

/*! @brief 根据文件描述符,向文件写入内容
@param fd 文件描述符
@param string 待写入的字符串
@param position 文件写入取位置,默认为当前文件位置
@param encoding 指定解码方式,缺省解码 utf8
@return 实际写入的字节数
*/
static Integer write(Integer fd, String string, Integer position = -1, String encoding = "utf8") async;

/*! @brief 创建文本文件,并写入内容
@param fname 指定文件名
@param txt 指定要写入的字符串
Expand Down
27 changes: 27 additions & 0 deletions npm/types/dts/module/fs.d.ts
Expand Up @@ -438,6 +438,33 @@ declare module 'fs' {
*/
function readLines(fname: string, maxlines?: number): any[];

/**
* @description 根据文件描述符,向文件写入内容
* @param fd 文件描述符
* @param buffer 待写入的 Buffer 对象
* @param offset Buffer 数据读取偏移量, 默认为 0
* @param length 文件写入字节数,默认为 -1
* @param position 文件写入取位置,默认为当前文件位置
* @return 实际写入的字节数
*
*/
function write(fd: number, buffer: Class_Buffer, offset?: number, length?: number, position?: number): number;

function write(fd: number, buffer: Class_Buffer, offset?: number, length?: number, position?: number, callback?: (err: Error | undefined | null, retVal: number)=>any): void;

/**
* @description 根据文件描述符,向文件写入内容
* @param fd 文件描述符
* @param string 待写入的字符串
* @param position 文件写入取位置,默认为当前文件位置
* @param encoding 指定解码方式,缺省解码 utf8
* @return 实际写入的字节数
*
*/
function write(fd: number, string: string, position?: number, encoding?: string): number;

function write(fd: number, string: string, position?: number, encoding?: string, callback?: (err: Error | undefined | null, retVal: number)=>any): void;

/**
* @description 创建文本文件,并写入内容
* @param fname 指定文件名
Expand Down
40 changes: 39 additions & 1 deletion npm/types/dts/module/test.d.ts
Expand Up @@ -178,8 +178,46 @@ declare module 'test' {

/**
* @description 开始执行定义的测试模块
*
* 测试运行完成后,将以以下形式返回测试结果:
* ```JavaScript
* {
* "total": 2, // 总测试项目数
* "pass": 2, // 通过测试项目数
* "fail": 0, // 失败测试项目数
* "skip": 0, // 跳过测试项目数
* "todo": 0, // 计划测试项目数
* "time": 0.000000, // 测试耗时
* "cases": [ // 测试项目列表
* {
* "name": "test", // 测试项目名称
* "time": 0.000000, // 测试耗时
* "result": true, // 测试结果
* "error": null // 测试错误信息
* },
* {
* "name": "sub cases", // 测试组名称
* "total": 1, // 总测试项目数
* "pass": 1, // 通过测试项目数
* "fail": 0, // 失败测试项目数
* "skip": 0, // 跳过测试项目数
* "todo": 0, // 计划测试项目数
* "time": 0.000000, // 测试耗时
* "cases": [ // 测试项目列表
* {
* "name": "test", // 测试项目名称
* "time": 0.000000, // 测试耗时
* "result": true, // 测试结果
* "error": null // 测试错误信息
* }
* ]
* }
* ]
* }
* ```
*
* @param mode 指定进行测试模式,ERROR 时,项目报错信息集中在报告后显示,低于 ERROR 时,输出信息随时显示,高于 ERROR 时,只显示报告
* @return 返回测试用例统计结果,正确则返回 0,错误则返回错误个数
* @return 返回测试结果
*
*/
function run(mode: number): FIBJS.GeneralObject;
Expand Down
68 changes: 68 additions & 0 deletions test/fs_test.js
Expand Up @@ -802,6 +802,74 @@ describe('fs', () => {
});
});

describe('write', () => {
var fd;

beforeEach(() => fd = fs.open('test.txt', 'w+'));
afterEach(() => fs.close(fd));
after(() => {
try {
fs.unlink('test.txt');
} catch (e) { }
});

it("normal write", () => {
var buf = Buffer.alloc(3);
fs.write(fd, 'abc');
fs.read(fd, buf, 0, 3, 0);
assert.deepEqual(buf, new Buffer('abc'));
});

it("multi write", () => {
var buf = Buffer.alloc(6);
fs.write(fd, 'abc');
fs.write(fd, 'abc');
fs.read(fd, buf, 0, 6, 0);
assert.deepEqual(buf, new Buffer('abcabc'));
});

it("spec offset", () => {
var buf = Buffer.from("abc");
fs.write(fd, buf, 1);
fs.write(fd, 'd');
fs.read(fd, buf, 0, 3, 0);
assert.deepEqual(buf, new Buffer('bcd'));

assert.throws(() => {
fs.write(fd, buf, -1);
});

assert.throws(() => {
fs.write(fd, buf, 4);
});
});

it("spec length", () => {
var buf = Buffer.from("abc");
fs.write(fd, buf, 0, 2);
fs.write(fd, 'd');
fs.read(fd, buf, 0, 3, 0);
assert.deepEqual(buf, new Buffer('abd'));

var buf = Buffer.from("abc");
fs.write(fd, buf, 1, 2, 0);
fs.write(fd, 'd');
fs.read(fd, buf, 0, 3, 0);
assert.deepEqual(buf, new Buffer('bcd'));

assert.throws(() => {
fs.write(fd, buf, 0, 4);
});
});

it("spec position", () => {
var buf = Buffer.from("abc");
fs.write(fd, buf, 0, 3, 10);
fs.read(fd, buf, 0, 3, 10);
assert.deepEqual(buf, new Buffer('abc'));
});
});

it("readdir", () => {
var fl = fs.readdir(path.join(__dirname, 'vm_test'));
fl.sort();
Expand Down

0 comments on commit 4f9780b

Please sign in to comment.