Nexus 4无法通过MTP显示文件

80

我想要将一个简单的XML文件写入SD卡,但是我注意到我的Nexus 4确实写入了该文件,但是在使用Windows 7的MTP协议查看时,无法查看该文件。

代码:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    CustomerQueryRqType customerQueryRequest = new CustomerQueryRqType();
    Serializer serializer = new Persister();
    File myFile = new File(Environment.getExternalStorageDirectory() + "/customerQueryRequest.xml");

    try {
        boolean created = myFile.createNewFile();
        serializer.write(customerQueryRequest, myFile);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

我可以用Astro文件管理器在手机上看到该文件:

屏幕截图

但是Windows无法看到它...

屏幕截图

在该目录下使用adb shell命令显示:

ls -l
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Alarms
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Android
drwxrwxr-x root     sdcard_rw          2012-11-21 19:30 DCIM
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Download
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Movies
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Music
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Notifications
drwxrwxr-x root     sdcard_rw          2012-11-19 12:06 Pictures
drwxrwxr-x root     sdcard_rw          1970-01-16 20:51 Podcasts
drwxrwxr-x root     sdcard_rw          2012-11-19 13:22 Ringtones
drwxrwxr-x root     sdcard_rw          2012-11-19 14:33 bluetooth
-rw-rw-r-- root     sdcard_rw       79 2012-12-05 22:26 customerQueryRequest.xml
drwxrwxr-x root     sdcard_rw          2012-11-20 02:50 data
-rw-rw-r-- root     sdcard_rw    11394 2012-11-19 13:54 eightpen_custom_gestures
drwxrwxr-x root     sdcard_rw          2012-11-19 13:17 media

我的 Nexus 4 怎么了?为什么它把我的东西从 Windows 中隐藏起来了?


1
我以为我做错了什么。现在我知道我并不孤单。 - neverMind9
12个回答

72

似乎存在一个已知问题,会影响通过MTP访问Android USB文件。 MTP缓存会过期,直到手机重新启动。

解决方法是:

  • 清除“媒体存储”应用程序的数据
  • 使用SDrescanSD Scanner(也适用于Android 4.4/5,在F-Droid上可用)应用程序强制进行更新

或者干脆不使用USB。这个问题不会影响其他访问文件的方法。例如,尝试使用AirDroid传输文件。


注意:此方法不适用于Android 5.0.2:在清除“媒体存储”并使用SD扫描后,文件夹在Windows 7中显示为无法打开的4K文件。此时唯一的解决方案是再次清除媒体存储并重新启动设备。

2
安装SDrescan,运行它:问题解决了!非常感谢。 - PiTheNumber
这种情况以前没有发生过,但今天发生了。顺便说一下,我重新启动应该就可以解决,不知道为什么它现在还不工作。 - Muhammad Babar
奇怪的是,手机重启了3次后它确实出现了。 - Muhammad Babar
这个方案在Android 5.0.2上不可行。在清除“媒体存储”并使用SD重扫描器后,文件夹在Windows7中以无法打开的4K文件形式出现。此时唯一的解决方案是再次清除媒体存储并重新启动设备。 - Antonio
这在Nexus 7 Android 4.4.2上也没有起作用。我的Mac报告说我的自定义目录是一个4k文件。 - Joe Lapp
但是当我把文件放在标准目录中时,它确实可以工作。 - Joe Lapp

44

11
好的,这应该是这个问题的解决方案。 - Sorcerer
这个解决方案在我的 Nexus 7 上无法工作,Android 版本为 4.4.2,连接到 Mac。我正在外部存储中创建一个新文件夹,并将文件存储在其中。如果我只对文件夹中的文件运行此操作,则 Mac 不显示任何内容。如果我还在我的新目录上运行它,则 Mac 显示我的目录是一个 4k 文件(而不是目录)。我还尝试调用 context.sendBroadcast(),但没有效果。 - Joe Lapp
我刚刚尝试了一下进行媒体扫描并广播在标准下载目录中创建的文件,但是当连接到 Mac 时它们从未出现。 - Joe Lapp
啊,这个不能在onDestroy()中完成。如果我在其他地方做它就可以了。我可以在创建文件的时候做它,但是桌面文件浏览器显示大小为零字节。即便如此,当我复制文件时,它会复制整个文件。 - Joe Lapp
适用于8.1。删除的文件只有在重新启动后才会消失。使用此功能,至少已写入的文件会立即出现在已挂载系统的文件浏览器中。 - Midson

5

在花费了数小时的时间后,我像这样解决了问题:

private void rescanFolder(String dest) {
    // Scan files only (not folders);
    File[] files = new File(dest).listFiles(new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.isFile();
        }
    });

    String[] paths = new String[files.length];
    for (int co=0; co< files.length; co++)
        paths[co] = files[co].getAbsolutePath();

    MediaScannerConnection.scanFile(activity, paths, null, null);

    // and now recursively scan subfolders
    files = new File(dest).listFiles(new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    });

    for (int co=0; co<files.length; co++)
        rescanFolder(files[co].getAbsolutePath());
} 

问题是你必须仅扫描文件(而不是文件夹),然后递归地重复每个子文件夹。

编辑 此外,如果您不希望照片添加到照片库中(但只想在mtp协议上显示您的内容),请在重新扫描之前将一个空的.nomedia文件放置在您的文件夹中,如下所示:

new File(myFolder + File.separator + ".nomedia").createNewFile();
rescanFolder(myFolder);

