Как я могу получить путь к внешней SD-карте для Android 4.0+?

94

Samsung Galaxy S3 имеет внешний слот для SD-карты, к которому крепится /mnt/extSdCard.

Как я могу получить этот путь чем-то вроде Environment.getExternalStorageDirectory()?

Это вернется mnt/sdcard, и я не могу найти API для внешней SD-карты. (Или съемный USB-накопитель на некоторых планшетах.)

Ромул Уракаги Цай
источник
а зачем тебе это? На Android делать подобные вещи крайне не рекомендуется. Возможно, если вы разделите свою мотивацию, мы сможем указать вам на лучшую практику для этого типа вещей.
rharter
2
Когда пользователь меняет свой телефон, подключите SD-карту к новому телефону, и на первом телефоне это / sdcard, на втором телефоне это / mnt / extSdCard, все, что использует путь к файлу, терпит крах. Мне нужно создать реальный путь из его относительного пути.
Ромул Уракаги Цай
Я сейчас эта тема старая, но это может помочь. вам следует использовать этот метод. System.getenv (); см. проект Environment3, чтобы получить доступ ко всем хранилищам, подключенным к вашему устройству. github.com/omidfaraji/Environment3
Омид Фараджи,
Возможный дубликат поиска внешнего местоположения SD-карты
Брайан Роджерс
Вот мое решение, которое работает до Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

Ответы:

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;
}

Оригинальный метод был протестирован и работал с

  • Huawei X3 (сток)
  • Galaxy S2 (сток)
  • Galaxy S3 (сток)

Я не уверен, на какой версии Android они были на момент тестирования.

Я тестировал свою модифицированную версию с

  • Moto Xoom 4.1.2 (стоковая)
  • Galaxy Nexus (cyanogenmod 10) с помощью кабеля otg
  • HTC Incredible (cyanogenmod 7.2) вернул как внутренний, так и внешний. Это устройство является своего рода чудаком, поскольку его внутренняя часть в основном не используется, поскольку getExternalStorage () вместо этого возвращает путь к SD-карте.

и некоторые отдельные устройства хранения, которые используют SD-карту в качестве основного хранилища

  • HTC G1 (cyanogenmod 6.1)
  • HTC G1 (сток)
  • HTC Vision / G2 (в наличии)

За исключением Incredible, все эти устройства вернули только свои съемные накопители. Вероятно, мне следует провести дополнительные проверки, но это, по крайней мере, немного лучше, чем любое решение, которое я нашел до сих пор.

Гнатонический
источник
3
Я думаю, что ваше решение даст неверное имя папки, если исходное имя содержит заглавные буквы, такие как / mnt / SdCard
Евгений Попович
1
Я тестировал на некоторых устройствах Motorola, Samsung и LG, и они отлично работали.
pepedeutico
2
@KhawarRaza, этот метод перестал работать с kitkat. Используйте метод Дмитрия Лозенко в качестве запасного варианта, если вы поддерживаете устройства pre-ics.
Gnathonic 06
1
Работает на HUAWEI Honor 3c. Спасибо.
li2 02 авг.15,
2
это возвращение / мнт вместо / хранения на 4.0+ для меня на Galaxy Note 3
Ono
54

Я нашел более надежный способ получить пути ко всем SD-картам в системе. Это работает на всех версиях Android и обеспечивает возврат ко всем хранилищам (включая эмуляцию).

Правильно работает на всех моих устройствах.

PS: На основе исходного кода класса Environment.

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 07
1
@cYrixmorten это предоставляется поверх кода .. это Patternдля/
Ankit Bansal
Кто-нибудь тестировал это решение на Lolipop?
lenrok258 02
Пробовал этот метод на lenovo P780. Не работает.
Сатиш Кумар
2
Работает до Lollipop; не работает на Marshmallow (Galaxy Tab A с 6.0.1), откуда System.getenv("SECONDARY_STORAGE")возвращается /storage/sdcard1. Это местоположение не существует, но фактическое местоположение есть /storage/42CE-FD0A, где 42CE-FD0A - серийный номер тома отформатированного раздела.
DaveAlden 07
32

Я думаю, чтобы использовать внешнюю SD-карту, вам нужно использовать это:

new File("/mnt/external_sd/")

ИЛИ

new File("/mnt/extSdCard/")

в твоем случае...

вместо Environment.getExternalStorageDirectory()

Работает для меня. Вы должны сначала проверить, что находится в каталоге mnt, и работать оттуда ..


Вы должны использовать какой-либо метод выбора, чтобы выбрать, какую SD-карту использовать:

