如何获取Android 4.0+的外部SD卡路径?


93

三星Galaxy S3具有一个外部SD卡插槽,该插槽安装在上/mnt/extSdCard

我怎么能通过类似的东西走这条路Environment.getExternalStorageDirectory()

这将返回mnt/sdcard,而我找不到外部SD卡的API。(或某些平板电脑上的可移动USB存储设备。)


你为什么要这个?在Android上执行此类操作是非常不可取的。也许,如果您分享自己的动力,我们可以为您指明此类事情的最佳实践方向。
rharter 2014年

2
当您的用户更换手机时,将SD卡插入新手机,在第一部手机上是/ sdcard,在第二部手机上是/ mnt / extSdCard,所有使用文件路径的文件都会崩溃。我需要从其相对路径生成真实路径。
Romulus Urakagi Ts'ai 2014年

我现在这个话题很老,但这可能会有所帮助。您应该使用此方法。System.getenv(); 请参阅Project Environment3以访问连接到设备的所有存储。 github.com/omidfaraji/Environment3
Omid Faraji


这是直到牛轧糖都可以使用的我的解决方案:stackoverflow.com/a/40205116/5002496
Gokul NC

Answers:


58

我在这里找到的解决方案有所不同

public static HashSet<String> getExternalMounts() {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String s = "";
    try {
        final Process process = new ProcessBuilder().command("mount")
                .redirectErrorStream(true).start();
        process.waitFor();
        final InputStream is = process.getInputStream();
        final byte[] buffer = new byte[1024];
        while (is.read(buffer) != -1) {
            s = s + new String(buffer);
        }
        is.close();
    } catch (final Exception e) {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines) {
        if (!line.toLowerCase(Locale.US).contains("asec")) {
            if (line.matches(reg)) {
                String[] parts = line.split(" ");
                for (String part : parts) {
                    if (part.startsWith("/"))
                        if (!part.toLowerCase(Locale.US).contains("vold"))
                            out.add(part);
                }
            }
        }
    }
    return out;
}

原始方法已经过测试并与

  • 华为X3(股票)
  • Galaxy S2(库存)
  • Galaxy S3(库存)

我不确定这些是在哪个Android版本上进行测试的。

我已经用

  • Moto Xoom 4.1.2(现货)
  • 使用OTG电缆的Galaxy Nexus(cyanogenmod 10)
  • HTC Incredible(cyanogenmod 7.2)返回了内部和外部。该设备有点奇怪,因为getExternalStorage()返回了sdcard的路径,因此其内部大部分未使用。

以及一些使用sdcard作为主存储的单个存储设备

  • HTC G1(cyanogenmod 6.1)
  • HTC G1(库存)
  • HTC Vision / G2(库存)

除了难以置信之外,所有这些设备仅返回了可移动存储。我可能应该做一些额外的检查,但这至少比我到目前为止发现的任何解决方案都要好。


3
我认为您的解决方案将给无效的文件夹名称,如果原始名称包含大写字母,例如/ mnt / SdCard
Eugene Popovich

1
我已经在一些摩托罗拉,三星和LG设备上进行了测试,并且效果很好。
pepedeutico

2
@KhawarRaza,此方法自kitkat起已停止工作。使用Dmitriy Lozenko的方法,如果您支持Preics设备,则将其作为后备方法。
Gnathonic 2014年

1
适用于HUAWEI Honor 3c。谢谢。
li2

2
这将在Galaxy Note 3上为我返回4.0版本以上的/ mnt而不是/ storage
ono

54

我找到了一种更可靠的方式来获取系统中所有SD-CARD的路径。这适用于所有Android版本,并返回所有存储(包括仿真的)的路径。

在我所有的设备上都能正常工作。

PS:基于环境类的源代码。

private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

