Wie kann ich den externen SD-Kartenpfad für Android 4.0+ abrufen?


93

Das Samsung Galaxy S3 verfügt über einen externen SD-Kartensteckplatz, an den montiert werden kann /mnt/extSdCard.

Wie kann ich diesen Weg durch so etwas bekommen Environment.getExternalStorageDirectory()?

Dies wird zurückkehren mnt/sdcardund ich kann die API für die externe SD-Karte nicht finden. (Oder austauschbarer USB-Speicher auf einigen Tablets.)


Warum willst du das? Unter Android ist es sehr nicht ratsam, solche Dinge zu tun. Wenn Sie Ihre Motivation teilen, können wir Sie vielleicht in die Richtung der besten Vorgehensweise für diese Art von Dingen weisen.
Rharter

2
Wenn Ihr Benutzer sein Telefon wechselt, die SD-Karte an ein neues Telefon anschließt und auf dem ersten Telefon / sdcard, auf dem zweiten Telefon / mnt / extSdCard, stürzt alles ab, was den Dateipfad verwendet. Ich muss einen realen Pfad aus seinem relativen Pfad generieren.
Romulus Urakagi Ts'ai

Ich jetzt ist dieses Thema alt, aber das kann helfen. Sie sollten diese Methode verwenden. System.getenv (); Informationen zum Zugriff auf alle mit Ihrem Gerät verbundenen Speicher finden Sie unter Projektumgebung3. github.com/omidfaraji/Environment3
Omid Faraji


Hier ist meine Lösung, die bis Nougat funktioniert: stackoverflow.com/a/40205116/5002496
Gokul NC

Antworten:


58

Ich habe eine Variation einer Lösung, die ich hier gefunden habe

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

Die ursprüngliche Methode wurde getestet und bearbeitet

  • Huawei X3 (Lager)
  • Galaxy S2 (Lager)
  • Galaxy S3 (Lager)

Ich bin nicht sicher, auf welcher Android-Version diese waren, als sie getestet wurden.

Ich habe meine modifizierte Version mit getestet

  • Moto Xoom 4.1.2 (Lager)
  • Galaxy Nexus (Cyanogenmod 10) mit einem anderen Kabel
  • HTC Incredible (Cyanogenmod 7.2) gab sowohl das interne als auch das externe zurück. Dieses Gerät ist insofern etwas seltsam, als sein internes Gerät weitgehend ungenutzt bleibt, da getExternalStorage () stattdessen einen Pfad zur SD-Karte zurückgibt.

und einige einzelne Speichergeräte, die eine SD-Karte als Hauptspeicher verwenden

  • HTC G1 (Cyanogenmod 6.1)
  • HTC G1 (Lager)
  • HTC Vision / G2 (Lager)

Mit Ausnahme des Unglaublichen haben alle diese Geräte nur ihren Wechselspeicher zurückgegeben. Es gibt wahrscheinlich einige zusätzliche Überprüfungen, die ich durchführen sollte, aber dies ist zumindest ein bisschen besser als jede Lösung, die ich bisher gefunden habe.


3
Ich denke, Ihre Lösung wird einen ungültigen Ordnernamen geben, wenn der ursprüngliche Großbuchstaben wie / mnt / SdCard
Eugene Popovich

1
Ich habe auf einigen Motorola-, Samsung- und LG-Geräten getestet und es hat perfekt funktioniert.
Pepdeutico

2
@KhawarRaza, diese Methode funktioniert ab Kitkat nicht mehr. Verwenden Sie die Methode von Dmitriy Lozenko, mit dieser als Fallback, wenn Sie Pre-Iics-Geräte unterstützen.
Gnathonic

1
Arbeitet an HUAWEI Honor 3c. Vielen Dank.
2.

2
dies Rückkehr / mnt statt / Speicher auf 4.0+ für mich auf einem Galaxy Note 3
ono

54

Ich habe einen zuverlässigeren Weg gefunden, um Pfade zu allen SD-CARDs im System zu erhalten. Dies funktioniert auf allen Android-Versionen und gibt Pfade zu allen Speichern zurück (einschließlich emuliert).

