【问题标题】:How to get the internal and external sdcard path in android如何在android中获取内部和外部sdcard路径
【发布时间】:2012-11-01 21:33:50
【问题描述】:

大多数新的 android 设备都有一个内部 sdcard 和一个外部 sdcard。我想制作一个文件浏览器应用程序,但我不知道如何获取在我的应用程序中使用的路径,因为

File file = Environment.getExternalStorageDirectory();

只在大多数设备中返回 /mnt/sdcard 但是另一个外部 SD 卡还有另一条路径,例如 /storage1 or /storage2 .任何帮助表示赞赏。

【问题讨论】:

    标签: android file android-sdcard android-file


    【解决方案1】:

    如何在android中获取内部和外部sdcard路径

    在内部存储中存储的方法:

    File getDir (String name, int mode)
    
    File getFilesDir () 
    

    以上方法存在于Context 类中

    手机内存存储方法:

    File getExternalStorageDirectory ()
    
    File getExternalFilesDir (String type)
    
    File getExternalStoragePublicDirectory (String type)
    

    一开始大家都用Environment.getExternalStorageDirectory(),指向手机内存的root。结果,根目录被随机内容填充。

    后来增加了这两个方法:

    Context 类中,他们添加了getExternalFilesDir(),指向手机内存中的特定应用目录。卸载应用时,该目录及其内容将被删除。

    Environment.getExternalStoragePublicDirectory() 用于存储知名文件类型(如照片和电影)的集中位置。此目录及其内容将在应用卸载时不会被删除。

    存储在可移动存储(即 micro SD 卡)中的方法

    在 API 级别 19 之前,没有官方的方式存储在 SD 卡中。但是许多人可以使用非官方的 API 来做到这一点。

    官方在 API 级别 19(Android 版本 4.4 - Kitkat)的Context 类中引入了一种方法。

    File[] getExternalFilesDirs (String type)
    

    它返回所有应用程序特定目录的绝对路径 应用程序可以放置的共享/外部存储设备 它拥有的持久性文件。这些文件在应用程序内部, 并且通常不作为媒体对用户可见。

    这意味着,它将返回到 Micro SD 卡和内部存储器的路径。一般第二个返回路径为micro SD卡的存储路径。

    根据 Google/官方 Android 文档的内部和外部存储术语与我们的想法完全不同

    【讨论】:

      【解决方案2】:

      是的。不同的制造商使用不同的 SD 卡名称,例如三星 Tab 3 它的 extsd,而其他三星设备使用不同的 SD 卡,不同的制造商使用不同的名称。

      我和你有同样的要求。所以我从我的项目中为您创建了一个示例示例转到此链接Android Directory chooser 示例,该示例使用了 android-dirchooser 库。此示例检测 SD 卡并列出所有子文件夹,它还检测设备是否有多个 SD 卡。

      部分代码如下所示完整示例转到链接Android Directory Chooser

      /**
      * Returns the path to internal storage ex:- /storage/emulated/0
       *
      * @return
       */
      private String getInternalDirectoryPath() {
      return Environment.getExternalStorageDirectory().getAbsolutePath();
       }
      
      /**
       * Returns the SDcard storage path for samsung ex:- /storage/extSdCard
       *
       * @return
       */
          private String getSDcardDirectoryPath() {
          return System.getenv("SECONDARY_STORAGE");
      }
      
      
       mSdcardLayout.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View view) {
              String sdCardPath;
              /***
               * Null check because user may click on already selected buton before selecting the folder
               * And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
               */
      
              if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
                  mCurrentInternalPath = mSelectedDir.getAbsolutePath();
              } else {
                  mCurrentInternalPath = getInternalDirectoryPath();
              }
              if (mCurrentSDcardPath != null) {
                  sdCardPath = mCurrentSDcardPath;
              } else {
                  sdCardPath = getSDcardDirectoryPath();
              }
              //When there is only one SDcard
              if (sdCardPath != null) {
                  if (!sdCardPath.contains(":")) {
                      updateButtonColor(STORAGE_EXTERNAL);
                      File dir = new File(sdCardPath);
                      changeDirectory(dir);
                  } else if (sdCardPath.contains(":")) {
                      //Multiple Sdcards show root folder and remove the Internal storage from that.
                      updateButtonColor(STORAGE_EXTERNAL);
                      File dir = new File("/storage");
                      changeDirectory(dir);
                  }
              } else {
                  //In some unknown scenario at least we can list the root folder
                  updateButtonColor(STORAGE_EXTERNAL);
                  File dir = new File("/storage");
                  changeDirectory(dir);
              }
      
      
          }
      });
      

      【讨论】:

        【解决方案3】:

        由于没有直接的方法来获取路径,因此解决方案可能是 扫描 /system/etc/vold.fstab 文件并查找如下行: dev_mount sdcard /mnt/sdcard 1 /devices/platform/s3c-sdhci.0/mmc_host/mmc0

        找到一个后,将其拆分为元素,然后拉出 该挂载点的路径并将其添加到数组列表中

        强调文本有些设备完全缺少 vold 文件,因此我们在此处添加路径 确保列表始终包含第一个 sdcard 的路径, 无论是真实的还是模拟的。

            sVold.add("/mnt/sdcard");
        
            try {
                Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
                while (scanner.hasNext()) {
                    String line = scanner.nextLine();
                    if (line.startsWith("dev_mount")) {
                        String[] lineElements = line.split(" ");
                        String element = lineElements[2];
        
                        if (element.contains(":"))
                            element = element.substring(0, element.indexOf(":"));
        
                        if (element.contains("usb"))
                            continue;
        
                        // don't add the default vold path
                        // it's already in the list.
                        if (!sVold.contains(element))
                            sVold.add(element);
                    }
                }
            } catch (Exception e) {
                // swallow - don't care
                e.printStackTrace();
            }
        }
        

        现在我们有了一个干净的挂载路径列表,测试每一个以使 确保它是有效且可用的路径。如果不是,请将其从 列表。

        private static void testAndCleanList() 
        {
            for (int i = 0; i < sVold.size(); i++) {
                String voldPath = sVold.get(i);
                File path = new File(voldPath);
                if (!path.exists() || !path.isDirectory() || !path.canWrite())
                    sVold.remove(i--);
            }
        }
        

        【讨论】:

          【解决方案4】:

          我不确定这个答案有多普遍,但我在装有 Android 4.4 的摩托罗拉 XT830C 和 Nexus 7 android 6.0.1 上对其进行了测试。在三星 SM-T530NU Android 5.0.2 上。 我使用了System.getenv("SECONDARY_STORAGE")Environment.getExternalStorageDirectory().getAbsolutePath()
          没有第二张 SD 卡的 Nexus,System.getenv 返回 null,Envirnoment.getExterna... 给出 /storage/emulated/0。
          具有外部 SD 卡的摩托罗拉设备为 System.getenv("SECONDARY_STORAGE") 提供 /storage/sdcard1,Envirnoment.getExterna... 提供 /storage/emulated/0。
          samsumg 为外部 SD 返回 /storage/extSdCard。
          就我而言,我正在外部位置创建一个子目录并使用

           appDirectory = (System.getenv("SECONDARY_STORAGE") == null)
                 ? Environment.getExternalStorageDirectory().getAbsolutePath()
                 : System.getenv("SECONDARY_STORAGE");
          

          找到SD卡。在这个目录中创建一个子目录是可行的。
          当然我必须在清单文件中设置访问外部存储器的权限。
          我还有一个 Nook 8" 彩色平板电脑。当我有机会对其进行测试时,如果我对这种方法有任何问题,我会发布。

          【讨论】:

            【解决方案5】:

            但其他外部 sdcard 有另一条路径,例如 /storage1 或 /storage2

            Android SDK 中没有任何东西——至少在 Android 4.1 中——可以让您访问这些路径。无论如何,您的应用程序可能无法读取或写入它们。此类存储位置的行为及其用途取决于设备制造商。

            【讨论】:

            • 好的,但是如何通过代码知道设备是否有内部和外部sdcard
            • @Ma7moudHatem:Android SDK 中没有任何东西——至少在 Android 4.1 中——告诉你“设备是否有内部和外部 sdcard 代码”。
            • @MahmoudHatem 用于查找内部或外部 sdcard 的正确位置,您必须在您的 android SDK 中使用 DDMS。
            • 不,DDMS 会给出适用于 adb 的答案,但通常不适用于应用程序,这些应用程序在不同的路径上看到与 adb 不同的存储空间。
            【解决方案6】:
            File main=new File(String.valueOf(Environment.getExternalStorageDirectory().getAbsolutePath()));
            File[]t=main.getParentFile().listFiles();
            
            for(File dir:t)
            {
                Log.e("Main",dir.getAbsolutePath());
            }
            

            输出:

            E/Main: /storage/sdcard1
            E/Main: /storage/sdcard0
            

            我有一张 SD 卡和内置内存。

            【讨论】:

              【解决方案7】:

              对于所有 Android 版本,

              权限:

              <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
              <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
              <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
              

              使用 Android 10 的 requestLegacyExternalStorage(添加到 AndroidManifest > 应用标签):

              android:requestLegacyExternalStorage="true"
              

              获取内部目录路径:

              @Nullable
              public static String getInternalStorageDirectoryPath(Context context) {
                  String storageDirectoryPath;
              
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                      StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
                      if(storageManager == null) {
                          storageDirectoryPath = null; //you can replace it with the Environment.getExternalStorageDirectory().getAbsolutePath()
                      } else {
                          storageDirectoryPath = storageManager.getPrimaryStorageVolume().getDirectory().getAbsolutePath();
                      }
                  } else {
                      storageDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath();
                  }
              
                  return storageDirectoryPath;
              }
              

              获取外部目录:

              @NonNull
              public static List<String> getExternalStorageDirectoryPaths(Context context) {
                  List<String> externalPaths = new ArrayList<>();
                  String internalStoragePath = getInternalStorageDirectoryPath(context);
              
                  File[] allExternalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
                  for(File filesDir : allExternalFilesDirs) {
                      if(filesDir != null) {
                          int nameSubPos = filesDir.getAbsolutePath().lastIndexOf("/Android/data");
                          if(nameSubPos > 0) {
                              String filesDirName = filesDir.getAbsolutePath().substring(0, nameSubPos);
                              if(!filesDirName.equals(internalStoragePath)) {
                                  externalPaths.add(filesDirName);
                              }
                          }
                      }
                  }
              
                  return externalPaths;
              }
              

              【讨论】:

                【解决方案8】:

                没有获取内部/外部sdcard路径的公共api。

                但是在 android.os.storage 包中有一个叫做 StorageManager 的平台 api。见http://goo.gl/QJj1eu

                有列表存储、挂载/卸载存储、获取挂载状态、获取存储路径等功能。

                但它是隐藏的 api,它应该在下一个 android 版本中被弃用或破坏。

                而且有些方法需要特别许可,而且大部分都没有记录。

                【讨论】:

                  【解决方案9】:

                  试试这个代码会有所帮助

                  Map<String, File> externalLocations = ExternalStorage.getAllStorageLocations();
                  File sdCard = externalLocations.get(ExternalStorage.SD_CARD);
                  File externalSdCard = externalLocations.get(ExternalStorage.EXTERNAL_SD_CARD);
                  

                  【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-06-01
                  • 1970-01-01
                  • 2015-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多