/**
 * Raturns all available SD-Cards in the system (include emulated)
 *
 * Warning: Hack! Based on Android source code of version 4.3 (API 18)
 * Because there is no standart way to get it.
 * TODO: Test on future Android versions 4.4+
 *
 * @return paths to all available SD-Cards in the system (include emulated)
 */
public static String[] getStorageDirectories()
{
    // Final set of paths
    final Set<String> rv = new HashSet<String>();
    // Primary physical SD-CARD (not emulated)
    final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
    // All Secondary SD-CARDs (all exclude primary) separated by ":"
    final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    // Primary emulated SD-CARD
    final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
    if(TextUtils.isEmpty(rawEmulatedStorageTarget))
    {
        // Device has physical external storage; use plain paths.
        if(TextUtils.isEmpty(rawExternalStorage))
        {
            // EXTERNAL_STORAGE undefined; falling back to default.
            rv.add("/storage/sdcard0");
        }
        else
        {
            rv.add(rawExternalStorage);
        }
    }
    else
    {
        // Device has emulated storage; external storage paths should have
        // userId burned into them.
        final String rawUserId;
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
        {
            rawUserId = "";
        }
        else
        {
            final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
            final String[] folders = DIR_SEPORATOR.split(path);
            final String lastFolder = folders[folders.length - 1];
            boolean isDigit = false;
            try
            {
                Integer.valueOf(lastFolder);
                isDigit = true;
            }
            catch(NumberFormatException ignored)
            {
            }
            rawUserId = isDigit ? lastFolder : "";
        }
        // /storage/emulated/0[1,2,...]
        if(TextUtils.isEmpty(rawUserId))
        {
            rv.add(rawEmulatedStorageTarget);
        }
        else
        {
            rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
        }
    }
    // Add all secondary storages
    if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
    {
        // All Secondary SD-CARDs splited into array
        final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
        Collections.addAll(rv, rawSecondaryStorages);
    }
    return rv.toArray(new String[rv.size()]);
}

5
DIR_SEPORATOR应该是什么?
cYrixmorten

1
@cYrixmorten在代码顶部提供了它Pattern/
Ankit Bansal,

有人在Lolipop上测试了此溶液吗?
lenrok258 2015年

我在联想P780上尝试了此方法,但无法正常工作。
Satheesh Kumar 2015年

2
适用于棒棒糖;无法在其中System.getenv("SECONDARY_STORAGE")返回的棉花糖(含6.0.1的Galaxy Tab A)上工作/storage/sdcard1。该位置不存在,但是实际位置是/storage/42CE-FD0A,其中42CE-FD0A是格式化分区的卷序列号。
DaveAlden's

32

我想使用外部SD卡,您需要使用以下代码:

new File("/mnt/external_sd/")

要么

new File("/mnt/extSdCard/")

就你而言...

代替 Environment.getExternalStorageDirectory()

为我工作。您应该先检查目录mnt中的内容,然后从那里开始工作。


您应该使用某种类型的选择方法来选择要使用的sdcard:

File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
    String[] dirList = storageDir.list();
    //TODO some type of selecton method?
}

1
好吧,实际上我想要一个方法而不是硬编码路径,但是/ mnt /列表应该可以。谢谢。
Romulus Urakagi Ts'ai 2012年

没问题。在设置中有一个选项,您可以从中选择路径,然后使用方法来检索它。
FabianCook 2012年

10
不幸的是,外部SD卡可能与/ mnt位于不同的文件夹中。例如,在三星GT-I9305上,它是/ storage / extSdCard,而内置SD卡的路径是/ storage / sdcard0
iseeall 2013年

2
好吧,您将获得sdcard位置,然后获得其父目录。
FabianCook

适用于Android 4.0+的外部SD卡(用于Pendrive通过OTG电缆连接到平板电脑的)的路径是什么?
osimer pothe 2015年

15

为了检索所有外部存储(它们是SD卡还是内部不可移动存储),可以使用以下代码:

final String state = Environment.getExternalStorageState();

