我的设备上安装了一个 API 级别为 21 的Google Drive Android 应用程序。我想让我的应用程序从我设备上的 Google Drive 私人文件夹中读取一些文件,进行一些更改并让 Google Drive Android 应用程序同步它。单击某个文件会启动文件下载过程,然后会出现应用程序选择器。正如这里所指出的, Google Drive Android 应用程序不再将dataUri作为file://...发送到其他应用程序。它发送一个content://...代替。不过,我可以得到
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(dataUri, "r");
有了pfd,我可以通过以下方式在缓冲区中的某个位置读出一些字节:
FileInputStream fis = new FileInputStream(pfd.getFileDescriptor());
FileChannel fileChannel = fis.getChannel();
fileChannel.position(position);
int bytesRead = fileChannel.read(buffer);
当我尝试将缓冲区中的一些字节写入Google Drive 私有文件夹中文件的某个位置时,就会出现问题:
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(dataUri, "w"/*"rw", "rwt"*/); //Exception here for "rw"
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
FileChannel fileChannel = fos.getChannel();
fileChannel.position(position); //Exception here for "w" and "rwt"
int bytesWrite = fileChannel.write(buffer);
这给了我IOException - lseek failed: ESPIPE (Illegal seek)。同样的例外是“rwt”模式。访问模式“rw”给出了其他例外:
java.io.FileNotFoundException: Unsupported mode: rw:
清单中存在所有必要的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
从另一面来看,可以从我的应用程序中重写私有 Google Drive Android 应用程序中的整个文件 - 如果我没有在写入时进行任何定位 - 只需将 FileInputStream 复制到 FileOutputStream:
FileInputStream fis = new FileInputStream("/storage/sdcard0/aaa/www/flower.jpg");
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(dataUri, "rwt");
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
new StreamCopyThread(fis, fos).start();
问题是:为什么 Google 让我们有机会重写私有 Google Drive 文件夹中的整个文件,而不给我们机会只更改该文件中的几个字节?
PS 为简洁起见,省略了所有必要的 try-catch 块