File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
    String[] dirList = storageDir.list();
    //TODO some type of selecton method?
}
FabianCook
источник
1
На самом деле мне нужен метод, а не путь жесткого кода, но список / mnt / должен быть в порядке. Спасибо.
Romulus Urakagi Ts'ai
Нет проблем. У вас есть опция в настройках, из которой вы выбираете путь, а затем используйте метод для его получения.
FabianCook 07
10
К сожалению, внешняя SD-карта может находиться в другой папке, чем / mnt. Например, на Samsung GT-I9305 это / storage / extSdCard, а для встроенной SD-карты путь / storage / sdcard0
iseeall
2
Тогда вы получите местоположение SD-карты, а затем ее родительский каталог.
FabianCook
Какой будет путь к внешней SD-карте (для флешки, подключенной к планшету через кабель OTG) для Android 4.0+?
Osimer pothe
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") для получения списка всех вторичных каталогов (например, " / хранилище / extSdCard: / хранилище / UsbDriveA: / хранилище / UsbDriveB " ). Помните, что и в этом случае вы можете отфильтровать список дополнительных каталогов, чтобы исключить USB-накопители.

В любом случае, обратите внимание, что использование жестко заданных путей всегда является плохим подходом (особенно когда каждый производитель может изменить его по своему усмотрению).

Паоло Ровелли
источник
System.getenv ("SECONDARY_STORAGE") НЕ работал с USB-устройствами, подключенными через кабель OTG на Nexus 5 и Nexus 7.
Khawar Raza
Вот мое решение, которое работает до Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC
14

Я использовал решение Дмитрия Лозенко , пока не проверил Asus Zenfone2 , Marshmallow 6.0.1, и решение не работает. Решение не удалось при получении EMULATED_STORAGE_TARGET , особенно для пути microSD, то есть: / storage / F99C-10F4 / . Я отредактировал код, чтобы получить эмулируемые корневые пути непосредственно из эмулированных путей приложения, context.getExternalFilesDirs(null);и добавил больше известных физических путей для конкретных моделей телефонов .

Для того, чтобы сделать нашу жизнь проще, я сделал библиотеку здесь . Вы можете использовать его через систему сборки gradle, maven, sbt и leiningen.

Если вам нравится старомодный способ, вы также можете скопировать и вставить файл прямо отсюда , но вы не узнаете, будет ли обновление в будущем, не проверив его вручную.

Если у вас есть вопросы или предложения, дайте мне знать

HendraWD
источник
1
Я не использовал это широко, но это хорошо работает для моей проблемы.
Дэвид
1
Отличное решение! Однако одно замечание - если SD-карта будет удалена, когда приложение активно, context.getExternalFilesDirs(null)вернется nullк одному из файлов, и в следующем цикле будет исключение. Предлагаю добавить if (file == null) continue;в качестве первой строчки цикла.
Koger
1
@Koger, спасибо за предложение, я добавил его и исправил опечатку в своем ответе
HendraWD
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
передняя ссылка developer.android.com/reference/android/content/…
Strubbl
10

Я сделал следующее, чтобы получить доступ ко всем внешним SD-картам.

С участием:

File primaryExtSd=Environment.getExternalStorageDirectory();

вы получаете путь к первичной внешней SD Затем с помощью:

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

вы получаете родительский каталог первичного внешнего хранилища, а также он является родительским для всех внешних SD. Теперь вы можете перечислить все хранилища и выбрать тот, который вам нужен.

Надеюсь, это будет полезно.

валента
источник
Это должен быть принятый ответ, и спасибо, что он полезен.
Meanman
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;
      }
    }
разработчик Android
источник
externalCacheDirs[0].getParentFile().getParentFile().getParentFile().getParentFile().getAbsolutePath()Это рецепт катастрофы. Если вы делаете это, вы можете просто жестко закодировать нужный путь, поскольку если вы получите каталог кеша с чем-либо, кроме 4 родителей, вы получите NullPointerException или неправильный путь.
rharter
@rharter Правильно. Исправлена ​​и эта проблема. Пожалуйста, посмотрите.
разработчик Android
В документации ( developer.android.com/reference/android/content/… ) говорится: «Возвращенные сюда внешние запоминающие устройства считаются постоянной частью устройства, включая как эмулируемые внешние накопители, так и слоты для физических носителей, например SD-карты в батарее. отсек. Возвращенные пути не включают временные устройства, такие как USB-накопители ". Похоже, в них также нет слотов для SD-карт, то есть мест, где можно вынуть SD-карту, не заходя под аккумулятор. Хотя трудно сказать.
LarsH
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-карты нет, то возвращается встроенное хранилище. Я воспользуюсь им, если SD-карты не существует, возможно, вам придется ее поменять.

rml
источник
1
это выбрасывает null на Android версии 19. rootDir.listFiles () возвращает null. Я тестировал его с помощью Nexus 7, эмулятора и Galaxy Note.
Manu Zi
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);
cst05001
источник
2

На самом деле на некоторых устройствах имя внешней SD-карты по умолчанию отображается как 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), Marshmallow имеет другую схему, внутреннее хранилище на Nexus 5X с Android 6.0 - «/ mnt / sdcard», а внешняя SD-карта находится в «/ storage». / XXXX-XXXX "
AB
2

Да. Разные производители используют разные имена SD-карт, например, в Samsung Tab 3 его extsd, а другие устройства Samsung используют SD-карту, как этот другой производитель использует разные имена.

У меня было такое же требование, как и у вас. поэтому я создал для вас пример из моего проекта, перейдите по этой ссылке Пример выбора каталога Android, который использует библиотеку androi-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);
        }


    }
});
Шиварадж Патил
источник
2