if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) {  // we can read the External Storage...           
    //Retrieve the primary External Storage:
    final File primaryExternalStorage = Environment.getExternalStorageDirectory();

    //Retrieve the External Storages root directory:
    final String externalStorageRootDir;
    if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) {  // no parent...
        Log.d(TAG, "External Storage: " + primaryExternalStorage + "\n");
    }
    else {
        final File externalStorageRoot = new File( externalStorageRootDir );
        final File[] files = externalStorageRoot.listFiles();

        for ( final File file : files ) {
            if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) {  // it is a real directory (not a USB drive)...
                Log.d(TAG, "External Storage: " + file.getAbsolutePath() + "\n");
            }
        }
    }
}

或者,您可以使用System.getenv(“ EXTERNAL_STORAGE”)检索主外部存储目录(例如“ / storage / sdcard0”)和System.getenv(“ SECONDARY_STORAGE”)来检索所有辅助目录的列表(例如“ / storage / extSdCard:/ storage / UsbDriveA:/ storage / UsbDriveB“)。请记住,同样在这种情况下,您可能希望过滤辅助目录列表以排除USB驱动器。

无论如何,请注意,使用硬编码路径始终是一种不好的方法(尤其是当每个制造商都可以根据需要更改时)。


System.getenv(“SECONDARY_STORAGE”)没有工作了关于Nexus 5和Nexus 7,通过OTG线连接的USB设备
Khawar拉扎

这是直到牛轧糖都有效的我的解决方案:stackoverflow.com/a/40205116/5002496
Gokul NC

14

我一直使用Dmitriy Lozenko的解决方案,直到我检查了Asus Zenfone2棉花糖6.0.1并解决了该问题。在获取EMULATED_STORAGE_TARGET时,解决方案失败,特别是针对microSD路径,即:/ storage / F99C-10F4 /。我编辑了代码,以直接从模拟的应用程序路径获取模拟的根路径,context.getExternalFilesDirs(null);并添加更多已知的特定于电话模型的物理路径。

为了使我们的生活更轻松,我在这里建了一座图书馆。您可以通过gradle,maven,sbt和leiningen构建系统使用它。

如果您喜欢老式的方法,则也可以直接从此处复制粘贴文件,但是如果不手动检查它的话,您将不知道将来是否有更新。

如果您有任何问题或建议,请告诉我


1
我没有广泛使用它,但是对于我的问题来说效果很好。
大卫,

1
很好的解决方案!但是请注意-如果在应用程序处于活动状态时删除SD卡,context.getExternalFilesDirs(null)则会返回null其中一个文件,并且在以下循环中将出现异常。我建议添加if (file == null) continue;为循环的第一行。
Koger

1
@Koger谢谢您的建议,我已经添加了它,并为我的答案定
错了字

13

好消息!在KitKat中,现在有一个公共API可与这些辅助共享存储设备进行交互。

新方法Context.getExternalFilesDirs()Context.getExternalCacheDirs()方法可以返回多个路径,包括主设备和辅助设备。然后,您可以遍历它们并检查Environment.getStorageState()File.getFreeSpace()确定存储文件的最佳位置。ContextCompat在support-v4库中也可以使用这些方法。

另请注意,如果您仅对使用所返回的目录感兴趣,则Context不再需要READ_WRITE_EXTERNAL_STORAGE权限。展望未来,您将始终具有对这些目录的读/写访问权限,而无需其他权限。

应用也可以通过终止其许可请求来继续在旧设备上工作,如下所示:

<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="18" />

谢谢。我已经按照您编写的内容编写了一些代码,并且我认为它可以很好地找到所有SD卡路径。你可以看看吗?此处:stackoverflow.com/a/27197248/878126。顺便说一句,您不应该使用“ getFreeSpace”,因为从理论上讲,可用空间会在运行时改变。
Android开发人员


10

