2

I have the following problem:

I got a file in a binary format, which is stored in the assets directory of my app. And I want to read this file and write it's contents to another place. The logic for reading and writing works fine for "normal" text files, but for the binary file I get weird and unintended behaviour. If i read a text file, my filecontent and buffer stores the text just fine. For a binary file the buffer is mostly empty and missing a lot of the data. And I am also not able to write the contents from the buffer to the filecontent array. This is the code for reading the files:

AAsset* file = AAssetManager_open(Application::AssetManager,
                filePath.c_str(), AASSET_MODE_BUFFER);
        long fileLength = AAsset_getLength(file);
        unsigned char* fileContent = new unsigned char[fileLength];
        int currentByte = 0;
        //256 kb chunk size
        const int BUFFER_SIZE = 1024*256;
        unsigned char buffer[BUFFER_SIZE];
        while(true){
            int bytesRead = AAsset_read(file, buffer, BUFFER_SIZE);
            if(bytesRead <= 0){
                break;
            }
            for(int i=0; i < bytesRead; i++){
                fileContent[currentByte] = buffer[i];
                currentByte++;
            }
        }

Is there anything obvious I am missing? Or do I need to use different datatypes for the binary data? Any tips are appreciated :)

Wuceng
  • 53
  • 3
  • Don't use assets for your read/write functionality because it's intended mostly for static resources. Instead, use the file storage locations. https://stackoverflow.com/questions/21816049/write-and-read-binary-files-in-android/21816168 this may be helpful for you. – Hack06 Jun 03 '20 at 13:30
  • Well that doesn't really answer my question. I don't want to store all my assets (models, textures,scenes,...) outside of the assets directory, as I want them to be delivered with the app and be able to edit a few of them and then write them to another location. – Wuceng Jun 03 '20 at 13:43
  • For storing files during your mobile application execution, you have several options: application-local storage, public storage, SQLite database. https://developer.android.com/training/data-storage - note that assets are not mentioned at all. – Hack06 Jun 03 '20 at 13:49
  • _"And I am also not able to write the contents from the buffer to the filecontent array."_ What does that mean exactly? – Michael Jun 03 '20 at 13:50

2 Answers2

1

Allocating 256kb on the stack is bound to blow your thread's stack limit. Why not write into fileContent directly:

while(true){
    int bytesRead = AAsset_read(file, fileContent + currentByte, BUFFER_SIZE);
    if(bytesRead <= 0){
        break;
    }
    currentByte += bytesRead;
}
Botje
  • 26,269
  • 3
  • 31
  • 41
0

You don't need to read in chunks if you intend to keep all this BLOB in memory for a while:

int bytesRead = AAsset_read(file, fileContent, fileLength);
if (bytesRead <= fileLength) {
    LOGW("expected %d bytes, read only %d bytes", fileLength, bytesRead);
}

Even better, let Android take care of fileContent allocation:

AAsset* file = AAssetManager_open(Application::AssetManager, filePath.c_str(), AASSET_MODE_BUFFER);
long fileLength = AAsset_getLength(file);
unsigned char* fileContent = static_cast<unsigned char*>(AAsset_getBuffer(file));

Chunks may be useful if the media asset is really long, and you immediately write it (probably with some changes) to a file.

PS: it's important to free the memory allocated with new or AAsset_getBuffer() as soon as you don't need it anymore. The asset, too, must be closed: AAsset_close(file).

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • This does not work. The read is limited to 1MB files as far as I know. My file is 39 MB. – Wuceng Jun 03 '20 at 16:55
  • As for limits and limitations of this approach, please read https://stackoverflow.com/a/2870000/192373. You should store media files uncompressed in your assets. – Alex Cohn Jun 03 '20 at 17:48