Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RandomAccessFile in Android raw resource file

Tags:

android

I tried to create a RandomAccessFile object from a raw resource file in android resource directory without success.

I'm only able to get a inputstream object from raw resource file.

getResources().openRawResource(R.raw.file);

Is it possible to create a RandomAccessFile object from raw asset file or Do I need to stick with inputstream?

like image 788
thavan Avatar asked Feb 17 '12 21:02

thavan


2 Answers

Why not get a new AssetFileDescriptor each time you need a seek? It seems not to be a cpu cycles intensive task (or is it?)

//seek to your first start position
InputStream ins = getAssets().openFd("your_file_name").createInputStream();
isChunk.skip(start);
//read some bytes
ins.read(toThisBuffer, 0, length);

//later on
//seek to a different position, need to openFd again! 
//because createInputStream can be called on asset file descriptor only once.
//This resets the new stream to file offset 0, 
//so need to seek (skip()) to a new position relative to file beginning.

ins = getAssets().openFd("your_file_name").createInputStream();
ins.skip(start2);

//read some bytes
ins.read(toThatBuffer, 0, length);

I've used this method in my app that needs random access to a 20Mb resource file hundreds of times per second.

like image 38
LuWiz Avatar answered Oct 18 '22 19:10

LuWiz


It's simply not possible to seek forward and back in an input stream without buffering everything in between into memory. That can be extremely costly, and isn't a scalable solution for reading a (binary) file of some arbitrary size.

You're right: ideally, one would use a RandomAccessFile, but reading from the resources provides an input stream instead. The suggestion mentioned in the comments above is to use the input stream to write the file to the SD card, and randomly access the file from there. You could consider writing the file to a temporary directory, reading it, and deleting it after use:

String file = "your_binary_file.bin";
AssetFileDescriptor afd = null;
FileInputStream fis = null;
File tmpFile = null;
RandomAccessFile raf = null;
try {
    afd = context.getAssets().openFd(file);
    long len = afd.getLength();
    fis = afd.createInputStream();
    // We'll create a file in the application's cache directory
    File dir = context.getCacheDir();
    dir.mkdirs();
    tmpFile = new File(dir, file);
    if (tmpFile.exists()) {
        // Delete the temporary file if it already exists
        tmpFile.delete();
    }
    FileOutputStream fos = null;
    try {
        // Write the asset file to the temporary location
        fos = new FileOutputStream(tmpFile);
        byte[] buffer = new byte[1024];
        int bufferLen;
        while ((bufferLen = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, bufferLen);
        }
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {}
        }
    }
    // Read the newly created file
    raf = new RandomAccessFile(tmpFile, "r");
    // Read your file here
} catch (IOException e) {
    Log.e(TAG, "Failed reading asset", e);
} finally {
    if (raf != null) {
        try {
            raf.close();
        } catch (IOException e) {}
    }
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {}
    }
    if (afd != null) {
        try {
            afd.close();
        } catch (IOException e) {}
    }
    // Clean up
    if (tmpFile != null) {
        tmpFile.delete();
    }
}
like image 166
Paul Lammertsma Avatar answered Oct 18 '22 20:10

Paul Lammertsma