从应用程序Java端,使用file.mkdir创建目录,并使用Java API从USB大容量存储设备复制文件夹(jpg_3)中存在的JPG文件。
然后使用File.delete()方法从内部存储器中删除相同的文件和目录。
当试图将这些相同的文件添加到内部存储器时,文件没有被复制,而是得到以下异常:
02-20 16:11:56.727 17471 17964 E XXXXXX:java.io.FileNotFoundException:/storage/emulated/0/XXX/jpg_3/galaxy-wallpaper-4.jpg:open failed:ENOENT(没有这样的文件或目录)
后来我们发现下面提到的进程仍在访问那些已删除的文件。
shell @ ABC:/ storage / emulated / legacy / XXX #lsof | grep jpg_3
sdcard 1819 media_rw 5 ??? ??? ??? ??? /data/media/0/XXX/jpg_3/galaxy-wallpaper-4.jpg(已删除)
android.p 3205 u0_a4 67 ??? ??? ??? ??? /storage/emulated/0/XXX/jpg_3/galaxy-wallpaper-4.jpg(已删除)
shell @ ABC:/ storage / emulated / legacy / XXX#ps 3205
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a4 3168 1830 1022984 58080 ffffffff 76e7f868 S android.process.media
如果我们尝试使用mkdir创建具有相同名称的目录(在ADB Shell中),我们得到以下错误:
shell @ ABC:/ storage / emulated / legacy / XXX#mkdir jpg_3 mkdir jpg_3失败,设备或资源忙
我们怀疑这些.jpg文件的软链接即使在删除后仍然存在,这会导致上述错误。
我们尝试了File.delete()以及下面提到的代码参考:android : deleting an image
public static void deleteFileFromMediaStore(final ContentResolver contentResolver, final File file) {
String canonicalPath;
try {
canonicalPath = file.getCanonicalPath();
} catch (IOException e) {
canonicalPath = file.getAbsolutePath();
}
final Uri uri = MediaStore.Files.getContentUri("external");
final int result = contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
if (result == 0) {
final String absolutePath = file.getAbsolutePath();
if (!absolutePath.equals(canonicalPath)) {
contentResolver.delete(uri,
MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
}
}
}
如何解决.jpg文件的softlink问题?
N.B:我们还尝试重新扫描设备
MediaScannerConnection.scanFile(mService.getApplicationContext(), new String[]{
oDeleteFile.getAbsolutePath().toString()
}, null, null);
但它没有帮助。
提前致谢
在Android Nougat版本中,有一个文件ExifInterface.java(/ frameworks / base / media / java / android / media /),它有一个函数'getJpegAttributes',它从JPEG输入流中加载EXIF属性。下面是该文件的链接 - http://androidxref.com/7.0.0_r1/xref/frameworks/base/media/java/android/media/ExifInterface.java
在此函数中,DataInputStream已由以下代码创建 -
DataInputStream dataInputStream = new DataInputStream(inputStream);
但是,在函数结束时,尚未关闭相同的文件流。因此,即使MediaScannerService.java完成了对复制文件的扫描,Android Media Provider进程也无需访问该文件。因此,当我们在函数结束时通过以下代码关闭文件流时 -
if (null != dataInputStream) {
Log.d(TAG, "dataInputStream.close()" );
dataInputStream.close();
}
问题得到解决。