Funktioniert auf allen meinen Geräten ordnungsgemäß.

PS: Basierend auf dem Quellcode der Umgebungsklasse.

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
Was sollte DIR_SEPORATOR sein?
cYrixmorten

1
@cYrixmorten seine oben auf Code zur Verfügung gestellt .. es ist ein Patternfür/
Ankit Bansal

Hat jemand diese Lösung auf Lolipop getestet?
Lenrok258

Ich habe diese Methode auf Lenovo P780 versucht. Es funktioniert nicht.
Satheesh Kumar

2
Funktioniert bis zu Lollipop; funktioniert nicht auf Marshmallow (Galaxy Tab A mit 6.0.1), wo System.getenv("SECONDARY_STORAGE")zurückgegeben wird /storage/sdcard1. Dieser Speicherort ist nicht vorhanden, der tatsächliche Speicherort jedoch /storage/42CE-FD0A, wobei 42CE-FD0A die Volume-Seriennummer der formatierten Partition ist.
DaveAlden

32

Ich denke, um die externe SD-Karte zu verwenden, benötigen Sie diese:

new File("/mnt/external_sd/")

ODER

new File("/mnt/extSdCard/")

in deinem Fall...

als Ersatz für Environment.getExternalStorageDirectory()

Funktioniert bei mir. Sie sollten zuerst überprüfen, was sich im Verzeichnis mnt befindet, und von dort aus arbeiten.


Sie sollten eine Auswahlmethode verwenden, um die zu verwendende SD-Karte auszuwählen:

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

1
Tatsächlich möchte ich eher eine Methode als einen Hardcode-Pfad, aber die / mnt / -Liste sollte in Ordnung sein. Danke dir.
Romulus Urakagi Ts'ai

Kein Problem. Haben Sie eine Option in den Einstellungen, aus denen Sie den Pfad auswählen, und verwenden Sie dann die Methode, um diesen abzurufen.
FabianCook

10
Leider befindet sich die externe SD-Karte möglicherweise in einem anderen Ordner als / mnt. Zum Beispiel auf Samsung GT-I9305 ist es / storage / extSdCard, während die eingebaute SD-Karte den Pfad / storage / sdcard0 hat
iseeall

2
Dann würden Sie den Speicherort der SD-Karte und dann das übergeordnete Verzeichnis erhalten.
FabianCook

Was ist der Pfad der externen SD-Karte (für Pendrive, die über ein OTG-Kabel mit dem Tablet verbunden ist) für Android 4.0+?
Osimer Pothe

15

Um alle externen Speicher abzurufen (unabhängig davon, ob es sich um SD-Karten oder interne nicht entfernbare Speicher handelt ), können Sie den folgenden Code verwenden:

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

Alternativ können Sie System.getenv ("EXTERNAL_STORAGE") verwenden , um das primäre externe Speicherverzeichnis (z. B. "/ storage / sdcard0" ) abzurufen, und System.getenv ("SECONDARY_STORAGE") , um die Liste aller sekundären Verzeichnisse (z. B. " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB " ). Denken Sie daran, dass Sie auch in diesem Fall die Liste der sekundären Verzeichnisse filtern möchten, um die USB-Laufwerke auszuschließen.

Bitte beachten Sie in jedem Fall, dass die Verwendung fest codierter Pfade immer ein schlechter Ansatz ist (insbesondere, wenn jeder Hersteller dies nach Belieben ändern kann).


System.getenv ("SECONDARY_STORAGE") funktionierte NICHT für USB-Geräte, die über ein OTG-Kabel an Nexus 5 und Nexus 7 angeschlossen waren.
Khawar Raza

Hier ist meine Lösung, die bis Nougat funktioniert: stackoverflow.com/a/40205116/5002496
Gokul NC

14

