Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Get File In Assets From Android NDK

I'm trying to access an image file in the assets folder from the native side. Now I can successfully search through the assets folder and its subdirectories locating the particular file that I am looking for:

AAssetDir* assetDir = AAssetManager_openDir(asset_manager, "images"); const char* filename; while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {    __android_log_print(ANDROID_LOG_DEBUG, "Debug", filename); }  AAssetDir_close(assetDir); 

I am also using OSG. I set the image as a texture to my shader with the following code:

texture->setImage(osgDB::readImageFile(fileNameWithPath)); 

But that file name must include the absolute path as well since it is not located in the same directory. However I found out that I cannot get the absolute path for the assets directory, being that it is compressed along with the APK.

Being that I can't access the absolute path, what other way could I use to get the image? Also to note, I do want to keep the files in the asset folder as appose to the sd card.

like image 333
Robert Avatar asked Nov 09 '12 23:11

Robert


People also ask

How to read a file from assets in Android?

This example demonstrates how do I read a file from assets in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main.xml. Step 3 – Right click app >> New >> Folder >> Assets folder.

How do I reference an asset in an APK?

Your assets are packaged into your apk, so you can't refer to them directly during runtime like in the sample code you provided. You have 2 options here: Copy out your asset to a local file in your files dir, and then reference the filename of the copied file. Thanks for contributing an answer to Stack Overflow!

How to read an image from an asset?

You can read the image from an asset with AAssetManager_open & AAsset_read, but since asset lies in apk you can't get a file path name for it - it is also compressed there. You can save the data to a file and read from that file later or you can directly process the chunk you got from your asset file if OSG allows.

How to read asset data from a file descriptor?

Open a new file descriptor that can be used to read the asset data. If the start or length cannot be represented by a 32-bit number, it will be truncated. If the file is large, use AAsset_openFileDescriptor64 instead. Returns < 0 if direct fd access is not possible (for example, if the asset is compressed).


2 Answers

You can read the image from an asset with AAssetManager_open & AAsset_read, but since asset lies in apk you can't get a file path name for it - it is also compressed there. You can save the data to a file and read from that file later or you can directly process the chunk you got from your asset file if OSG allows.

From here:

AAssetDir* assetDir = AAssetManager_openDir(mgr, ""); const char* filename = (const char*)NULL; while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {     AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);     char buf[BUFSIZ];     int nb_read = 0;     FILE* out = fopen(filename, "w");     while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)         fwrite(buf, nb_read, 1, out);     fclose(out);     AAsset_close(asset); } AAssetDir_close(assetDir); 
like image 194
auselen Avatar answered Sep 25 '22 07:09

auselen


One more thing worth mentioning is that android puts restriction on asset size that can be read at time, to 1Mb. In case your file is bigger than that, you have to split it into chunks. Here is my working solution which loads file in chunks to vector of chars:

AAssetManager * mgr = app->activity->assetManager;  AAssetDir* assetDir = AAssetManager_openDir(mgr, "");  const char* filename; std::vector<char> buffer;  while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL)  {     //search for desired file     if(!strcmp(filename, /* searched file name */))      {         AAsset *asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);          //holds size of searched file         off64_t length = AAsset_getLength64(asset);         //keeps track of remaining bytes to read         off64_t remaining = AAsset_getRemainingLength64(asset);         size_t Mb = 1000 *1024; // 1Mb is maximum chunk size for compressed assets         size_t currChunk;         buffer.reserve(length);          //while we have still some data to read         while (remaining != 0)          {             //set proper size for our next chunk             if(remaining >= Mb)             {                 currChunk = Mb;             }             else             {                 currChunk = remaining;             }             char chunk[currChunk];              //read data chunk             if(AAsset_read(asset, chunk, currChunk) > 0) // returns less than 0 on error             {                 //and append it to our vector                 buffer.insert(buffer.end(),chunk, chunk + currChunk);                 remaining = AAsset_getRemainingLength64(asset);             }         }         AAsset_close(asset);     }  } 
like image 45
wlochaty Avatar answered Sep 23 '22 07:09

wlochaty