C++Builder环境下Android设备二进制文件访问移植咨询
基于C++Builder将WinCE文件操作代码移植到Android的解决方案
核心问题解答
1. 能否继续使用C++标准文件访问函数?
可以。CBuilder的Clang编译器完全支持标准C库,包括<cstdio>中的fopen、fwrite、fread、fseek等函数,在Android平台下可直接沿用这些函数进行二进制文件操作。
2. 具体实现步骤
(1)适配文件路径与权限
Android文件系统权限规则与WinCE不同,需注意:
- 私有存储:APP私有目录可直接访问,通过C++Builder的
System.IOUtils获取路径,如TPath::GetDocumentsPath().c_str() - 外部存储:需在
AndroidManifest.xml中添加READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限(Android 10+需适配分区存储规则,Android 11+可申请MANAGE_EXTERNAL_STORAGE权限) - 避免硬编码路径,优先使用系统API获取合法路径
(2)移除WinCE专属代码
原代码中的MultiByteToWideChar、ANSItoUnicode、TEXT宏等WinCE特有的编码转换和宏定义需删除,Android默认使用UTF-8编码,直接用char*路径即可。同时移除WinCE_DLL_API宏,改用标准C++函数声明。
(3)保留标准文件操作逻辑
fopen的打开模式(如"rb"、"r+b")、fseek的定位规则等与WinCE完全一致,无需修改。
3. 替代方案(若不想用标准函数)
如果需要更贴近Android原生的实现,可选择以下两种方式:
- C++Builder跨平台API:使用
System::Ioutils类,封装了TFile::ReadAllBytes()、TFile::WriteAllBytes()、TFile::Open()等跨平台文件操作方法 - Android NDK POSIX API:使用
open()、read()、write()、lseek()等底层系统调用,行为与标准C++函数类似
适配后的示例代码
以下是移除WinCE专属代码、适配Android环境的修改版本:
#include <cstdio> #include <cstring> #include <cstdlib> // 定义返回值常量 #define APPEND 0 #define DATA_EXIST 1 #define DATA_FULL -1 #define NOT_FOUND 2 // 补充HASH_HEAD结构体定义(原代码未提供) typedef struct { long MAX_REC; int TTLLEN; int ITMLEN; int HASHNUM; int tab_bottom; int inx_bottom; int HEADLEN; int start_byte; } HASH_HEAD; // 补充自定义字符串比较函数(原代码未提供) int Str_cmp(const unsigned char* str1, const unsigned char* str2, int len) { for (int i = 0; i < len; ++i) { if (str1[i] != str2[i]) { return str1[i] - str2[i]; } } return 0; } int Hash2(char *DaTa_Fn, char *InDex_Fn, unsigned char *item, unsigned char *ttl_data, int *tab ) { unsigned char *cmp; int i, ret; int nill = -1, inx; long sum, stm_loc, x, k, MAX_INX; HASH_HEAD hash_head; ret = f_read(&hash_head, sizeof(hash_head), DaTa_Fn, 0L); if (!ret) return -2; // 文件打开错误 MAX_INX = hash_head.MAX_REC / 2; MAX_INX += hash_head.MAX_REC; cmp = (unsigned char *)malloc(hash_head.TTLLEN + 4); memset(cmp, '\x0', hash_head.TTLLEN + 4); stm_loc = sum = 0L; strcpy((char *)cmp, (char *)item); for (k = 1L, sum = 0L, i = 0; i < hash_head.ITMLEN; i++, k++) sum += (long)item[i] * k * k * (k % 10L + 1L); x = sum % hash_head.HASHNUM; stm_loc = x * 4L; sum = stm_loc; ret = f_read(&inx, 2, InDex_Fn, stm_loc); if (!ret) return -2; // 文件打开错误 if (inx == nill && *tab == nill) { if (hash_head.tab_bottom >= hash_head.MAX_REC || hash_head.inx_bottom >= MAX_INX) { free(cmp); return DATA_FULL; } f_write(&hash_head.tab_bottom, 2, InDex_Fn, stm_loc); stm_loc = (long)hash_head.tab_bottom * (long)hash_head.TTLLEN + (long)hash_head.HEADLEN; f_write(ttl_data, hash_head.TTLLEN, DaTa_Fn, stm_loc); *tab = hash_head.tab_bottom; hash_head.tab_bottom += 1; stm_loc = 0L; f_write(&hash_head.tab_bottom, 2, DaTa_Fn, stm_loc); free(cmp); return APPEND; } else if (inx == nill && *tab != nill) { free(cmp); return NOT_FOUND; } else // 冲突处理 { while (1) { stm_loc = (long)inx * (long)hash_head.TTLLEN + (long)hash_head.HEADLEN; f_read(cmp, hash_head.TTLLEN, DaTa_Fn, stm_loc); i = Str_cmp(cmp + hash_head.start_byte, item, hash_head.ITMLEN); if (i == 0) { memcpy(ttl_data, cmp, hash_head.TTLLEN); *tab = inx; free(cmp); return DATA_EXIST; } else { sum += 2L; f_read(&inx, 2, InDex_Fn, sum); // 获取下一个索引 if (inx == nill && *tab != nill) { free(cmp); return NOT_FOUND; } if (inx == nill && *tab == nill) { if (hash_head.tab_bottom >= hash_head.MAX_REC || hash_head.inx_bottom >= MAX_INX) // 无法追加 { free(cmp); return DATA_FULL; } f_write(&hash_head.inx_bottom, 2, InDex_Fn, sum); stm_loc = (long)hash_head.inx_bottom * 4L; sum = stm_loc; f_write(&hash_head.tab_bottom, 2, InDex_Fn, sum); sum += 2L; f_write(&nill, 2, InDex_Fn, sum); hash_head.inx_bottom += 1; stm_loc = (long)hash_head.tab_bottom * (long)hash_head.TTLLEN + (long)hash_head.HEADLEN; f_write(ttl_data, hash_head.TTLLEN, DaTa_Fn, stm_loc); *tab = hash_head.tab_bottom; hash_head.tab_bottom += 1; f_write(&hash_head.tab_bottom, 2, DaTa_Fn, 0L); f_write(&hash_head.inx_bottom, 2, DaTa_Fn, 2L); free(cmp); return APPEND; } else { stm_loc = (long)inx * 4L; sum = stm_loc; f_read(&inx, 2, InDex_Fn, stm_loc); } } } } } /*--------F_read---------*/ int f_read(void *buffer, int count, char *fn, long fpos ) { int num; FILE *fp; if ((fp = fopen(fn, "rb")) == NULL) { return 0; } fseek(fp, fpos, SEEK_SET); num = fread(buffer, 1, count, fp); fclose(fp); return (num == count) ? 1 : 0; } /*--------F_append---------*/ int f_append(void *buffer, int count, char *fn ) { int num; FILE *fp; if ((fp = fopen(fn, "r+b")) == NULL) { // 文件不存在时尝试创建 if ((fp = fopen(fn, "wb")) == NULL) return 0; } fseek(fp, 0, SEEK_END); num = fwrite(buffer, 1, count, fp); fclose(fp); return (num == count) ? 1 : 0; } /*--------F_write---------*/ int f_write(void *buffer, int count, char *fn, long fpos ) { int num; FILE *fp; if ((fp = fopen(fn, "r+b")) == NULL) { return 0; } fseek(fp, fpos, SEEK_SET); num = fwrite(buffer, 1, count, fp); fclose(fp); return (num == count) ? 1 : 0; }
注意事项
- 确保C++Builder项目目标平台选择Android,编译器使用Clang
- 测试时优先使用APP私有目录,避免权限问题
- 若原代码中
HASH_HEAD结构体或其他辅助函数定义与示例不同,需根据实际情况调整
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