非常有用的答案,我能够递归使用它,现在我可以通过MTP看到所有新创建的文件。不过,如何处理服务的解绑?我得到了一个ServiceConnectionLeaked错误:“Activity has leaked ServiceConnection android.media.MediaScannerConnection@42164d98 that was originally bound here”。有什么想法可以解决它吗?因为静态地使用MediaScannerConnection.scanFolder()没有机会断开绑定的服务... - Andre

4
我发现解决被接受的答案中提到的错误的最佳方法是使用SSH将数据从Android操作系统复制到另一台机器/服务器(Linux,MacOS,Windows)。
  • 确保设备(Android)和要复制数据的机器(例如连接到相同的wifi网络)可以通过IP或主机名到达。

可选但建议的

  • 使用USB共享网络连接Android设备。这样可以保证快速连接,因为采用有线连接,并且可以保证两个IP地址都在同一网络中,因此彼此可见。

在Android设备中

  • 安装SSH服务器。 SSHelper效果很好。
  • 运行SSHelper并转到配置选项卡以获取IP地址、端口和密码。在下面的示例中,它们分别是192.168.1.5、2222和'admin'。
  • 默认密码是admin,但如果您决定更改密码,请在更改后点击“使用新值重新启动服务器”按钮。

在机器上

  • 安装rsync。如果使用Ubuntu,则已默认安装。
  • 打开shell并键入以下命令。将IP地址和端口更改为您的值。

rsync -avzhP --inplace --info=progress2 -e 'ssh -p 2222' 192.168.1.5:/storage/emulated/0/DCIM/Camera/ /home/username/path/to/pics/

  • 您将收到以下提示,请输入密码。

SSHelper Version 8.5 Copyright 2014, P. Lutus Default password is "admin" (recommend: change it) username@192.168.1.5's password: admin receiving incremental file list

其他建议对我无效:

  • 使用USB存储模式而不是MTP不受设备支持(与许多其他新设备一样)。
  • 我的操作系统(Android 6.0.1)中没有清除“Media Storage”应用程序数据的选项。
  • 通过其他网络共享文件的方法存在缺点。FTP无法确保文件的完整性。如果连接中断,它会覆盖或跳过所有文件,因此其中一个文件可能是不完整的。其他协议可能难以安装,而其他应用程序可能使用专有协议。

3
在Xperia Z上,下面的代码完全正常:
  String screenShotFile = "....";
  activity.sendBroadcast(new Intent(
        Intent.ACTION_MEDIA_MOUNTED, Uri
                .fromFile(screenShotFile)));

for 4.4+ use:

activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                                Uri.fromFile(screenShotFile)));

很遗憾,我不记得是否已经充分测试过了。

http://commonsware.com/blog/2013/11/06/android-4p4-permission-regressions.html


2

注意 /storage/emulated。Android 4.2有一些奇怪的模拟每个应用程序/用户访问的问题,例如为每个用户单独设置一个/sdcard/。请尝试将文件移动到/sdcard/而不是显示的模拟sdcard。


11
所有的链接都指向 /storage/emulated/legacy,而该目录本身是链接到 /mnt/shell/emulated/0 的,这个目录包含了该文件。 - moonlightcheese

2

简单的代码提出了一个问题:如何在Android上刷新MediaStore?如果在我将文件放在外部存储器后调用,它会对MediaStore进行必要的更新。在我的Nexus 4上,Windows 7文件资源管理器中的内容会立即刷新。


刚刚经历了一件事,它可能最终停止更新。 - stephan

1

我曾遇到与我的OneplusOne类似的问题:

在软件更新(至6.0.1)后,我无法在连接到电脑(PTP和MTP)时查看相机照片。两个应用程序SDRescan和SDscanner都没有效果。

我的解决方案是使用终端或手机上的任何文件浏览器应用程序将所有图片从DCIM复制到另一个文件夹中。连接到电脑后,我能够看到复制的文件...我将它们移动到了电脑上并清除了相机文件夹。这并不是永久性的解决方案,但至少对我来说解决了问题,直到我进行下一次备份。=D


1

我需要为我的应用程序创建一个目录并复制一些示例文件。经过许多实验和研究,以下步骤对我完美地起作用:

1)使用File.mkdir()创建目录。

2)将文件复制到目录中,并在每个文件上运行MediaScanner。

MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);

在目录上运行MediaScanner。
MediaScannerConnection.scanFile(context, new String[]{directory.getAbsolutePath()}, null, null);

结果:通过MTP,在PC上文件和目录立即显示。

同时扫描目录和特定文件对我很有用。您还可以通过准备一个包含两个元素的String[]数组来组合这两个调用,其中列出了文件和父级。另请参阅https://dev59.com/Qmox5IYBdhLWcg3wIQ5o#25086535。 - parvus

0
以上的答案可以用于创建文件。如果您稍后删除了该文件并希望该更改也得到反映,您可以执行以下两个解决方案中的任何一个;首先让我们介绍两个看似有效但在某些设备上会导致问题的解决方案。第一个是扫描已删除的文件:
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));

这适用于许多设备上的已删除文件,但在某些设备上,它实际上会创建一个新的0字节文件,这可能不是您想要的。在这种情况下,如果您正在运行<4.4 KitKat,则可以执行以下操作:

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(folder)));

其中文件夹等于file.getParentFile()。不幸的是,在KitKat 4.4及以上版本中,这将导致SecurityException被抛出,因此对于这些设备,您可以尝试直接从Media Store删除:

final Uri externalFilesUri = Files.getContentUri("external");
context.getContentResolver().delete(externalFilesUri, Files.FileColumns.DATA + "=?", new String[] {file.getAbsolutePath()});

我已经测试了这个方法,作为 ACTION_MEDIA_MOUNTED 在 KitKat 上无法工作的解决方法,在 Nexus 5 上的测试中它是有效的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接