7

Mon application utilise Java classe RandomAccessFile pour lire/écrire des octets à un fichier sur la carte SD au hasard au moyen de la réalisation de l'interface SeekableByteChannel. Maintenant, j'ai besoin de le réécrire pour Android 5.0 avec une nouvelle API Lollipop.Comment obtenir un accès aléatoire à un fichier sur la carte SD au moyen de l'API présentée pour Lollipop?

J'ai trouvé the only way lire:

InputStream inputStream = getContentResolver().openInputStream(uri); 

et écrire:

ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(uri, "w"); 
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); 

de/vers un fichier dans la nouvelle API.

Je voudrais avoir la possibilité de régler le canal dans certains position aléatoire et lire/écrire des octets à cette position. Est-il possible de faire cela dans le nouveau SDK 21? Est-ce que le nouveau SDK implique de cette façon l'obtention de canaux:

FieInputChannel fieInputChannel = fileInputStream.getChannel(); 
FieOutputChannel fieOutputChannel = fileOutputStream.getChannel(); 

ou une autre approche?

Répondre

7

Il semble que le seul moyen d'obtenir un accès en lecture/écriture aléatoire dans un fichier sur la carte SD pour SDK 21 (Lollipop) est la suivante:

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

EDIT 15/03/2017: La version peu optimisée ressemble à

import android.content.Context; 
import android.net.Uri; 
import android.os.ParcelFileDescriptor; 

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 { 
    private ParcelFileDescriptor pfdInput, pfdOutput; 
    private FileInputStream fis; 
    private FileOutputStream fos; 
    private long position; 

    public SecondaryCardChannel(Uri treeUri, Context context) { 
     try { 
      pfdInput = context.getContentResolver().openFileDescriptor(treeUri, "r"); 
      pfdOutput = context.getContentResolver().openFileDescriptor(treeUri, "rw"); 
      fis = new FileInputStream(pfdInput.getFileDescriptor()); 
      fos = new FileOutputStream(pfdOutput.getFileDescriptor()); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 

    public int read(ByteBuffer buffer) { 
     try { 
      FileChannel fch = fis.getChannel(); 
      fch.position(position); 
      int bytesRead = fch.read(buffer); 
      position = fch.position(); 
      return bytesRead; 
     } catch (IOException e) { 
      e.printStackTrace(); 
      return -1; 
     } 
    } 

    public int write(ByteBuffer buffer) { 
     try { 
      FileChannel fch = fos.getChannel(); 
      fch.position(position); 
      int bytesWrite = fch.write(buffer); 
      position = fch.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 fis.getChannel().size(); 
    } 

    public void force(boolean metadata) throws IOException { 
     fos.getChannel().force(metadata); 
     pfdOutput.getFileDescriptor().sync(); 
    } 

    public long truncate(long size) throws Exception { 
     FileChannel fch = fos.getChannel(); 
     try { 
      fch.truncate(size); 
      return fch.size(); 
     } catch (Exception e){ // Attention! Truncate is broken on removable SD card of Android 5.0 
      e.printStackTrace(); 
      return -1; 
     } 
    } 

    public void close() throws IOException { 
     FileChannel fch = fos.getChannel(); 
     fch.close(); 

     fos.close(); 
     fis.close(); 
     pfdInput.close(); 
     pfdOutput.close(); 
    } 
}