我执行以下操作以获取所有外部SD卡的权限。

带有:

File primaryExtSd=Environment.getExternalStorageDirectory();

您将获得通往主外部SD的路径,然后输入:

File parentDir=new File(primaryExtSd.getParent());

您将获得主要外部存储的父目录,它也是所有外部sd的父目录。现在,您可以列出所有存储并选择所需的存储。

希望它是有用的。


这应该是公认的答案,谢谢您,它很有用。
Meanman '17

9

这是我获取SD卡路径列表(不包括主要外部存储设备)的方式:

  /**
   * returns a list of all available sd cards paths, or null if not found.
   * 
   * @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
   */
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  public static List<String> getSdCardPaths(final Context context,final boolean includePrimaryExternalStorage)
    {
    final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
    if(externalCacheDirs==null||externalCacheDirs.length==0)
      return null;
    if(externalCacheDirs.length==1)
      {
      if(externalCacheDirs[0]==null)
        return null;
      final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
      if(!Environment.MEDIA_MOUNTED.equals(storageState))
        return null;
      if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
        return null;
      }
    final List<String> result=new ArrayList<>();
    if(includePrimaryExternalStorage||externalCacheDirs.length==1)
      result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
    for(int i=1;i<externalCacheDirs.length;++i)
      {
      final File file=externalCacheDirs[i];
      if(file==null)
        continue;
      final String storageState=EnvironmentCompat.getStorageState(file);
      if(Environment.MEDIA_MOUNTED.equals(storageState))
        result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
      }
    if(result.isEmpty())
      return null;
    return result;
    }

  /** Given any file/folder inside an sd card, this will return the path of the sd card */
  private static String getRootOfInnerSdCardFolder(File file)
    {
    if(file==null)
      return null;
    final long totalSpace=file.getTotalSpace();
    while(true)
      {
      final File parentFile=file.getParentFile();
      if(parentFile==null||parentFile.getTotalSpace()!=totalSpace||!parentFile.canRead())
        return file.getAbsolutePath();
      file=parentFile;
      }
    }

externalCacheDirs[0].getParentFile().getParentFile().getParentFile().getParentFile().getAbsolutePath()这是灾难的秘诀。如果执行此操作,则不妨硬编码所需的路径,如果您获得的缓存目录中有4个双亲以外的其他内容,则会得到NullPointerException或错误的路径。
rharter 2014年

@rharter正确。也修复了此问题。请看一看。
android开发人员

docs(developer.android.com/reference/android/content/…)说:“此处返回的外部存储设备被视为设备的永久部分,包括模拟的外部存储和物理媒体插槽,例如电池中的SD卡返回的路径不包括瞬态设备,例如USB闪存驱动器。” 听起来它们也不包含SD卡插槽,也就是说,您可以在不放下电池的情况下卸下SD卡的位置。不过很难说。
拉尔斯

1
@LarsH好吧,我已经在SGS3(和真实的SD卡)上进行了自己的测试,因此我认为它也可以在其他设备上使用。
Android开发人员

5

感谢你们提供的线索,尤其是@SmartLemon,我得到了解决方案。万一有人需要,我将我的最终解决方案放在这里(找到第一个列出的外部SD卡):

public File getExternalSDCardDirectory()
{
    File innerDir = Environment.getExternalStorageDirectory();
    File rootDir = innerDir.getParentFile();
    File firstExtSdCard = innerDir ;
    File[] files = rootDir.listFiles();
    for (File file : files) {
        if (file.compareTo(innerDir) != 0) {
            firstExtSdCard = file;
            break;
        }
    }
    //Log.i("2", firstExtSdCard.getAbsolutePath().toString());
    return firstExtSdCard;
}

如果那里没有外部SD卡,则它将返回板载存储。如果sdcard不存在,我将使用它,您可能需要更改它。


1
在Android版本19上抛出null。rootDir.listFiles()返回null。我已经使用nexus 7,模拟器和银河笔记对其进行了测试。
Manu Zi 2014年

