C语言跨平台实现自定义缓冲区的类fread流读取功能
跨平台内存二进制读取流实现
直接实现一套基于纯C标准库的内存读取上下文即可,完全不需要依赖平台特定API,行为对齐标准库文件流接口,可直接对接你现有的read/read_buf设计。
核心结构与基础实现
核心逻辑仅维护缓冲区基址、总长度、当前读取偏移三个字段,无额外依赖:
#include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // 内存二进制读取上下文,等价于Python io.BytesIO / C# BinaryReader typedef struct { const uint8_t* base; // 缓冲区起始地址 size_t length; // 缓冲区总长度 size_t pos; // 当前读取偏移 } MemReader;
基础操作函数的行为和C标准库文件流接口完全对齐:
// 初始化内存读取器,绑定外部传入的缓冲区,不做内存拷贝 void mem_reader_init(MemReader* reader, const void* buf, size_t size) { reader->base = (const uint8_t*)buf; reader->length = size; reader->pos = 0; } // 等价于fread的内存读取实现,返回实际成功读取的元素个数 size_t mem_read(MemReader* reader, void* out, size_t elem_size, size_t elem_count) { if (reader->pos > reader->length) { return 0; } size_t remain = reader->length - reader->pos; size_t need = elem_size * elem_count; size_t copy_len = need > remain ? remain : need; if (copy_len > 0 && out != NULL) { memcpy(out, reader->base + reader->pos, copy_len); } reader->pos += copy_len; return copy_len / elem_size; } // 读取单个基础类型值的便捷宏,返回1表示读取成功、0表示缓冲区越界 #define MEM_READER_READ_ONE(reader, ptr) mem_read((reader), (ptr), sizeof(*(ptr)), 1) // 跳转读取位置,whence参数和fseek完全一致:支持SEEK_SET/SEEK_CUR/SEEK_END,返回0表示操作成功 int mem_seek(MemReader* reader, long offset, int whence) { size_t new_pos; switch (whence) { case SEEK_SET: new_pos = (size_t)offset; break; case SEEK_CUR: new_pos = reader->pos + (size_t)offset; break; case SEEK_END: new_pos = reader->length + (size_t)offset; break; default: return -1; } if (new_pos > reader->length) { return -1; } reader->pos = new_pos; return 0; } // 获取当前读取位置,等价于ftell size_t mem_tell(const MemReader* reader) { return reader->pos; } // 判断是否读到缓冲区末尾 int mem_eof(const MemReader* reader) { return reader->pos >= reader->length; }
如果需要处理跨平台字节序问题,只需要在基础读取函数上封装对应大小端的读取方法即可,比如
mem_read_u32_le、mem_read_u16_be这类,不需要改动核心读取逻辑。
对接现有接口
你原有的函数设计不需要改动,直接按如下逻辑实现即可,全程无平台相关调用:
// 读取整个文件到内存后转交read_buf处理 void* read(const char* filename) { FILE* f = fopen(filename, "rb"); if (!f) return NULL; if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; } long file_size = ftell(f); if (file_size < 0) { fclose(f); return NULL; } rewind(f); void* buf = malloc((size_t)file_size); if (!buf) { fclose(f); return NULL; } size_t read_len = fread(buf, 1, (size_t)file_size, f); fclose(f); if (read_len != (size_t)file_size) { free(buf); return NULL; } void* result = read_buf(buf, (size_t)file_size); free(buf); // 如果需要解析后长期持有缓冲区,可移除该行,按自身内存管理逻辑调整 return result; } // read_buf内部使用MemReader逐段解析二进制格式 void* read_buf(const void* buf, size_t size) { MemReader reader; mem_reader_init(&reader, buf, size); // 解析示例: // uint32_t file_magic; // MEM_READER_READ_ONE(&reader, &file_magic); // uint16_t format_version; // MEM_READER_READ_ONE(&reader, &format_version); // 其余字段解析逻辑... return NULL; // 替换为实际解析结果的返回逻辑 }
方案特性
- 完全兼容C89及以上标准,全平台通用,无第三方依赖
- 零额外内存拷贝,读取器仅持有缓冲区指针,运行开销极低
- 接口和标准库文件流操作对齐,学习成本为零
- 可灵活扩展变长字符串读取、字节序转换等二进制解析常用能力
内容的提问来源于stack exchange,提问作者demberto
相关产品推荐
相关产品推荐

