web-dev-qa-db-fra.com

Comment obtenir un fichier dans les actifs de Android NDK

J'essaie d'accéder à un fichier image dans le dossier des ressources à partir du côté natif. Maintenant, je peux rechercher avec succès dans le dossier assets et ses sous-répertoires en localisant le fichier que je cherche:

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);

J'utilise aussi OSG. J'ai défini l'image en tant que texture dans mon shader avec le code suivant:

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

Mais ce nom de fichier doit également inclure le chemin absolu puisqu'il ne se trouve pas dans le même répertoire. Cependant, j'ai découvert que je ne pouvais pas obtenir le chemin absolu du répertoire des actifs, car il était compressé avec l'APK.

Étant donné que je ne peux pas accéder au chemin absolu, quel autre moyen pourrais-je utiliser pour obtenir l'image? À noter également que je souhaite conserver les fichiers dans le dossier des ressources en tant que fichiers attachés à la carte SD.

24
Robert

Vous pouvez lire l’image de la ressource avec AAssetManager_open & AAsset_read, mais comme la ressource se trouve dans apk, vous ne pouvez pas obtenir un nom de chemin de fichier pour cette image. Elle est également compressée. Vous pouvez enregistrer les données dans un fichier et les lire ultérieurement, ou traiter directement le bloc que vous avez obtenu à partir de votre fichier d'actif, si OSG le permet.

De ici :

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);
30
auselen

Une autre chose à noter est qu'Android impose une restriction sur la taille des ressources pouvant être lue à la fois, jusqu'à 1 Mo. Si votre fichier est plus volumineux, vous devez le scinder en morceaux. Voici ma solution de travail qui charge le fichier en morceaux au vecteur de caractères:

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);
    }

}
0
wlochaty