3

请参阅我的代码,希望对您有所帮助:

    Runtime runtime = Runtime.getRuntime();
    Process proc = runtime.exec("mount");
    InputStream is = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    String line;
    String mount = new String();
    BufferedReader br = new BufferedReader(isr);
    while ((line = br.readLine()) != null) {
        if (line.contains("secure")) continue;
        if (line.contains("asec")) continue;

        if (line.contains("fat")) {//TF card
            String columns[] = line.split(" ");
            if (columns != null && columns.length > 1) {
                mount = mount.concat("*" + columns[1] + "\n");
            }
        } else if (line.contains("fuse")) {//internal storage
            String columns[] = line.split(" ");
            if (columns != null && columns.length > 1) {
                mount = mount.concat(columns[1] + "\n");
            }
        }
    }
    txtView.setText(mount);

2

实际上,在某些设备中,外部sdcard默认名称显示为extSdCard,对于其他设备则显示为sdcard1

此代码段有助于找出确切的路径,并帮助您检索外部设备的路径。

String sdpath,sd1path,usbdiskpath,sd0path;    
        if(new File("/storage/extSdCard/").exists())
            {
               sdpath="/storage/extSdCard/";
               Log.i("Sd Cardext Path",sdpath);
            }
        if(new File("/storage/sdcard1/").exists())
         {
              sd1path="/storage/sdcard1/";
              Log.i("Sd Card1 Path",sd1path);
         }
        if(new File("/storage/usbcard1/").exists())
         {
              usbdiskpath="/storage/usbcard1/";
              Log.i("USB Path",usbdiskpath);
         }
        if(new File("/storage/sdcard0/").exists())
         {
              sd0path="/storage/sdcard0/";
              Log.i("Sd Card0 Path",sd0path);
         }

这极大地帮助了我。
Droid Chris

有些设备使用“ / storage / external_sd”(LG G3 KitKat),棉花糖有一些不同的方案,使用Android 6.0的Nexus 5X上的内部存储为“ / mnt / sdcard”,而外部SD卡位于“ / storage”下/ XXXX-XXXX”
AB

2

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

我和你有同样的要求。所以我从我的项目中为您创建了一个示例示例,请转到此链接,其中使用androi-dirchooser库的Android目录选择器示例。本示例检测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);
        }


    }
});

2

该解决方案(由该问题的其他答案组合而成)处理的事实(如@ono所述)System.getenv("SECONDARY_STORAGE")与棉花糖无关。

经过测试并致力于:

  • 三星Galaxy Tab 2(Android 4.1.1-股票)
  • 三星Galaxy Note 8.0(Android 4.2.2-库存)
  • 三星Galaxy S4(Android 4.4-股票)
  • 三星Galaxy S4(Android 5.1.1-Cyanogenmod)
  • 三星Galaxy Tab A(Android 6.0.1-股票)

    /**
     * Returns all available external SD-Card roots in the system.
     *
     * @return paths to all available external SD-Card roots in the system.
     */
    public static String[] getStorageDirectories() {
        String [] storageDirectories;
        String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            List<String> results = new ArrayList<String>();
            File[] externalDirs = applicationContext.getExternalFilesDirs(null);
            for (File file : externalDirs) {
                String path = file.getPath().split("/Android")[0];
                if((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Environment.isExternalStorageRemovable(file))
                        || rawSecondaryStoragesStr != null && rawSecondaryStoragesStr.contains(path)){
                    results.add(path);
                }
            }
            storageDirectories = results.toArray(new String[0]);
        }else{
            final Set<String> rv = new HashSet<String>();
    
            if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
                final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
                Collections.addAll(rv, rawSecondaryStorages);
            }
            storageDirectories = rv.toArray(new String[rv.size()]);
        }
        return storageDirectories;
    }