Ich habe die Lösung von Dmitriy Lozenko verwendet , bis ich ein Asus Zenfone2 , Marshmallow 6.0.1, überprüft habe und die Lösung nicht funktioniert. Die Lösung schlug fehl, als EMULATED_STORAGE_TARGET speziell für den microSD-Pfad abgerufen wurde, dh: / storage / F99C-10F4 / . Ich habe den Code bearbeitet, um die emulierten Stammpfade direkt von emulierten Anwendungspfaden mit context.getExternalFilesDirs(null);abzurufen und bekanntere telefonmodellspezifische physische Pfade hinzuzufügen .

Um unser Leben leichter zu machen, habe ich hier eine Bibliothek erstellt . Sie können es über das Build-System gradle, maven, sbt und leiningen verwenden.

Wenn Sie die altmodische Methode mögen, können Sie die Datei auch direkt von hier aus kopieren und einfügen. Sie werden jedoch nicht wissen, ob es in Zukunft ein Update gibt, ohne es manuell zu überprüfen.

Wenn Sie Fragen oder Anregungen haben, lassen Sie es mich bitte wissen


1
Ich habe dies nicht ausgiebig genutzt, aber das funktioniert gut für mein Problem.
David

1
Tolle Lösung! Ein Hinweis jedoch: Wenn die SD-Karte bei aktiver Anwendung entfernt wird, context.getExternalFilesDirs(null)wird nullfür eine der Dateien zurückgegeben, und in der folgenden Schleife tritt eine Ausnahme auf. Ich schlage vor, if (file == null) continue;als erste Zeile in der Schleife hinzuzufügen .
Koger

1
@ Koger danke für den Vorschlag, ich habe ihn hinzugefügt und einen Tippfehler zu meiner Antwort
behoben

13

Gute Nachrichten! In KitKat gibt es jetzt eine öffentliche API für die Interaktion mit diesen sekundären gemeinsam genutzten Speichergeräten.

Die Methoden new Context.getExternalFilesDirs()und Context.getExternalCacheDirs()können mehrere Pfade zurückgeben, einschließlich primärer und sekundärer Geräte. Sie können sie dann durchlaufen und überprüfen Environment.getStorageState()und File.getFreeSpace()den besten Speicherort für Ihre Dateien ermitteln. Diese Methoden sind auch ContextCompatin der support-v4-Bibliothek verfügbar .

Beachten Sie außerdem, dass Sie Contextdie Berechtigungen READ_oder nicht mehr benötigen , wenn Sie nur die von zurückgegebenen Verzeichnisse verwenden WRITE_EXTERNAL_STORAGEmöchten. In Zukunft haben Sie immer Lese- / Schreibzugriff auf diese Verzeichnisse, ohne dass zusätzliche Berechtigungen erforderlich sind.

Apps können auch auf älteren Geräten weiterarbeiten, indem sie ihre Berechtigungsanforderung wie folgt beenden:

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

Danke dir. Ich habe einen Code erstellt, der dem folgt, was Sie geschrieben haben, und ich denke, er funktioniert gut, wenn Sie alle SD-Kartenpfade finden. Kannst du dir das mal ansehen ? Hier: stackoverflow.com/a/27197248/878126. Übrigens sollten Sie "getFreeSpace" nicht verwenden, da sich der freie Speicherplatz theoretisch zur Laufzeit ändern kann.
Android-Entwickler


10

Ich habe Folgendes getan, um Zugang zu allen externen SD-Karten zu erhalten.

Mit:

File primaryExtSd=Environment.getExternalStorageDirectory();

Sie erhalten den Pfad zur primären externen SD. Dann mit:

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

Sie erhalten das übergeordnete Verzeichnis des primären externen Speichers und es ist auch das übergeordnete Verzeichnis aller externen SDs. Jetzt können Sie den gesamten Speicher auflisten und den gewünschten auswählen.

Hoffe es ist nützlich.


Dies sollte die akzeptierte Antwort sein, und danke, dass es nützlich ist.
Meanman

9

