获取文件下的名字并访问之
如果我们只知道文件夹的名字,但并不知道文件夹下面有哪些具体文件,比如我们只知道有个dir文件夹,但不知道下面的具体情况。那么我们可以使用AAssetDir_getNextFileName
来获取文件夹的文件名。但是有个问题,这个方法只能获得文件夹下的文件名,而无法获得子文件夹,有哪位知道的请告知。
注意:AAssetDir_getNextFileName
只返回文件名,而不是该文件的完整路径,比如只会返回cs.jpg,而不是dir/cs.jpg,所以如果直接把AAssetDir_getNextFileName
的返回结果传给AAssetManager_open
会读取不到正确的文件,返回NULL.
AAssetDir *assetDir = AAssetManager_openDir(nativeasset, "dir");const char *filename = AAssetDir_getNextFileName(assetDir);while (filename != NULL){ char fullname[1024]; sprintf(fullname, "dir/%s", filename); //get the full path
AAsset *file = AAssetManager_open(nativeasset, fullname, AASSET_MODE_BUFFER); if(file == NULL){
LOGD("FILE NULL %s", filename); break;
} size_t fileLength = AAsset_getLength(file);
LOGD("filename next:%s, size:%d", filename, fileLength); char *buffer = (char*)malloc(fileLength);
AAsset_read(file, buffer, fileLength);
AAsset_close(file); //do something with the buffer
free(buffer);
filename = AAssetDir_getNextFileName(assetDir);
}
AAssetDir_close(assetDir); //remember to close it
使用AAsset_getBuffer读整个文件内容
在上面的case中,我们拿到AAsset之后都是malloc内存,然后把文件信息读出来的形式,其实这种方式适合不一次性读取整个文件内容的情况,按照官网的说法就是:
Attempt to read 'count' bytes of data from the current offset.
也就是AAsset_read
应该配合AAsset_seek
使用更美味。
对于一次性读取整个文件的内容,更好的方式是使用AAsset_getBuffer
AAsset *assetFile = AAssetManager_open(nativeasset, "sz.jpg", AASSET_MODE_BUFFER);size_t fileLength = AAsset_getLength(assetFile);const char *dataBuffer2 =(const char *) AAsset_getBuffer(assetFile);std::vector<char> vec2(dataBuffer2, dataBuffer2 + fileLength);
cv::Mat mat2 = cv::imdecode(vec2, CV_LOAD_IMAGE_COLOR);
LOGD("asset file lenght:%d mat: %d x %d %d", fileLength, mat2.cols, mat2.rows, mat2.channels());
AAsset_close(assetFile);
以FileDescriptor的方式来读取
我们可以使用AAsset_openFileDescriptor
来获取FileDescriptor,然后再进行其他操作。需要注意的是,AAsset_openFileDescriptor
返回当前fd的起始seek位置start以及文件长度length。在读取内容之前记得要先seek到start,否则会发现文件内容不对。见代码中的lseek
.
AAsset *assetFile = AAssetManager_open(nativeasset, "sz.jpg", AASSET_MODE_BUFFER);size_t fileLength = AAsset_getLength(assetFile);
LOGD("before fd fileLength:%d",fileLength);off_t start = 0, length = 0;int fd = AAsset_openFileDescriptor(assetFile, &start, &length);
LOGD("fd:%d start:%d length:%d", fd, start, length);
lseek(fd, start, SEEK_CUR); //NOTICE char *dataBuffer = (char*)malloc(fileLength);memset(dataBuffer, 0, fileLength);
read(fd, dataBuffer, fileLength);
close(fd); //close fdLOGD("read_ %d %d %d", dataBuffer[0], dataBuffer[1], dataBuffer[2]);std::vector<char> vec2(dataBuffer, dataBuffer + fileLength);
cv::Mat mat2 = cv::imdecode(vec2, CV_LOAD_IMAGE_COLOR);
LOGD("use fd mat:%d x %d %d", mat2.cols, mat2.rows, mat2.channels());
AAsset_close(assetFile);
获得fd之后,也可以通过他来获得一个FILE:FILE * file = fdopen(fd, "rb");
但是一定要记得fclose(file)
。总的来说不如read方便。
open mode
AAssetManager_open
需要传入一个mode参数,各参数的含义如下,按需使用。
AASSET_MODE_UNKNOWN: Not known how the data is to be accessed
AASSET_MODE_RANDOM: Read chunks, and seek forward and backward
AASSET_MODE_STREAMING: Read sequentially, with an occasional
forward seek
AASSET_MODE_BUFFER: Attempt to load contents into memory, for fast
small reads
细节提示
关于压缩文件
Android APK中有些文件是会进行压缩的,而有些文件则因为本身就是已经压缩过的,不再进行压缩,具体有:
/* these formats are already compressed, or don't compress well */static const char* kNoCompressExt[] = { ".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg", ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".amr", ".awb", ".wma", ".wmv"};
那么对于在APK中会被压缩的文件,比如txt文件,就不能使用AAsset_openFileDescriptor
来读了,否则,会返回-1
这样的无效fd。对于会被压缩的文件,那么就只能使用AAsset_read
或者AAsset_getBuffer
来访问了。
作者:Android高级架构
链接:https://www.jianshu.com/p/0f0472717c17