条件rawSecondaryStoragesStr.contains(path)可以允许内部存储也被添加;我们遇到了这个问题,因为我的设备使用,返回了内部存储目录System.getenv("SECONDARY_STORAGE"),但是使用System.getenv(EXTERNAL_STORAGE)KitKat则返回了外部存储卡路径。似乎不同厂商已经没有任何该死的标准不同的方式实现这个..
戈库尔NC

这是直到牛轧糖都有效的我的解决方案:stackoverflow.com/a/40205116/5002496
Gokul NC

1

在某些设备上(例如三星sII),内部存储卡可能位于vfat中。在这种情况下,请使用最后一个代码,我们获得路径内部存储卡(/ mnt / sdcad),但没有外部存储卡。下面的代码参考解决了这个问题。

static String getExternalStorage(){
         String exts =  Environment.getExternalStorageDirectory().getPath();
         try {
            FileReader fr = new FileReader(new File("/proc/mounts"));       
            BufferedReader br = new BufferedReader(fr);
            String sdCard=null;
            String line;
            while((line = br.readLine())!=null){
                if(line.contains("secure") || line.contains("asec")) continue;
            if(line.contains("fat")){
                String[] pars = line.split("\\s");
                if(pars.length<2) continue;
                if(pars[1].equals(exts)) continue;
                sdCard =pars[1]; 
                break;
            }
        }
        fr.close();
        br.close();
        return sdCard;  

     } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

1
       File[] files = null;
    File file = new File("/storage");// /storage/emulated
if (file.exists()) {
        files = file.listFiles();
            }
            if (null != files)
                for (int j = 0; j < files.length; j++) {
                    Log.e(TAG, "" + files[j]);
                    Log.e(TAG, "//--//--// " +             files[j].exists());

                    if (files[j].toString().replaceAll("_", "")
                            .toLowerCase().contains("extsdcard")) {
                        external_path = files[j].toString();
                        break;
                    } else if (files[j].toString().replaceAll("_", "")
                            .toLowerCase()
                            .contains("sdcard".concat(Integer.toString(j)))) {
                        // external_path = files[j].toString();
                    }
                    Log.e(TAG, "--///--///--  " + external_path);
                }

0

我确信这段代码一定能解决您的问题...对我来说这很好... \

try {
            File mountFile = new File("/proc/mounts");
            usbFoundCount=0;
            sdcardFoundCount=0;
            if(mountFile.exists())
             {
                Scanner usbscanner = new Scanner(mountFile);
                while (usbscanner.hasNext()) {
                    String line = usbscanner.nextLine();
                    if (line.startsWith("/dev/fuse /storage/usbcard1")) {
                        usbFoundCount=1;
                        Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
                    }
            }
         }
            if(mountFile.exists()){
                Scanner sdcardscanner = new Scanner(mountFile);
                while (sdcardscanner.hasNext()) {
                    String line = sdcardscanner.nextLine();
                    if (line.startsWith("/dev/fuse /storage/sdcard1")) {
                        sdcardFoundCount=1;
                        Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
                    }
            }
         }
            if(usbFoundCount==1)
            {
                Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
                Log.i("-----USB--------","USB Connected and properly mounted" );
            }
            else
            {
                Toast.makeText(context,"USB not found!!!!", 7000).show();
                Log.i("-----USB--------","USB not found!!!!" );

            }
            if(sdcardFoundCount==1)
            {
                Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
                Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
            }
            else
            {
                Toast.makeText(context,"SDCard not found!!!!", 7000).show();
                Log.i("-----SDCard--------","SDCard not found!!!!" );

            }
        }catch (Exception e) {
            e.printStackTrace();
        } 

Environment.getExternalStorageDirectory()不应为您提供外部sdcard或usb位置的确切位置。只需解析到“ / proc / mounts”位置,然后/ dev / fuse / storage / sdcard1”将为您提供该位置,无论您的sdcard是否正确安装或不相同的USB also.This,您就可以轻松获得it..Cheers..Sam
山姆

0

这不是真的。即使未安装SD卡,/ mnt / sdcard / external_sd也可以存在。当您尝试在未挂载时写入/ mnt / sdcard / external_sd时,应用程序将崩溃。

您需要使用以下方法检查是否首先安装了SD卡:

boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

7
getExternalStorageState()我认为,当返回内部存储而不是外部SD卡时,这毫无意义。
Romulus Urakagi Ts'ai 2012年

他们是否提供立即获取外部SD卡的功能?搜索一个小时后,我找不到任何线索。如果是这种情况,那么在更新了许多版本之后,这真是太奇怪了。
rml 2013年

当您说“那不是真的”时,您指的是什么?我知道,那是2.5年前……
LarsH

0
 String path = Environment.getExternalStorageDirectory()
                        + File.separator + Environment.DIRECTORY_PICTURES;
                File dir = new File(path);

4
没用 它返回内部存储的路径。即/ storage / emulated / 0

0

您可以使用-Co​​ntext.getExternalCacheDirs()或Context.getExternalFilesDirs()或Context.getObbDirs()之类的东西。它们在所有外部存储设备中为应用程序提供特定于目录的目录,应用程序可以在其中存储其文件。

所以像这样-Context.getExternalCacheDirs()[i] .getParentFile()。getParentFile()。getParentFile()。getParent()可以让您获取外部存储设备的根路径。

我知道这些命令是出于不同的目的,但其他答案对我却不起作用。

这个链接给了我很好的指导-https: //possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")为棉花糖返回null。这是找到所有外部因素的另一种方法。您可以检查它是否可移动,从而确定内部/外部

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    File[] externalCacheDirs = context.getExternalCacheDirs();
    for (File file : externalCacheDirs) {
        if (Environment.isExternalStorageRemovable(file)) {
            // It's a removable storage
        }
    }
}

