5

Is there any way get a RandomAccessFile from a given DocumentFile?

I know it is possible to get an InputStream via getUri

InputStream inputStream = getContentResolver().openInputStream(DocumentFile.getUri());

But I need a RandomAccessFile

Thanks for your help,

Jens

Tunaki
  • 132,869
  • 46
  • 340
  • 423
JensSommer
  • 51
  • 2

4 Answers4

3

It seems the only way to get a random read/write access to a file on SD card for SDK 21 (Lollipop) is as follows:

import android.content.Context;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import com.jetico.bestcrypt.FileManagerApplication;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class SecondaryCardChannel {//By analogy with the java.nio.channels.SeekableByteChannel
    private FileChannel fileChannel;
    private ParcelFileDescriptor pfd;
    private boolean isInputChannel;
    private long position;

    public SecondaryCardChannel(Uri treeUri, Context context) {
        try {
            pfd = context.getContentResolver().openFileDescriptor(treeUri, "rw");
            FileInputStream fis = new FileInputStream(pfd.getFileDescriptor());
            fileChannel = fis.getChannel();
            isInputChannel = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public int read(ByteBuffer buffer) {
        if (!isInputChannel) {
            try {
                fileChannel.close();
                FileInputStream fis = new FileInputStream(pfd.getFileDescriptor());
                fileChannel = fis.getChannel();
                isInputChannel = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            fileChannel.position(position);
            int bytesRead = fileChannel.read(buffer);
            position = fileChannel.position();
            return bytesRead;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }

    public int write(ByteBuffer buffer) {
        if (isInputChannel) {
            try {
                fileChannel.close();
                FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
                fileChannel = fos.getChannel();
                isInputChannel = false;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            fileChannel.position(position);
            int bytesWrite = fileChannel.write(buffer);
            position = fileChannel.position();
            return bytesWrite;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }

    public long position() throws IOException {
        return position;
    }

    public SecondaryCardChannel position(long newPosition) throws IOException {
        position = newPosition;
        return this;
    }

    public long size() throws IOException {
        return fileChannel.size();
    }

    public SecondaryCardChannel truncate(long size) throws IOException {
        fileChannel.truncate(size);
        return this;
    }
}
isabsent
  • 3,683
  • 3
  • 25
  • 46
  • 1
    This does not work if you open a Document File in append mode as it keeps on writing at end of the file regardless of FileChannel position – Rahul Verma Dec 09 '16 at 10:28
2

Since API level 21 (Lollipop), this might be a low level replacement:

ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "rw");
FileDescriptor fd = pfd.getFileDescriptor();
// seek to offset 10 from beginning of file
android.system.Os.lseek(fd, 10, OsConstants.SEEK_SET);

other low-level methods like read(fd, ...)? write(fd, ...) fstat(fd) can be found in android.system.OS, too.

Be sure you have an uri that has read/write access.

Udo Klimaschewski
  • 5,150
  • 1
  • 28
  • 41
-1

Create text file which contains path of all files that you want to open at random

in = new BufferedReader(new FileReader("randomfilepaths.txt"));

Create a function for getting path of one random file this could be done by the readLine().

code:

protected String getRandomPath() {
     String returnval = null;
 try{
   if((returnval = in.readLine()) == null){
    in.close();
    moreFiles = false;
   }
 }catch(Exception e){}
 return returnval;
}

Here returnval will contain the String path to a random file.

  • I was talking about the class RandomAccessFile http://developer.android.com/reference/java/io/RandomAccessFile.html – JensSommer Mar 06 '15 at 12:27
-1

In fact Google forgot to add that kind of function or decided not to do it. Thus it is not possible to get a RandomAccessFile when using the Storage Access Framework.

However, if you need a RandomAccessFile in your code, you might, if possible, create a super class like MyRandomAccessFile with its subclasses based on either RandomAccessFile (and File) or on InputStream and OutputStream you can get from the DocumentFile. I used that method to adapt JaudioTagger to SAF.