如何实现仅在写缓冲区满时触发写入的fwrite类似函数?
问题
我想要实现一个类似fwrite的函数,但当前编写的mini_fwrite未能满足需求。我希望仅当写缓冲区(buffer_write)被填满时才触发write系统调用,现有代码如下:
相关结构体定义
typedef struct MYFILE { int fd; void *buffer_read; void *buffer_write; int ind_read; int ind_write; } MYFILE;
mini_fopen函数
int IOBUFFER_SIZE = 2048; MYFILE *mini_fopen(char *file, char mode) { if (file == NULL) return NULL; MYFILE *fo; fo = (MYFILE *)mini_calloc(sizeof(MYFILE), 1); if (mode == 'r') fo->fd = open(file, O_RDONLY); else if (mode == 'w') fo->fd = open(file, O_WRONLY); else if (mode == 'b') fo->fd = open(file, O_RDWR); else if (mode == 'a') fo->fd = open(file, O_APPEND); else mini_perror("Error\n"); if (fo->fd == -1) return NULL; fo->ind_read = -1; fo->ind_write = -1; fo->buffer_read = NULL; fo->buffer_write = NULL; return fo; }
当前mini_fwrite函数
int mini_fwrite(void *buffer, int size_element, int number_element, MYFILE *file) { if (file->ind_write == -1) { file->buffer_write = mini_calloc(IOBUFFER_SIZE, 1); file->ind_write = 0; } int i = 0; while (i < size_element * number_element) { ((char *)file->buffer_write)[file->ind_write] = ((char *)buffer)[i]; file->ind_write++; i++; if (file->ind_write == IOBUFFER_SIZE) { if (write(file->fd, file->buffer_write, file->ind_write) == -1) { mini_perror("Error"); } file->ind_write = 0; } } return i; }
修改方案
原代码存在效率低下(逐字节拷贝)、返回值语义不符、错误处理不严谨的问题。以下是针对性修改:
- 批量填充缓冲区:计算缓冲区剩余空间,一次性拷贝最大可行字节数,减少循环开销
- 修正返回值:返回成功写入的元素个数(而非字节数),与标准
fwrite行为对齐 - 增强错误处理:
write调用失败时立即返回错误状态,避免无效操作 - 完善边界逻辑:处理写入数据量远大于缓冲区的场景,确保填满即写
修改后的mini_fwrite代码
int mini_fwrite(void *buffer, int size_element, int number_element, MYFILE *file) { // 参数合法性校验 if (!file || !buffer || size_element <= 0 || number_element <= 0) { return 0; } const int total_bytes = size_element * number_element; int bytes_processed = 0; char *src_ptr = (char *)buffer; // 初始化写缓冲区(未初始化时) if (file->ind_write == -1) { file->buffer_write = mini_calloc(IOBUFFER_SIZE, 1); if (!file->buffer_write) { mini_perror("Failed to allocate write buffer"); return -1; } file->ind_write = 0; } char *buf_ptr = (char *)file->buffer_write; while (bytes_processed < total_bytes) { // 计算缓冲区剩余可写空间 int buf_remaining = IOBUFFER_SIZE - file->ind_write; // 计算本次拷贝的字节数:取剩余数据和缓冲区空间的较小值 int copy_size = total_bytes - bytes_processed; if (copy_size > buf_remaining) { copy_size = buf_remaining; } // 批量拷贝数据到缓冲区 memcpy(buf_ptr + file->ind_write, src_ptr + bytes_processed, copy_size); file->ind_write += copy_size; bytes_processed += copy_size; // 缓冲区已满,触发系统调用写入 if (file->ind_write == IOBUFFER_SIZE) { ssize_t write_ret = write(file->fd, buf_ptr, IOBUFFER_SIZE); if (write_ret == -1) { mini_perror("Write system call failed"); return -1; } file->ind_write = 0; // 重置缓冲区索引 } } // 返回成功写入的元素个数 return bytes_processed / size_element; }
补充优化建议
如果需要在缓冲区未填满时强制写入(比如程序退出前),可实现mini_fflush函数:
int mini_fflush(MYFILE *file) { if (!file || file->ind_write <= 0 || !file->buffer_write) { return 0; } ssize_t flush_ret = write(file->fd, file->buffer_write, file->ind_write); if (flush_ret == -1) { mini_perror("Flush failed"); return -1; } file->ind_write = 0; return 0; }
另外,原mini_fopen中O_APPEND模式的打开参数建议修正为O_WRONLY | O_APPEND | O_CREAT,否则文件不存在时无法创建,会导致打开失败。
内容的提问来源于stack exchange,提问作者Bayto Malin
相关产品推荐
相关产品推荐