0

我已经在我的Samsung Galaxy Tab S2(型号:T819Y)上尝试了Dmitriy LozenkoGnathonic提供的解决方案,但是没有一个帮助我检索到外部SD卡目录的路径。命令执行包含指向外部SD卡目录的必需路径(即/ Storage / A5F9-15F4),但它与正则表达式不匹配,因此未返回。我没有三星遵循的目录命名机制。为什么它们偏离标准(例如extsdcard),并提出了一些像我这样的问题(例如/ Storage / A5F9-15F4)。我有什么想念的吗?无论如何,随着Gnathonic的正则表达式的变化mount 解决方案帮助我获得了有效的sdcard目录:

final HashSet<String> out = new HashSet<String>();
        String reg = "(?i).*(vold|media_rw).*(sdcard|vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
        String s = "";
        try {
            final Process process = new ProcessBuilder().command("mount")
                    .redirectErrorStream(true).start();
            process.waitFor();
            final InputStream is = process.getInputStream();
            final byte[] buffer = new byte[1024];
            while (is.read(buffer) != -1) {
                s = s + new String(buffer);
            }
            is.close();
        } catch (final Exception e) {
            e.printStackTrace();
        }

        // parse output
        final String[] lines = s.split("\n");
        for (String line : lines) {
            if (!line.toLowerCase(Locale.US).contains("asec")) {
                if (line.matches(reg)) {
                    String[] parts = line.split(" ");
                    for (String part : parts) {
                        if (part.startsWith("/"))
                            if (!part.toLowerCase(Locale.US).contains("vold"))
                                out.add(part);
                    }
                }
            }
        }
        return out;

我不确定这是否是有效的解决方案,是否可以为其他三星平板电脑提供结果,但目前它已解决了我的问题。以下是在Android(v6.0)中检索可移动SD卡路径的另一种方法。我已经用android棉花糖测试了该方法,并且有效。它使用的方法是非常基本的,并且肯定也适用于其他版本,但是必须进行测试。对此有所了解将有所帮助:

