如何通过为 Lollipop 提供的 API 随机访问 SD 卡上的文件?
How to get random access to a file on SD-Card by means of API presented for Lollipop?
我的应用程序使用 Java class RandomAccessFile to read/write bytes to a file on SD card randomly by means of realization of SeekableByteChannel 接口。现在我需要用新的 Lollipop API 为 Android 5.0 重写它。
我找到the only way阅读:
InputStream inputStream = getContentResolver().openInputStream(uri);
然后写:
ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
from/to 新建一个文件 API.
我希望能够在某些 随机 位置和 read/write 字节的位置设置频道。可以在新的 SDK 21 中做到这一点吗?新的SDK是否暗示以这种方式获取渠道:
FieInputChannel fieInputChannel = fileInputStream.getChannel();
FieOutputChannel fieOutputChannel = fileOutputStream.getChannel();
或其他一些方法?
对于 SDK 21 (Lollipop),随机 read/write 访问 SD 卡上的文件的唯一方法似乎如下:
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;
}
}
编辑 2017 年 3 月 15 日:
稍微优化一下的版本看起来像
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();
}
}
我的应用程序使用 Java class RandomAccessFile to read/write bytes to a file on SD card randomly by means of realization of SeekableByteChannel 接口。现在我需要用新的 Lollipop API 为 Android 5.0 重写它。
我找到the only way阅读:
InputStream inputStream = getContentResolver().openInputStream(uri);
然后写:
ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
from/to 新建一个文件 API.
我希望能够在某些 随机 位置和 read/write 字节的位置设置频道。可以在新的 SDK 21 中做到这一点吗?新的SDK是否暗示以这种方式获取渠道:
FieInputChannel fieInputChannel = fileInputStream.getChannel();
FieOutputChannel fieOutputChannel = fileOutputStream.getChannel();
或其他一些方法?
对于 SDK 21 (Lollipop),随机 read/write 访问 SD 卡上的文件的唯一方法似乎如下:
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;
}
}
编辑 2017 年 3 月 15 日: 稍微优化一下的版本看起来像
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();
}
}