web-dev-qa-db-de.com

Android Open External Storage-Verzeichnis (SD-Karte) zum Speichern von Dateien

Ich möchte den Pfad des externen Speicherverzeichnisses öffnen, um die Datei programmatisch zu speichern.

private File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "");

oder

private File path = new File(Environment.getExternalStorageDirectory() + "");

Ich habe versucht, den Pfad von oben über beide Methoden zu bekommen, aber beide zeigen auf den internen Speicher.

Wenn wir den Speicherspeicher öffnen, wenn die SD-Karte vorhanden ist, wird dies wie folgt angezeigt: -enter image description here

gerätespeicher und SD-Speicherkarte.

Ich möchte den Speicherpfad von sd durch Codierung erhalten.

    <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission Android:name="Android.permission.STORAGE" />
    <uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
34
yuva ツ

Ich hatte genau das gleiche Problem!

Um die interne SD-Karte zu erhalten, können Sie verwenden

String extStore = System.getenv("EXTERNAL_STORAGE");
File f_exts = new File(extStore);

Um die externe SD-Karte zu erhalten, können Sie verwenden

String secStore = System.getenv("SECONDARY_STORAGE");
File f_secs = new File(secStore);

Beim Ausführen des Codes

 extStore = "/storage/emulated/legacy"
 secStore = "/storage/extSdCarcd"

funktioniert perfekt!

60
Rijul Gupta

Der interne Speicher wird in der API als "externer Speicher" bezeichnet.

Wie in der Umgebung Dokumentation erwähnt

Hinweis: Lassen Sie sich nicht vom Wort "extern" verwechseln. Dieses Verzeichnis kann besser als Medien/gemeinsam genutzter Speicher betrachtet werden. Es ist ein Dateisystem, das eine relativ große Datenmenge aufnehmen kann und von allen Anwendungen gemeinsam genutzt wird (erzwingt keine Berechtigungen). Normalerweise handelt es sich hierbei um eine SD-Karte, sie kann jedoch auch als eingebauter Speicher in einem Gerät implementiert werden, das sich vom geschützten internen Speicher unterscheidet und als Dateisystem auf einem Computer eingehängt werden kann.

Um zu unterscheiden, ob "Environment.getExternalStorageDirectory ()" tatsächlich physisch internen oder externen Speicher zurückgegeben hat, rufen Sie Environment.isExternalStorageEmulated () auf. Wenn es emuliert wird, ist es intern. Bei neueren Geräten, die über einen internen Speicher und einen SD-Kartensteckplatz verfügen, gibt Environment.getExternalStorageDirectory () immer den internen Speicher zurück. Bei älteren Geräten, die nur eine SD-Karte als Medienspeicheroption haben, wird die SD-Karte immer zurückgegeben.

Es ist nicht möglich, alle Speicher mit der aktuellen Android-API abzurufen.

In der folgenden Antwort habe ich einen Helfer erstellt, der auf der Methode von Vitaliy Polchuk basiert

Wie bekomme ich die Liste der eingebauten externen Speicher des Android-Geräts

HINWEIS: Das Starten des sekundären KitKat-Speichers ist nur über READ-ONLY zugänglich. Sie können die Schreibbarkeit mithilfe der folgenden Methode überprüfen

/**
 * Checks whether the StorageVolume is read-only
 * 
 * @param volume
 *            StorageVolume to check
 * @return true, if volume is mounted read-only
 */
public static boolean isReadOnly(@NonNull final StorageVolume volume) {
    if (volume.mFile.equals(Environment.getExternalStorageDirectory())) {
        // is a primary storage, check mounted state by Environment
        return Android.os.Environment.getExternalStorageState().equals(
                Android.os.Environment.MEDIA_MOUNTED_READ_ONLY);
    } else {
        if (volume.getType() == Type.USB) {
            return volume.isReadOnly();
        }
        //is not a USB storagem so it's read-only if it's mounted read-only or if it's a KitKat device
        return volume.isReadOnly() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat;
    }
}