public static String getSDCardDirPathForAndroidMarshmallow() {

    File rootDir = null;

    try {
        // Getting external storage directory file
        File innerDir = Environment.getExternalStorageDirectory();

        // Temporarily saving retrieved external storage directory as root
        // directory
        rootDir = innerDir;

        // Splitting path for external storage directory to get its root
        // directory

        String externalStorageDirPath = innerDir.getAbsolutePath();

        if (externalStorageDirPath != null
                && externalStorageDirPath.length() > 1
                && externalStorageDirPath.startsWith("/")) {

            externalStorageDirPath = externalStorageDirPath.substring(1,
                    externalStorageDirPath.length());
        }

        if (externalStorageDirPath != null
                && externalStorageDirPath.endsWith("/")) {

            externalStorageDirPath = externalStorageDirPath.substring(0,
                    externalStorageDirPath.length() - 1);
        }

        String[] pathElements = externalStorageDirPath.split("/");

        for (int i = 0; i < pathElements.length - 1; i++) {

            rootDir = rootDir.getParentFile();
        }

        File[] files = rootDir.listFiles();

        for (File file : files) {
            if (file.exists() && file.compareTo(innerDir) != 0) {

                // Try-catch is implemented to prevent from any IO exception
                try {

                    if (Environment.isExternalStorageRemovable(file)) {
                        return file.getAbsolutePath();

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

如果您有其他方法可以解决此问题,请与我们分享。谢谢


这是直到牛轧糖都有效的我的解决方案:stackoverflow.com/a/40205116/5002496
Gokul NC

我在华硕Zenfone 2上确实遇到了同样的问题,但我改用了Dmitriy Lozenko的代码来解决问题stackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD您建议的解决方案可能不适用于Android Marshmallow(6.0),因为其中已删除了对环境变量的支持。我不能完全记得,但我想我已经尝试过了。
阿卜杜勒·雷曼

@GokulNC我会尝试一下。似乎合法:)
阿卜杜勒·雷曼

@GokulNC是的,这就是为什么我使用context.getExternalFilesDirs(null); 版本为>棉花糖时,而不是直接使用物理路径
HendraWD

0
String secStore = System.getenv("SECONDARY_STORAGE");

File externalsdpath = new File(secStore);

这将获取外部sd二级存储的路径。


0
//manifest file outside the application tag
//please give permission write this 
//<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        File file = new File("/mnt");
        String[] fileNameList = file.list(); //file names list inside the mnr folder
        String all_names = ""; //for the log information
        String foundedFullNameOfExtCard = ""; // full name of ext card will come here
        boolean isExtCardFounded = false;
        for (String name : fileNameList) {
            if (!isExtCardFounded) {
                isExtCardFounded = name.contains("ext");
                foundedFullNameOfExtCard = name;
            }
            all_names += name + "\n"; // for log
        }
        Log.d("dialog", all_names + foundedFullNameOfExtCard);

或者,这对于初学者来说至少是获取设备中安装的所有驱动程序的stringList。
Emre Kilinc Arslan

0

要访问HTC One X(Android)上SD卡中的文件,请使用以下路径:

file:///storage/sdcard0/folder/filename.jpg

注意三元组“ /”!


-1

在Galaxy S3 Android 4.3上,我使用的路径是./storage/extSdCard/Card/,它可以完成工作。希望能帮助到你,


-1

以下步骤对我有用。您只需要编写以下行:

String sdf = new String(Environment.getExternalStorageDirectory().getName());
String sddir = new String(Environment.getExternalStorageDirectory().getPath().replace(sdf,""));

第一行将给出sd目录的名称,您只需要在第二个字符串的replace方法中使用它即可。第二个字符串将包含内部sd(/ storage /)的路径。我只是为我的应用程序需要此路径,但是如果需要,您可以走得更远。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.