一点一滴成长

导航

libuv文件系统

  1、读取和写入文件

  如下为异步打开test.dat文件后,读取文件数据并将其写入到标准输出的示例,读取和写入的时候使用uv_buf_t类型来作为缓存: 

#include "uv.h"
#include <assert.h>

uv_fs_t open_req, read_req, write_req;

void on_write(uv_fs_t* req) {
    if (req->result < 0) {
        fprintf(stderr, "Write error: %s\n", uv_strerror((int)req->result));
    }
    else {
        fprintf(stdout, "\nComplete: %d characters written\n", req->result);
    }
}

void on_read(uv_fs_t* req) {
    if (req->result < 0) { //error:uv_fs_t::result域为读取的数据量或错误码
        fprintf(stderr, "Read error: %s\n", uv_strerror(req->result));
    }
    else if (req->result == 0) { //读取到文件末尾
        uv_fs_t close_req;
        uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); 
        if (req->data)
            free(req->data);
    }
    else if (req->result > 0) { //读取到数据
        if (req->data) {
            auto iov = uv_buf_init((char*)(req->data), req->result);
            write_req.data = iov.base;
            uv_fs_write(uv_default_loop(), &write_req, 1/*标准输出*/, &iov, 1, -1, on_write);
        }
    }
}

void on_open(uv_fs_t* req)
{
    assert(req == &open_req);

    if (req->result >= 0) { //打开正常:uv_fs_t::result域为打开文件的fd(文件描述符)/ handle(句柄)
        int size = 1024; 
        auto iov = uv_buf_init((char*)malloc(size), size); //保存读取到的数据
        read_req.data = iov.base; //handle和request都有一个data域,可以用来存储上下文信息
        uv_fs_read(uv_default_loop(), &read_req, req->result, &iov, 1, -1, on_read);
    }
    else { //error
        fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result)); //uv_strerror()可以获取错误信息,uv_err_name()可以获取错误名字
    }
}

int main()
{
    //int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
    //参数flags与mode和标准的 Unix flags 相同,对应Windows,libuv会自动将参数转换为 Windows 环境下的相关标志位(flags)
    uv_fs_open(uv_default_loop(), &open_req, "test.dat", O_RDWR, 0, on_open/*文件打开的回调*/); //文件操作方法如果不指定回调的话操作则为同步模式
    uv_run(uv_default_loop(), UV_RUN_DEFAULT);

    //清理内存
    uv_fs_req_cleanup(&open_req);
    uv_fs_req_cleanup(&read_req);
    uv_fs_req_cleanup(&write_req);
}

  除了uv_fs_open()、uv_fs_read(),libuv还提供uv_fs_stat()、uv_fs_mkdir()、uv_fs_access()等文件或目录的操作方法。libuv还提供了监视文件和文件夹的变化的相关api,具体可以参考 File change events

2、流式操作

  也可以使用流式操作来进行读取或写入操作,通过uv_read_start()、uv_write()、uv_read_stop()方法,调用uv_read_start()后会读取数据直到可读数据为空或uv_read_stop()被调用。TCP套接字,UDP套接字,管道支持流式操作,可以为文件关联一个pipe来对文件进行uv_read_start()、uv_write()流式操作。如下分别为test.dat文件和标准输出关联了一个pipe管道,然后对文件进行读取,读取到数据后将其写入到标准输出。实际运行代码发现将管道关联到文件的方法会报错,原因不得而知:

#include "uv.h"
#include <assert.h>

uv_pipe_t stdout_pipe, file_pipe;

void on_stdout_write(uv_write_t* req, int status) {
    free(req->data);
    free(req);
}

void on_read_file(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
    if (nread > 0) { //读取到数据
        uv_write_t* req = (uv_write_t*)malloc(sizeof(uv_write_t));
        auto iov = uv_buf_init((char*)malloc(nread), nread);
        memcpy(iov.base, (*buf).base, nread);
        iov.len = nread;
        req->data = iov.base;
        uv_write(req, (uv_stream_t*)&stdout_pipe, &iov, 1, on_stdout_write/*写入数据回调*/);
    }
    else if (nread < 0) { //读取到结尾或发生错误
        if (nread == UV_EOF) { /*end of file*/
        
        }else if(nread == UV_ENOBUFS) { /*alloc_buf() returned a buffer of length 0*/
            
        }

        uv_close((uv_handle_t*)&stdout_pipe, NULL);
        uv_close((uv_handle_t*)&file_pipe, NULL);
    }
    else { //there is no more reading left

    }

    if (buf->base)
        free(buf->base);
}

void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
    *buf = uv_buf_init((char*)malloc(suggested_size), suggested_size);
}

int main()
{
    uv_loop_t* loop = uv_default_loop();

    uv_fs_t file_req;
    int fd = uv_fs_open(loop, &file_req, "test.dat", O_CREAT | O_RDWR, 0644, NULL/*回调为空表示同步模式*/);

    auto i = uv_pipe_init(loop, &file_pipe, 1); //创建有名管道
    auto n = uv_pipe_open(&file_pipe, fd); //将管道和文件描述符关联起来,文件描述符会自动设为非阻塞

    uv_pipe_init(loop, &stdout_pipe, 0);
    uv_pipe_open(&stdout_pipe, 1/*标准输出*/);

    auto r = uv_read_start((uv_stream_t*)&file_pipe, alloc_buffer/*提供保存读取到数据的缓存uv_buf_t的方法*/, on_read_file/*读取到数据的回调*/);
    uv_run(loop, UV_RUN_DEFAULT);
}

 

posted on 2024-05-09 09:50  整鬼专家  阅读(26)  评论(0编辑  收藏  举报