StorageHelper-Klasse

import Java.io.BufferedReader;
import Java.io.File;
import Java.io.FileNotFoundException;
import Java.io.FileReader;
import Java.io.IOException;
import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;
import Java.util.Map.Entry;
import Java.util.StringTokenizer;

import Android.os.Environment;

public final class StorageHelper {

    //private static final String TAG = "StorageHelper";

    private StorageHelper() {
    }

    private static final String STORAGES_ROOT;

    static {
        final String primaryStoragePath = Environment.getExternalStorageDirectory()
                .getAbsolutePath();
        final int index = primaryStoragePath.indexOf(File.separatorChar, 1);
        if (index != -1) {
            STORAGES_ROOT = primaryStoragePath.substring(0, index + 1);
        } else {
            STORAGES_ROOT = File.separator;
        }
    }

    private static final String[] AVOIDED_DEVICES = new String[] {
        "rootfs", "tmpfs", "dvpts", "proc", "sysfs", "none"
    };

    private static final String[] AVOIDED_DIRECTORIES = new String[] {
        "obb", "asec"
    };

    private static final String[] DISALLOWED_FILESYSTEMS = new String[] {
        "tmpfs", "rootfs", "romfs", "devpts", "sysfs", "proc", "cgroup", "debugfs"
    };

    /**
     * Returns a list of mounted {@link StorageVolume}s Returned list always
     * includes a {@link StorageVolume} for
     * {@link Environment#getExternalStorageDirectory()}
     * 
     * @param includeUsb
     *            if true, will include USB storages
     * @return list of mounted {@link StorageVolume}s
     */
    public static List<StorageVolume> getStorages(final boolean includeUsb) {
        final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>();

        // this approach considers that all storages are mounted in the same non-root directory
        if (!STORAGES_ROOT.equals(File.separator)) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader("/proc/mounts"));
                String line;
                while ((line = reader.readLine()) != null) {
                    // Log.d(TAG, line);
                    final StringTokenizer tokens = new StringTokenizer(line, " ");

                    final String device = tokens.nextToken();
                    // skipped devices that are not sdcard for sure
                    if (arrayContains(AVOIDED_DEVICES, device)) {
                        continue;
                    }

                    // should be mounted in the same directory to which
                    // the primary external storage was mounted
                    final String path = tokens.nextToken();
                    if (!path.startsWith(STORAGES_ROOT)) {
                        continue;
                    }

                    // skip directories that indicate tha volume is not a storage volume
                    if (pathContainsDir(path, AVOIDED_DIRECTORIES)) {
                        continue;
                    }

                    final String fileSystem = tokens.nextToken();
                    // don't add ones with non-supported filesystems
                    if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) {
                        continue;
                    }

                    final File file = new File(path);
                    // skip volumes that are not accessible
                    if (!file.canRead() || !file.canExecute()) {
                        continue;
                    }

                    List<StorageVolume> volumes = deviceVolumeMap.get(device);
                    if (volumes == null) {
                        volumes = new ArrayList<StorageVolume>(3);
                        deviceVolumeMap.put(device, volumes);
                    }

