使用新的 Android 范围存储将 exif 信息从一个 URI 复制到另一个?
Copy exif info from one Uri to the other with the new Android Scoped Storage?
我有两个 Uri
来自不同的文件,其模式“内容”由 Android SAF API 获得,我需要将 exif 信息从一个文件复制到另一个文件。目标文件是由我的应用程序创建的,因此我已授予对它的写入权限。
通过 ContentResolver
我可以获得一个 InputStream
,我可以用它来实例化一个 ExifInterface
,从中我可以从源 Uri
中提取 exif:
InputStream ins = context.getContentResolver().openInputStream(imageInputUri);
ExifInterface originalExif = new ExifInterface(ins);
到目前为止一切顺利...
问题是将 exif 信息写入目标 Uri
。我不能像对源代码那样做,因为用 InputStream
创建的 ExifInferface
是只读的,不能用于将 exif 信息保存为 stated in the docs。
我怎样才能解决这个问题并最终能够将这些 exif 信息从一个文件复制到另一个文件?
由于没有人给出答案,但感谢@blackapps 的评论,我能够自己找到解决方案。如果其他人找到这个 post 搜索同一问题的答案,我会 post 在这里。
事实证明,ExifInterface
有一个构造函数接收 FileDescriptor
作为参数,并且可以通过使用从 Uri
打开 FileDescriptor
ContentResolver
。那么解决方案很简单,为了成功打开 FileDescriptor
唯一需要额外注意的是使用“rw”模式,因为 ExifInterface
需要读取和写入信息而不仅仅是写入.
示例代码如下:
InputStream ins = null;
ParcelFileDescriptor outFd = null;
try {
ins = context.getContentResolver().openInputStream(imageInputUri);
ExifInterface originalExif = new ExifInterface(ins);
outFd = context.getContentResolver().openFileDescriptor(imageOutputUri, "rw");
ExifInterface newExif = new ExifInterface(outFd.getFileDescriptor());
copyExifAttributes(originalExif, newExif, width, height);
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
} finally {
if (ins != null) {
try {
ins.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
}
}
if (outFd != null) {
try {
outFd.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
}
}
}
请注意,此代码不适用于 Android 早于 Lollipop (api 21) 的版本。这是一个 ExifInterface
限制,因为它需要一个可搜索的 FileDescriptor 才能工作,并且 ExifiInterface
使用 native call for doing this. Looking at the Android docs 可以看到此本机代码仅在 Lollipop 之后可用。
我有两个 Uri
来自不同的文件,其模式“内容”由 Android SAF API 获得,我需要将 exif 信息从一个文件复制到另一个文件。目标文件是由我的应用程序创建的,因此我已授予对它的写入权限。
通过 ContentResolver
我可以获得一个 InputStream
,我可以用它来实例化一个 ExifInterface
,从中我可以从源 Uri
中提取 exif:
InputStream ins = context.getContentResolver().openInputStream(imageInputUri);
ExifInterface originalExif = new ExifInterface(ins);
到目前为止一切顺利...
问题是将 exif 信息写入目标 Uri
。我不能像对源代码那样做,因为用 InputStream
创建的 ExifInferface
是只读的,不能用于将 exif 信息保存为 stated in the docs。
我怎样才能解决这个问题并最终能够将这些 exif 信息从一个文件复制到另一个文件?
由于没有人给出答案,但感谢@blackapps 的评论,我能够自己找到解决方案。如果其他人找到这个 post 搜索同一问题的答案,我会 post 在这里。
事实证明,ExifInterface
有一个构造函数接收 FileDescriptor
作为参数,并且可以通过使用从 Uri
打开 FileDescriptor
ContentResolver
。那么解决方案很简单,为了成功打开 FileDescriptor
唯一需要额外注意的是使用“rw”模式,因为 ExifInterface
需要读取和写入信息而不仅仅是写入.
示例代码如下:
InputStream ins = null;
ParcelFileDescriptor outFd = null;
try {
ins = context.getContentResolver().openInputStream(imageInputUri);
ExifInterface originalExif = new ExifInterface(ins);
outFd = context.getContentResolver().openFileDescriptor(imageOutputUri, "rw");
ExifInterface newExif = new ExifInterface(outFd.getFileDescriptor());
copyExifAttributes(originalExif, newExif, width, height);
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
} finally {
if (ins != null) {
try {
ins.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
}
}
if (outFd != null) {
try {
outFd.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage(), e);
}
}
}
请注意,此代码不适用于 Android 早于 Lollipop (api 21) 的版本。这是一个 ExifInterface
限制,因为它需要一个可搜索的 FileDescriptor 才能工作,并且 ExifiInterface
使用 native call for doing this. Looking at the Android docs 可以看到此本机代码仅在 Lollipop 之后可用。