So erhalte ich die Liste der SD-Kartenpfade (ohne den primären externen Speicher):

  /**
   * 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()Dies ist ein Rezept für eine Katastrophe. Wenn Sie dies tun, können Sie den gewünschten Pfad genauso gut hart codieren, da Sie eine NullPointerException oder den falschen Pfad erhalten, wenn Sie ein Cache-Verzeichnis mit etwas anderem als 4 übergeordneten Elementen erhalten.
Rharter

@rharter Richtig. Dieses Problem wurde ebenfalls behoben. Guck dir das mal bitte an.
Android-Entwickler

In den Dokumenten ( developer.android.com/reference/android/content/… ) heißt es: "Externe Speichergeräte, die hier zurückgegeben werden, gelten als fester Bestandteil des Geräts, einschließlich emulierter externer Speicher und physischer Mediensteckplätze, z. B. SD-Karten in einem Akku Fach. Die zurückgegebenen Pfade enthalten keine vorübergehenden Geräte wie USB-Sticks. " Es hört sich so an, als ob sie auch keine SD-Kartensteckplätze enthalten, dh die Stellen, an denen Sie eine SD-Karte entfernen können, ohne unter den Akku zu gehen. Schwer zu sagen.
LarsH

1
@LarsH Nun, ich habe es selbst auf SGS3 (und einer echten SD-Karte) getestet, daher denke ich, dass es auch auf anderen Geräten funktionieren sollte.
Android-Entwickler

5

Vielen Dank für die Hinweise von euch, insbesondere @SmartLemon, ich habe die Lösung bekommen. Falls jemand anderes es braucht, stelle ich hier meine endgültige Lösung ein (um die erste aufgeführte externe SD-Karte zu finden):

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

Wenn dort keine externe SD-Karte vorhanden ist, wird der integrierte Speicher zurückgegeben. Ich werde es verwenden, wenn die SD-Karte nicht vorhanden ist. Möglicherweise müssen Sie sie ändern.


1
Dies wirft null auf Android Version 19. rootDir.listFiles () gibt null zurück. Ich habe es mit Nexus 7, Emulator und Galaxy Note getestet.
Manu Zi

3

Beziehen Sie sich auf meinen Code, hoffe hilfreich für Sie:

    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

Tatsächlich wird bei einigen Geräten der Standardname der externen SD-Karte so angezeigt, wie extSdCardbei anderen sdcard1.

Mit diesem Code-Snippet können Sie den genauen Pfad ermitteln und den Pfad des externen Geräts abrufen.

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

Das hat mir sehr geholfen.
Droid Chris

Es gibt einige Geräte, die "/ storage / external_sd" (LG G3 KitKat) verwenden, Marshmallow hat ein anderes Schema, der interne Speicher auf dem Nexus 5X mit Android 6.0 lautet "/ mnt / sdcard" und die externe SD-Karte befindet sich unter "/ storage" / XXXX-XXXX "
AB

2

Ja. Unterschiedliche Hersteller verwenden unterschiedliche SD-Kartennamen wie in Samsung Tab 3, und andere Samsung-Geräte verwenden SD-Karten wie diese. Unterschiedliche Hersteller verwenden unterschiedliche Namen.

Ich hatte die gleichen Anforderungen wie Sie. Deshalb habe ich aus meinem Projekt ein Beispielbeispiel für Sie erstellt. Gehen Sie zu diesem Link. Beispiel für eine Android-Verzeichnisauswahl , das die androi-dirchooser-Bibliothek verwendet. In diesem Beispiel wird die SD-Karte erkannt und alle Unterordner aufgelistet. Außerdem wird festgestellt, ob das Gerät mehr als eine SD-Karte hat.

Ein Teil des Codes sieht folgendermaßen aus. Ein vollständiges Beispiel finden Sie unter dem Link 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

Diese Lösung (zusammengestellt aus anderen Antworten auf diese Frage) behandelt die Tatsache (wie von @ono erwähnt), System.getenv("SECONDARY_STORAGE")die bei Marshmallow keinen Nutzen hat.

Getestet und bearbeitet an:

  • Samsung Galaxy Tab 2 (Android 4.1.1 - Lager)
  • Samsung Galaxy Note 8.0 (Android 4.2.2 - Lager)
  • Samsung Galaxy S4 (Android 4.4 - Lager)
  • Samsung Galaxy S4 (Android 5.1.1 - Cyanogenmod)
  • Samsung Galaxy Tab A (Android 6.0.1 - Lager)

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

Die Bedingung rawSecondaryStoragesStr.contains(path)kann ermöglichen, dass der interne Speicher auch hinzugefügt wird. Wir können diesen Zustand besser beseitigen. Ich war mit diesem Problem konfrontiert, da mein Gerät das interne Speicherverzeichnis mit System.getenv("SECONDARY_STORAGE")zurückgibt, aber den Pfad der externen Speicherkarte mit System.getenv(EXTERNAL_STORAGE)auf KitKat zurückgibt . Es scheint, dass verschiedene Anbieter dies ohne verdammten Standard unterschiedlich implementiert hatten.
Gokul NC

Hier ist meine Lösung, die bis Nougat funktioniert: stackoverflow.com/a/40205116/5002496
Gokul NC

1

Auf einigen Geräten (zum Beispiel Samsung Galaxy SII) kann die interne Speicherkarte in VFAT sein. In diesem Fall verwenden wir den letzten Code. Wir erhalten eine interne Speicherkarte (/ mnt / sdcad), aber keine externe Karte. Code siehe unten lösen dieses Problem.

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

Ich bin sicher, dass dieser Code sicherlich Ihre Probleme lösen wird ... Das funktioniert gut für mich ... \

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 () sollte Ihnen nicht den genauen Speicherort Ihrer externen SD-Karte oder Ihres USB-Speicherorts geben. Analysieren Sie einfach den Speicherort "/ proc / mounts", und / dev / fuse / storage / sdcard1 "gibt Ihnen den Speicherort an, ob Ihre SD-Karte ordnungsgemäß ist montiert oder nicht gleich für USB auch. Auf diese Weise können Sie es leicht bekommen .. Cheers ..
Sam

0

das ist nicht wahr. / mnt / sdcard / external_sd kann auch dann vorhanden sein, wenn die SD-Karte nicht gemountet ist. Ihre Anwendung stürzt ab, wenn Sie versuchen, in / mnt / sdcard / external_sd zu schreiben, wenn sie nicht gemountet ist.

Sie müssen überprüfen, ob die SD-Karte zuerst eingelegt ist, indem Sie Folgendes verwenden:

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

7
Dies ist bedeutungslos, wenn getExternalStorageState()der interne Speicher anstelle der externen SD-Karte zurückgegeben wird, denke ich.
Romulus Urakagi Ts'ai

Bieten sie jetzt eine Funktion, um eine externe SD-Karte zu erhalten? Ich kann nach einer Stunde Suche keinen Hinweis finden. Wenn dies der Fall ist, ist dies nach so vielen aktualisierten Versionen so seltsam.
rml

Als Sie sagten "das ist nicht wahr", worauf bezogen Sie sich? Ich weiß, das war vor 2,5 Jahren ...
LarsH

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

4
Es funktioniert nicht. Es gibt den Pfad des internen Speichers zurück. dh / storage /

0

Sie können Folgendes verwenden: Context.getExternalCacheDirs () oder Context.getExternalFilesDirs () oder Context.getObbDirs (). Sie geben anwendungsspezifische Verzeichnisse in allen externen Speichergeräten an, in denen die Anwendung ihre Dateien speichern kann.

Mit so etwas wie Context.getExternalCacheDirs () [i] .getParentFile (). GetParentFile (). GetParentFile (). GetParent () können Sie den Stammpfad externer Speichergeräte ermitteln.

Ich weiß, dass diese Befehle für einen anderen Zweck bestimmt sind, aber andere Antworten haben bei mir nicht funktioniert.

Dieser Link gab mir gute Hinweise - https://possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")Gibt für Marshmallow null zurück. Dies ist eine weitere Möglichkeit, alle externen Verzeichnisse zu finden. Sie können überprüfen, ob es entfernbar ist, um festzustellen, ob es intern / extern ist

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

Ich habe die Lösungen von Dmitriy Lozenko und Gnathonic auf meinem Samsung Galaxy Tab S2 (Modell: T819Y) ausprobiert, aber keine hat mir geholfen, den Pfad zu einem externen SD-Kartenverzeichnis abzurufen. mountDie Befehlsausführung enthielt den erforderlichen Pfad zum externen SD-Kartenverzeichnis (dh / Storage / A5F9-15F4) , stimmte jedoch nicht mit dem regulären Ausdruck überein und wurde daher nicht zurückgegeben. Ich verstehe den Verzeichnisbenennungsmechanismus nicht, gefolgt von Samsung. Warum sie von Standards abweichen (dh extsdcard) und sich etwas wirklich faul einfallen lassen, wie in meinem Fall (dh / Storage / A5F9-15F4) . Fehlt mir etwas? Wie auch immer, nach Änderungen im regulären Ausdruck von Gnathonic Die Lösung hat mir geholfen, ein gültiges SD-Kartenverzeichnis zu erhalten:

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;

Ich bin nicht sicher, ob dies eine gültige Lösung ist und ob sie Ergebnisse für andere Samsung-Tablets liefert, aber es hat mein Problem vorerst behoben. Im Folgenden finden Sie eine weitere Methode zum Abrufen des Pfads für austauschbare SD-Karten in Android (Version 6.0). Ich habe die Methode mit Android Marshmallow getestet und es funktioniert. Der darin verwendete Ansatz ist sehr einfach und wird sicherlich auch für andere Versionen funktionieren, aber das Testen ist obligatorisch. Einige Einblicke werden hilfreich sein:

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

Bitte teilen Sie uns mit, wenn Sie einen anderen Ansatz zur Behebung dieses Problems haben. Vielen Dank


Hier ist meine Lösung, die bis Nougat funktioniert: stackoverflow.com/a/40205116/5002496
Gokul NC

Ich habe tatsächlich das gleiche Problem mit Ihnen auf Asus Zenfone 2, aber ich ändere stattdessen den Code von Dmitriy Lozenko, um das Problem zu lösen stackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD Die von Ihnen vorgeschlagene Lösung funktioniert möglicherweise nicht mit Android Marshmallow (6.0), da die Unterstützung für Umgebungsvariablen darin entfernt ist. Ich kann mich nicht genau erinnern, aber ich glaube, ich habe es versucht.
Abdul Rehman

@ GokulNC Ich werde es versuchen. scheint echt :)
Abdul Rehman

@GokulNC ja, deshalb benutze ich context.getExternalFilesDirs (null); anstatt direkt physische Pfade zu verwenden, wenn die Version> Marshmallow
HendraWD

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

File externalsdpath = new File(secStore);

Dadurch wird der Pfad des externen SD-Sekundärspeichers abgerufen.


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

Dies ist alternativ für Anfänger gedacht, die mindestens die StringList aller im Gerät gemounteten Treiber erhalten.
Emre Kilinc Arslan

0

Um auf Dateien auf meiner SD-Karte auf meinem HTC One X (Android) zuzugreifen , verwende ich diesen Pfad:

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

Beachten Sie die Dreifach "/"!


-1

Unter Galaxy S3 Android 4.3 ist der Pfad, den ich verwende, ./storage/extSdCard/Card/ und er erledigt den Job. Ich hoffe es hilft,


-1

Die folgenden Schritte haben bei mir funktioniert. Sie müssen nur diese Zeilen schreiben:

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

Die erste Zeile gibt den Namen des SD-Verzeichnisses an, und Sie müssen ihn nur in der Ersetzungsmethode für die zweite Zeichenfolge verwenden. Die zweite Zeichenfolge enthält den Pfad für die interne und entfernbare SD (/ storage / in meinem Fall) . Ich brauchte diesen Pfad nur für meine App, aber Sie können weiter gehen, wenn Sie ihn brauchen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.