Это решение (собранное из других ответов на этот вопрос) обрабатывает факт (как упоминается @ono), который System.getenv("SECONDARY_STORAGE")бесполезен для Marshmallow.

Проверено и работает:

  • Samsung Galaxy Tab 2 (Android 4.1.1 - Стоковая)
  • Samsung Galaxy Note 8.0 (Android 4.2.2 - стоковый)
  • Samsung Galaxy S4 (Android 4.4 - стоковый)
  • Samsung Galaxy S4 (Android 5.1.1 - Cyanogenmod)
  • Samsung 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; похоже, что разные поставщики реализовали это по-разному, без какого-либо проклятого стандарта ..
Gokul NC
Вот мое решение, которое работает до Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC
1

На некоторых устройствах (например samsung galaxy sII) внутренняя карта памяти mabe должна быть в 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;
}
Alex
источник
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 () не должен сообщать вам точное местоположение вашей внешней SD-карты или местоположения USB. Просто проанализируйте местоположение "/ proc / mounts", тогда / dev / fuse / storage / sdcard1 "даст вам местоположение, правильно ли ваша SD-карта. установленный или не такой же и для usb. Таким образом, вы можете легко его получить .. Привет ..
Сэм
0

это не правда. / mnt / sdcard / external_sd может существовать, даже если SD-карта не подключена. ваше приложение выйдет из строя при попытке записи в / mnt / sdcard / external_sd, когда оно не смонтировано.

вам нужно сначала проверить, смонтирована ли SD-карта, используя:

boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
Марцин Скочилас
источник
7
getExternalStorageState()Я думаю, это бессмысленно, когда возвращает внутреннее хранилище, а не внешнюю SD-карту.
Ромул Уракаги Цай
Есть ли у них теперь возможность получить внешнюю SD-карту? Я не могу найти никакой подсказки после часа поисков. Если это так, то это так странно после стольких обновлений версий.
rml
Когда вы сказали «это неправда», что вы имели в виду? Я знаю, это было 2,5 года назад ...
Ларш 01
0
 String path = Environment.getExternalStorageDirectory()
                        + File.separator + Environment.DIRECTORY_PICTURES;
                File dir = new File(path);
сарра шрайри
источник
4
Не работает. Возвращает путь к внутренней памяти. ie / storage /
0

Вы можете использовать что-то вроде - Context.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 для Marshmallow. Это еще один способ найти все внешние каталоги. Вы можете проверить, является ли он съемным, который определяет, является ли внутренний / внешний

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

Я пробовал решения, предоставленные Дмитрием Лозенко и Gnathonic на моем Samsung Galaxy Tab S2 (модель: T819Y), но ни одно не помогло мне получить путь к внешней директории SD-карты. mountвыполнение команды содержало требуемый путь к внешней директории SD-карты (например, / Storage / A5F9-15F4), но не соответствовало регулярному выражению, поэтому не было возвращено. Я не понимаю механизма именования каталогов, за которым следует Samsung. Почему они отклоняются от стандартов (например, extsdcard) и придумывают что-то действительно подозрительное, как в моем случае (например, / Storage / A5F9-15F4) . Что мне не хватает? В любом случае, после изменений в регулярном выражении Gnathonic's решение помогло мне получить действительный каталог 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;

Я не уверен, что это правильное решение и даст ли оно результаты для других планшетов Samsung, но на данный момент оно устранило мою проблему. Ниже приведен еще один метод получения пути к съемной SD-карте в Android (v6.0). Я протестировал метод с зефиром 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;
}

Пожалуйста, поделитесь, если у вас есть другой подход к решению этой проблемы. Благодарность

Абдул Рехман
источник
Вот мое решение, которое работает до Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC
На самом деле у меня такая же проблема с вами на Asus Zenfone 2, но я меняю код Дмитрия Лозенко вместо этого, чтобы решить проблему stackoverflow.com/a/40582634/3940133
HendraWD
@HendraWD решение, которое вы предлагаете, может не работать с Android Marshmallow (6.0), поскольку в нем удалена поддержка переменных среды. Я не могу точно вспомнить, но думаю, что попробовал.
Абдул Рехман
@GokulNC Я попробую. кажется законным :)
Абдул Рехман
@GokulNC да, поэтому я использую context.getExternalFilesDirs (null); вместо прямого использования физических путей, когда версия> Marshmallow
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);
Эмре Килиндж Арслан
источник
Это альтернативно для новичков, по крайней мере, для получения строкового списка всех драйверов, установленных в устройстве.
Эмре Килинч Арслан
0

Для доступа к файлам на моей SD-карте в HTC One X (Android) я использую этот путь:

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

Обратите внимание на тройной знак "/"!

Пользователь HTC
источник
-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, и вам просто нужно использовать его в методе замены для второй строки. Вторая строка будет содержать путь к внутреннему и съемному sd (в моем случае / storage /) . Мне просто нужен этот путь для моего приложения, но вы можете пойти дальше, если вам это нужно.

EnVoY
источник