                    final StorageVolume volume = new StorageVolume(device, file, fileSystem);
                    final StringTokenizer flags = new StringTokenizer(tokens.nextToken(), ",");
                    while (flags.hasMoreTokens()) {
                        final String token = flags.nextToken();
                        if (token.equals("rw")) {
                            volume.mReadOnly = false;
                            break;
                        } else if (token.equals("ro")) {
                            volume.mReadOnly = true;
                            break;
                        }
                    }
                    volumes.add(volume);
                }

            } catch (IOException ex) {
                ex.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ex) {
                        // ignored
                    }
                }
            }
        }

        // remove volumes that are the same devices
        boolean primaryStorageIncluded = false;
        final File externalStorage = Environment.getExternalStorageDirectory();
        final List<StorageVolume> volumeList = new ArrayList<StorageVolume>();
        for (final Entry<String, List<StorageVolume>> entry : deviceVolumeMap.entrySet()) {
            final List<StorageVolume> volumes = entry.getValue();
            if (volumes.size() == 1) {
                // go ahead and add
                final StorageVolume v = volumes.get(0);
                final boolean isPrimaryStorage = v.file.equals(externalStorage);
                primaryStorageIncluded |= isPrimaryStorage;
                setTypeAndAdd(volumeList, v, includeUsb, isPrimaryStorage);
                continue;
            }
            final int volumesLength = volumes.size();
            for (int i = 0; i < volumesLength; i++) {
                final StorageVolume v = volumes.get(i);
                if (v.file.equals(externalStorage)) {
                    primaryStorageIncluded = true;
                    // add as external storage and continue
                    setTypeAndAdd(volumeList, v, includeUsb, true);
                    break;
                }
                // if that was the last one and it's not the default external
                // storage then add it as is
                if (i == volumesLength - 1) {
                    setTypeAndAdd(volumeList, v, includeUsb, false);
                }
            }
        }
        // add primary storage if it was not found
        if (!primaryStorageIncluded) {
            final StorageVolume defaultExternalStorage = new StorageVolume("", externalStorage, "UNKNOWN");
            defaultExternalStorage.mEmulated = Environment.isExternalStorageEmulated();
            defaultExternalStorage.mType =
                    defaultExternalStorage.mEmulated ? StorageVolume.Type.INTERNAL
                            : StorageVolume.Type.EXTERNAL;
            defaultExternalStorage.mRemovable = Environment.isExternalStorageRemovable();
            defaultExternalStorage.mReadOnly =
                    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
            volumeList.add(0, defaultExternalStorage);
        }
        return volumeList;
    }

    /**
     * Sets {@link StorageVolume.Type}, removable and emulated flags and adds to
     * volumeList
     * 
     * @param volumeList
     *            List to add volume to
     * @param v
     *            volume to add to list
     * @param includeUsb
     *            if false, volume with type {@link StorageVolume.Type#USB} will
     *            not be added
     * @param asFirstItem
     *            if true, adds the volume at the beginning of the volumeList
     */
    private static void setTypeAndAdd(final List<StorageVolume> volumeList,
            final StorageVolume v,
            final boolean includeUsb,
            final boolean asFirstItem) {
        final StorageVolume.Type type = resolveType(v);
        if (includeUsb || type != StorageVolume.Type.USB) {
            v.mType = type;
            if (v.file.equals(Environment.getExternalStorageDirectory())) {
                v.mRemovable = Environment.isExternalStorageRemovable();
            } else {
                v.mRemovable = type != StorageVolume.Type.INTERNAL;
            }
            v.mEmulated = type == StorageVolume.Type.INTERNAL;
            if (asFirstItem) {
                volumeList.add(0, v);
            } else {
                volumeList.add(v);
            }
        }
    }

    /**
     * Resolved {@link StorageVolume} type
     * 
     * @param v
     *            {@link StorageVolume} to resolve type for
     * @return {@link StorageVolume} type
     */
    private static StorageVolume.Type resolveType(final StorageVolume v) {
        if (v.file.equals(Environment.getExternalStorageDirectory())
                && Environment.isExternalStorageEmulated()) {
            return StorageVolume.Type.INTERNAL;
        } else if (containsIgnoreCase(v.file.getAbsolutePath(), "usb")) {
            return StorageVolume.Type.USB;
        } else {
            return StorageVolume.Type.EXTERNAL;
        }
    }

    /**
     * Checks whether the array contains object
     * 
     * @param array
     *            Array to check
     * @param object
     *            Object to find
     * @return true, if the given array contains the object
     */
    private static <T> boolean arrayContains(T[] array, T object) {
        for (final T item : array) {
            if (item.equals(object)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether the path contains one of the directories
     * 
     * For example, if path is /one/two, it returns true input is "one" or
     * "two". Will return false if the input is one of "one/two", "/one" or
     * "/two"
     * 
     * @param path
     *            path to check for a directory
     * @param dirs
     *            directories to find
     * @return true, if the path contains one of the directories
     */
    private static boolean pathContainsDir(final String path, final String[] dirs) {
        final StringTokenizer tokens = new StringTokenizer(path, File.separator);
        while (tokens.hasMoreElements()) {
            final String next = tokens.nextToken();
            for (final String dir : dirs) {
                if (next.equals(dir)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Checks ifString contains a search String irrespective of case, handling.
     * Case-insensitivity is defined as by
     * {@link String#equalsIgnoreCase(String)}.
     * 
     * @param str
     *            the String to check, may be null
     * @param searchStr
     *            the String to find, may be null
     * @return true if the String contains the search String irrespective of
     *         case or false if not or {@code null} string input
     */
    public static boolean containsIgnoreCase(final String str, final String searchStr) {
        if (str == null || searchStr == null) {
            return false;
        }
        final int len = searchStr.length();
        final int max = str.length() - len;
        for (int i = 0; i <= max; i++) {
            if (str.regionMatches(true, i, searchStr, 0, len)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Represents storage volume information
     */
    public static final class StorageVolume {

        /**
         * Represents {@link StorageVolume} type
         */
        public enum Type {
            /**
             * Device built-in internal storage. Probably points to
             * {@link Environment#getExternalStorageDirectory()}
             */
            INTERNAL,

            /**
             * External storage. Probably removable, if no other
             * {@link StorageVolume} of type {@link #INTERNAL} is returned by
             * {@link StorageHelper#getStorages(boolean)}, this might be
             * pointing to {@link Environment#getExternalStorageDirectory()}
             */
            EXTERNAL,

            /**
             * Removable usb storage
             */
            USB
        }

        /**
         * Device name
         */
        public final String device;

        /**
         * Points to mount point of this device
         */
        public final File file;

        /**
         * File system of this device
         */
        public final String fileSystem;

        /**
         * if true, the storage is mounted as read-only
         */
        private boolean mReadOnly;

        /**
         * If true, the storage is removable
         */
        private boolean mRemovable;

        /**
         * If true, the storage is emulated
         */
        private boolean mEmulated;

        /**
         * Type of this storage
         */
        private Type mType;

        StorageVolume(String device, File file, String fileSystem) {
            this.device = device;
            this.file = file;
            this.fileSystem = fileSystem;
        }

        /**
         * Returns type of this storage
         * 
         * @return Type of this storage
         */
        public Type getType() {
            return mType;
        }

        /**
         * Returns true if this storage is removable
         * 
         * @return true if this storage is removable
         */
        public boolean isRemovable() {
            return mRemovable;
        }

        /**
         * Returns true if this storage is emulated
         * 
         * @return true if this storage is emulated
         */
        public boolean isEmulated() {
            return mEmulated;
        }

        /**
         * Returns true if this storage is mounted as read-only
         * 
         * @return true if this storage is mounted as read-only
         */
        public boolean isReadOnly() {
            return mReadOnly;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((file == null) ? 0 : file.hashCode());
            return result;
        }

        /**
         * Returns true if the other object is StorageHelper and it's
         * {@link #file} matches this one's
         * 
         * @see Object#equals(Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final StorageVolume other = (StorageVolume) obj;
            if (file == null) {
                return other.file == null;
            }
            return file.equals(other.file);
        }

        @Override
        public String toString() {
            return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "")
                    + (mEmulated ? " E " : "") + fileSystem;
        }
    }
}
18

ich hoffe es funktioniert für Sie:

File yourFile = new File(Environment.getExternalStorageDirectory(), "textarabics.txt");

Dies gibt den folgenden Pfad an:

File path = Environment.getExternalStorageDirectory();

Versuche dies:

String pathName = "/mnt/";

oder probiere es aus:

String pathName = "/storage/";
4
Farhan Shah

rijul gupta antwort:

String strSDCardPath = System.getenv("SECONDARY_STORAGE");

    if ((strSDCardPath == null) || (strSDCardPath.length() == 0)) {
        strSDCardPath = System.getenv("EXTERNAL_SDCARD_STORAGE");
    }

    //If may get a full path that is not the right one, even if we don't have the SD Card there. 
    //We just need the "/mnt/extSdCard/" i.e and check if it's writable
    if(strSDCardPath != null) {
        if (strSDCardPath.contains(":")) {
            strSDCardPath = strSDCardPath.substring(0, strSDCardPath.indexOf(":"));
        }
        File externalFilePath = new File(strSDCardPath);

        if (externalFilePath.exists() && externalFilePath.canWrite()){
            //do what you need here
        }
    }
3
Alexandre

wenn Sie die Antwort von @ rijul vorantreiben, funktioniert es in Marshmallow und den obigen Versionen nicht:

       //for pre-Marshmallow versions
       String path = System.getenv("SECONDARY_STORAGE");

       // For Marshmallow, use getExternalCacheDirs() instead of System.getenv("SECONDARY_STORAGE")
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
           File[] externalCacheDirs = mContext.getExternalCacheDirs();
           for (File file : externalCacheDirs) {
               if (Environment.isExternalStorageRemovable(file)) {
                   // Path is in format /storage.../Android....
                   // Get everything before /Android
                   path = file.getPath().split("/Android")[0];
                   break;
               }
           }
       }


        // Android avd emulator doesn't support this variable name so using other one
        if ((null == path) || (path.length() == 0))
            path = Environment.getExternalStorageDirectory().getAbsolutePath();
2
Shubham

Ich möchte den Pfad des externen Speicherverzeichnisses zum Speichern der Datei öffnen Ich habe es versucht, aber ich bekomme keinen SD-Pfad. Wie kann ich Gibt es eine Lösung dafür?

Um Ihre App-Dateien auf der SD-Karte zu speichern, verwenden Sie die sollteFile[] getExternalFilesDirs (String type)-Methode in der Context-Klasse. Im Allgemeinen wäre der zweite zurückgegebene Pfad der Speicherpfad für die microSD-Karte (falls vorhanden).

Auf meinem Telefon war der zweite zurückgegebene Pfad /storage/sdcard1/Android/data/your.application.package.appname/files, nachdem null als Argument an getExternalFilesDirs (String type) übergeben wurde. Der Pfad kann jedoch auf verschiedenen Handys und verschiedenen Android-Versionen variieren.

Sowohl File getExternalStorageDirectory () als auch File getExternalStoragePublicDirectory (String type) in der Klasse Environment können abhängig von Ihrem Telefonmodell und der Version des Android-Betriebssystems das SD-Kartenverzeichnis oder das interne Speicherverzeichnis zurückgeben. 

Denn laut Offizielle Android-Anleitung externer Speicher kann es sein

wechselmedien (z. B. eine SD-Karte) oder ein internes (nicht entfernbarer) Speicher.

Die Terminologie des internen und externen Speichers laut Google/offiziellen Android-Dokumenten ist ziemlich verschieden von dem, was wir denken. 

0
AnV

ja, es kann in KitKat funktionieren.

über KitKat + geht es in den internen Speicher: Pfade wie (Speicher/emuliert/0).

bitte denken Sie darüber nach, wie "Xender App" die Erlaubnis zum Schreiben auf eine externe SD-Karte erteilt.

Glücklicherweise gibt es in Android 5.0 und später eine neue offizielle Methode, mit der Apps auf die externe SD-Karte geschrieben werden können. Apps müssen den Benutzer auffordern, Schreibzugriff auf einen Ordner auf der SD-Karte zu gewähren. Sie öffnen einen Systemordner-Auswahldialog. Der Benutzer muss in diesen bestimmten Ordner navigieren und ihn auswählen.

weitere Informationen finden Sie unter https://metactrl.com/docs/sdcard-on-Lollipop/

0
Muhammed Haris