In meiner Anwendung muss ich viele Bilder im Gerätespeicher speichern. Solche Dateien erfüllen in der Regel den Gerätespeicher, und ich möchte Benutzern die Möglichkeit geben, eine externe SD-Karte als Zielordner auszuwählen.
Ich habe überall gelesen, dass Android es Benutzern nicht erlaubt, auf eine externe SD-Karte zu schreiben. Mit SD-Karte meine ich die externe und montierbare SD-Karte und nicht den externen Speicher , aber Dateimanager-Anwendungen können auf allen Android-Versionen auf externe SD schreiben.
Was ist der bessere Weg, um Lese- / Schreibzugriff auf externe SD-Karten auf verschiedenen API-Ebenen (Pre-KitKat, KitKat, Lollipop +) zu gewähren?
Update 1
Ich habe Methode 1 aus Doomknights Antwort ohne Erfolg ausprobiert: Wie Sie sehen, überprüfe ich zur Laufzeit die Berechtigungen, bevor ich versuche, auf SD zu schreiben:
HashSet<String> extDirs = getStorageDirectories();
for(String dir: extDirs) {
Log.e("SD",dir);
File f = new File(new File(dir),"TEST.TXT");
try {
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED) {
f.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Ich erhalte jedoch einen Zugriffsfehler, der auf zwei verschiedenen Geräten versucht wurde: HTC10 und Shield K1.
10-22 14:52:57.329 30280-30280/? E/SD: /mnt/media_rw/F38E-14F8
10-22 14:52:57.329 30280-30280/? W/System.err: java.io.IOException: open failed: EACCES (Permission denied)
10-22 14:52:57.329 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:939)
10-22 14:52:57.329 30280-30280/? W/System.err: at com.myapp.activities.TestActivity.onResume(TestActivity.java:167)
10-22 14:52:57.329 30280-30280/? W/System.err: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1326)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.Activity.performResume(Activity.java:6338)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3336)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3384)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2574)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.access$900(ActivityThread.java:150)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1399)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Looper.loop(Looper.java:168)
10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5885)
10-22 14:52:57.330 30280-30280/? W/System.err: at java.lang.reflect.Method.invoke(Native Method)
10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:819)
10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:709)
10-22 14:52:57.330 30280-30280/? W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.Posix.open(Native Method)
10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
10-22 14:52:57.330 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:932)
10-22 14:52:57.330 30280-30280/? W/System.err: ... 14 more
Antworten:
Zusammenfassung
Sie können Lese- / Schreibzugriff auf externe SD-Karten auf den verschiedenen API-Ebenen ( API23 + zur Laufzeit ) gewähren .
Da KitKat, sind Berechtigungen nicht erforderlich , wenn Sie app-spezifische Verzeichnisse verwenden, erforderlich anders.
Universeller Weg:
Die Geschichte besagt, dass es keine universelle Möglichkeit gibt, auf eine externe SD-Karte zu schreiben, sondern dass ...
Diese Tatsache wird durch diese Beispiele für externe Speicherkonfigurationen für Geräte demonstriert .
API-basierter Weg:
Vor KitKat versuchen zu verwenden Doomsknight Methode 1, Methode 2 anders.
Fordern Sie Berechtigungen im Manifest (Api <23) und zur Laufzeit (Api> = 23) an.
Empfohlener Weg:
ContextCompat.getExternalFilesDirs löst den Zugriffsfehler, wenn Sie keine Dateien freigeben müssen.
Die sichere Möglichkeit zur Freigabe besteht darin, einen Inhaltsanbieter oder das neue Storage Access Framework zu verwenden .
Datenschutzbewusster Weg:
Ab Android Q Beta 4 werden Apps, die auf Android 9 (API-Stufe 28) oder niedriger abzielen, standardmäßig nicht geändert.
Apps, die standardmäßig auf Android Q abzielen (oder sich dafür entscheiden), erhalten eine gefilterte Ansicht in den externen Speicher.
1. Erste Antwort.
Aufgrund ständiger Änderungen gibt es unter Android keine universelle Möglichkeit , auf eine externe SD-Karte zu schreiben :
Pre-KitKat: Die offizielle Android-Plattform unterstützt SD-Karten bis auf Ausnahmen überhaupt nicht.
KitKat: Einführung von APIs, mit denen Apps auf Dateien in app-spezifischen Verzeichnissen auf SD-Karten zugreifen können.
Lollipop: APIs hinzugefügt, mit denen Apps den Zugriff auf Ordner anderer Anbieter anfordern können.
Nougat: Bereitstellung einer vereinfachten API für den Zugriff auf allgemeine externe Speicherverzeichnisse.
... Änderung des Datenschutzes für Android Q: Speicher mit App- und Medienbereich
Basierend auf der Antwort von Doomsknight und meiner sowie den Blog-Posts von Dave Smith und Mark Murphy: 1 , 2 , 3 :
/storage/extSdCard/Android/data/com.myapp.example/files
.2. Aktualisierte Antwort.
Ich würde anwendungsspezifische Verzeichnisse verwenden , um das Problem Ihrer aktualisierten Frage zu vermeiden und
ContextCompat.getExternalFilesDirs()
die Dokumentation von getExternalFilesDir als Referenz zu verwenden.Verbessern Sie die Heuristik , um zu bestimmen, was Wechselmedien darstellt, basierend auf den verschiedenen API-Ebenen wie
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
Denken Sie daran, dass Android 6.0 tragbare Speichergeräte unterstützt und Apps von Drittanbietern das Storage Access Framework durchlaufen müssen . Ihre Geräte HTC10 und Shield K1 sind wahrscheinlich API 23.
In Ihrem Protokoll wird eine Berechtigung angezeigt, der der Zugriff auf Ausnahmen verweigert wurde
/mnt/media_rw
, wie dieser Fix für API 19+:<permission name="android.permission.WRITE_EXTERNAL_STORAGE" > <group gid="sdcard_r" /> <group gid="sdcard_rw" /> <group gid="media_rw" /> // this line is added via root in the link to fix it. </permission>
Ich habe es nie versucht, damit ich keinen Code freigeben kann, aber ich würde den
for
Versuch vermeiden , in alle zurückgegebenen Verzeichnisse zu schreiben, und nach dem besten verfügbaren Speicherverzeichnis suchen , in das basierend auf dem verbleibenden Speicherplatz geschrieben werden kann .Vielleicht ist die Alternative von Gizm0 zu Ihrer
getStorageDirectories()
Methode ein guter Ausgangspunkt.ContextCompat.getExternalFilesDirs
Behebt das Problem, wenn Sie keinen Zugriff auf andere Ordner benötigen .3. Android 1.0 .. Pre-KitKat.
Versuchen Sie vor KitKat, Doomsknight-Methode 1 zu verwenden, oder lesen Sie diese Antwort von Gnathonic.
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; }
Fügen Sie den nächsten Code zu Ihrem hinzu
AndroidManifest.xml
und lesen Sie Zugriff auf externen Speicher erhaltenLesen Sie die Erklärung von Mark Murphy und empfehlen Sie die Beiträge von Dianne Hackborn und Dave Smith
4. Android 4.4 KitKat führt das Storage Access Framework (SAF) ein .
Ignorieren Sie die nächste Notiz aufgrund von Fehlern, aber versuchen Sie Folgendes zu verwenden
ContextCompat.getExternalFilesDirs()
:Lesen Sie auch die Erklärung von Paolo Rovelli und versuchen Sie, Jeff Sharkeys Lösung seit KitKat zu verwenden:
Mit KitKat sind Ihre Chancen auf eine "Komplettlösung" ohne Rooting so gut wie null:
5. Android 5.0 führte Änderungen und die DocumentFile- Hilfsklasse ein.
getStorageState
In API 19 hinzugefügt, in API 21 veraltet, verwendengetExternalStorageState(File)
6. Android 6.0 Marshmallow führt ein neues Laufzeitberechtigungsmodell ein.
Fordern Sie zur Laufzeit Berechtigungen ab API-Stufe 23+ an und lesen Sie Anfordern von Berechtigungen zur Laufzeit
7. Android 7.0 bietet eine vereinfachte API für den Zugriff auf externe Speicherverzeichnisse.
Lesen Sie die Beiträge von Mark Murphy: Seien Sie vorsichtig mit dem Zugriff auf das Bereichsverzeichnis . Es wurde in Android Q veraltet :
8. Android 8.0 Oreo .. Änderungen an Android Q Beta.
Update: Eine frühere Beta-Version von Android Q hat die Berechtigungen
READ_EXTERNAL_STORAGE
und vorübergehend durchWRITE_EXTERNAL_STORAGE
detailliertere, medienspezifische Berechtigungen ersetzt.Hinweis: Google hat Rollen in Beta 1 eingeführt und diese vor Beta 2 aus der Dokumentation entfernt ...
Hinweis: Die Berechtigungen für Mediensammlungen, die in früheren Betaversionen
READ_MEDIA_IMAGES
-READ_MEDIA_AUDIO
, undREAD_MEDIA_VIDEO
- eingeführt wurden, sind jetzt veraltet . Mehr Info:Q Beta 4 (endgültige APIs) von Mark Murphy: Der Tod des externen Speichers: Das Ende der Saga (?)
9. Verwandte Fragen und empfohlene Antworten.
Wie kann ich einen externen SD-Kartenpfad für Android 4.0+ erhalten?
mkdir () funktioniert im internen Flash-Speicher, aber nicht auf der SD-Karte?
Unterschied zwischen getExternalFilesDir und getExternalStorageDirectory ()
Warum funktioniert getExternalFilesDirs () auf einigen Geräten nicht?
Verwendung der neuen SD-Kartenzugriffs-API für Android 5.0 (Lollipop)
Schreiben auf eine externe SD-Karte in Android 5.0 und höher
Schreibberechtigung für Android SD-Karten mit SAF (Storage Access Framework)
SAFFAQ: Die häufig gestellten Fragen zum Storage Access Framework
10. Verwandte Fehler und Probleme.
Fehler: Unter Android 6 können Sie bei Verwendung von getExternalFilesDirs keine neuen Dateien in den Ergebnissen erstellen
Das Schreiben in das von getExternalCacheDir () auf Lollipop zurückgegebene Verzeichnis schlägt ohne Schreibberechtigung fehl
quelle
Ich glaube, es gibt zwei Methoden, um dies zu erreichen:
METHODE 1: (funktioniert aufgrund von Berechtigungsänderungen NICHT unter 6.0 und höher)
Ich verwende diese Methode seit Jahren auf vielen Geräteversionen ohne Probleme. Der Kredit ist auf die ursprüngliche Quelle zurückzuführen, da nicht ich es geschrieben habe.
Es wird wieder alle montierten Medien (einschließlich Echt SD - Karten) in einer Liste von Strings Verzeichnissen. Mit der Liste können Sie den Benutzer dann fragen, wo er speichern soll usw.
Sie können es wie folgt aufrufen:
Methode:
/** * Returns all the possible SDCard directories */ public static HashSet<String> getStorageDirectories() { 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().contains("asec")) { if (line.matches(reg)) { String[] parts = line.split(" "); for (String part : parts) { if (part.startsWith("/")) if (!part.toLowerCase().contains("vold")) out.add(part); } } } } return out; }
Methode 2:
Verwenden Sie die v4-Unterstützungsbibliothek
import android.support.v4.content.ContextCompat;
Rufen Sie einfach Folgendes an, um eine Liste
File
der Speicherorte zu erhalten.File[] list = ContextCompat.getExternalFilesDirs(myContext, null);
Die Standorte unterscheiden sich jedoch in der Nutzung.
Weitere Informationen zu ContextCompat
Sie sind wie app-spezifische Dateien. Versteckt vor anderen Apps.
quelle
Nur eine andere Antwort. Diese Antwort zeigt nur 5.0+, da ich glaube, dass die hier veröffentlichte Antwort von Doomknight der beste Weg für Android 4.4 und niedriger ist.
Dies wurde ursprünglich hier ( Gibt es eine Möglichkeit, die SD-Kartengröße in Android zu ermitteln? ) Von mir veröffentlicht, um die Größe der externen SD-Karte in Android 5.0+ zu ermitteln
So erhalten Sie die externe SD-Karte als
File
:public File getExternalSdCard() { File externalStorage = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { File storage = new File("/storage"); if(storage.exists()) { File[] files = storage.listFiles(); for (File file : files) { if (file.exists()) { try { if (Environment.isExternalStorageRemovable(file)) { externalStorage = file; break; } } catch (Exception e) { Log.e("TAG", e.toString()); } } } } } else { // do one of many old methods // I believe Doomsknight's method is the best option here } return externalStorage; }
Hinweis: Ich erhalte nur die "erste" externe SD-Karte. Sie können sie jedoch ändern und
ArrayList<File>
stattdessen zurückkehrenFile
und die Schleife fortsetzen, anstatt zu rufen,break
nachdem die erste gefunden wurde.quelle
isExternalStorageRemovable
Referenz developer.android.com/reference/android/os/…isExternalStorageRemovable
Ist es nur für> = 21 möglich, festzustellen, ob der Speicher auf <= 19 API-Geräten entfernbar ist (Microsd-Karte), und eine ähnliche Methode zu implementieren?Zusätzlich zu allen anderen netten Antworten könnte ich dieser Frage etwas mehr hinzufügen, damit sie den Lesern eine breitere Berichterstattung bietet. In meiner Antwort hier würde ich 2 zählbare Ressourcen verwenden, um externen Speicher darzustellen.
Die erste Ressource stammt aus der Android-Programmierung, 2. Ausgabe des Big Nerd Ranch Guide , Kapitel 16, Seite 294.
Das Buch beschreibt die grundlegenden und externen Datei- und Verzeichnismethoden. Ich werde versuchen, einen Lebenslauf darüber zu erstellen, was für Ihre Frage relevant sein könnte.
Der folgende Teil aus dem Buch:
Externer Speicher
Ihr Foto benötigt mehr als einen Platz auf dem Bildschirm. Bilder in voller Größe sind zu groß, um in einer SQLite-Datenbank gespeichert zu werden, geschweige denn
Intent
. Sie benötigen einen Platz im Dateisystem Ihres Geräts. Normalerweise würden Sie sie in Ihrem privaten Speicher ablegen. Denken Sie daran, dass Sie Ihren privaten Speicher zum Speichern Ihrer SQLite-Datenbank verwendet haben. Mit Methoden wieContext.getFileStreamPath(String)
undContext.getFilesDir()
können Sie dasselbe auch mit regulären Dateien tun (die sich in einem Unterordner neben dem Datenbankunterordner befinden, in dem sich Ihre SQLite-Datenbank befindet).Grundlegende Datei- und Verzeichnismethoden im Kontext
| Method | |---------------------------------------------------------------------------------------| |File getFilesDir() | | - Returns a handle to the directory for private application files. | | | |FileInputStream openFileInput(String name) | | - Opens an existing file for input (relative to the files directory). | | | |FileOutputStream openFileOutput(String name, int mode) | | - Opens a file for output, possibly creating it (relative to the files directory). | | | |File getDir(String name, int mode) | | - Gets (and possibly creates) a subdirectory within the files directory. | | | |String[] fileList() | | - Gets a list of file names in the main files directory, such as for use with | | openFileInput(String). | | | |File getCacheDir() | | - Returns a handle to a directory you can use specifically for storing cache files. | | You should take care to keep this directory tidy and use as little space as possible|
Wenn Sie Dateien speichern, die nur Ihre aktuelle Anwendung verwenden muss, sind diese Methoden genau das, was Sie benötigen.
Wenn Sie jedoch eine andere Anwendung zum Schreiben in diese Dateien benötigen, haben Sie kein Glück: Obwohl es ein
Context.MODE_WORLD_READABLE
Flag gibt, an das Sie übergeben könnenopenFileOutput(String, int)
, ist es veraltet und in seinen Auswirkungen auf neuere Geräte nicht vollständig zuverlässig. Wenn Sie Dateien speichern, um sie mit anderen Apps zu teilen, oder Dateien von anderen Apps empfangen (Dateien wie gespeicherte Bilder), müssen Sie sie stattdessen auf einem externen Speicher speichern.Es gibt zwei Arten von externem Speicher: Primärspeicher und alles andere. Alle Android-Geräte verfügen über mindestens einen Speicherort für externen Speicher: den primären Speicherort, der sich in dem von zurückgegebenen Ordner befindet
Environment.getExternalStorageDirectory()
. Dies mag eine SD-Karte sein, aber heutzutage wird sie häufiger in das Gerät selbst integriert. Einige Geräte verfügen möglicherweise über zusätzlichen externen Speicher. Das würde unter "alles andere" fallen.Der Kontext bietet auch einige Methoden, um auf externen Speicher zuzugreifen. Diese Methoden bieten einfache Möglichkeiten, um an Ihren primären externen Speicher zu gelangen, und irgendwie einfache Möglichkeiten, um an alles andere zu gelangen. Alle diese Methoden speichern Dateien auch an öffentlich zugänglichen Orten. Seien Sie also vorsichtig mit ihnen.
Externe Datei- und Verzeichnismethoden im Kontext
| Method | | --------------------------------------------------------------------------------------| |File getExternalCacheDir() | | - Returns a handle to a cache folder in primary external storage. Treat it like you do| | getCacheDir(), except a little more carefully. Android is even less likely to clean | | up this folder than the private storage one. | | | |File[] getExternalCacheDirs() | | - Returns cache folders for multiple external storage locations. | | | |File getExternalFilesDir(String) | | - Returns a handle to a folder on primary external storage in which to store regular | | files. If you pass in a type String, you can access a specific subfolder dedicated | | to a particular type of content. Type constants are defined in Environment, where | | they are prefixed with DIRECTORY_. | | For example, pictures go in Environment.DIRECTORY_PICTURES. | | | |File[] getExternalFilesDirs(String) | | - Same as getExternalFilesDir(String), but returns all possible file folders for the | | given type. | | | |File[] getExternalMediaDirs() | | - Returns handles to all the external folders Android makes available for storing | | media – pictures, movies, and music. What makes this different from calling | | getExternalFilesDir(Environment.DIRECTORY_PICTURES) is that the media scanner | | automatically scans this folder. The media scanner makes files available to | | applications that play music, or browse movies and photos, so anything that you | | put in a folder returned by getExternalMediaDirs() will automatically appear in | | those apps. |
Technisch gesehen sind die oben angegebenen externen Ordner möglicherweise nicht verfügbar, da einige Geräte eine austauschbare SD-Karte für die externe Speicherung verwenden. In der Praxis ist dies selten ein Problem, da fast alle modernen Geräte einen nicht entfernbaren internen Speicher für ihren „externen“ Speicher haben. Es lohnt sich also nicht, extreme Anstrengungen zu unternehmen, um dies zu erklären. Wir empfehlen jedoch, einfachen Code einzuschließen, um die Möglichkeit zu vermeiden, die Sie in Kürze ausführen werden.
Externe Speicherberechtigung
Im Allgemeinen benötigen Sie eine Berechtigung zum Schreiben oder Lesen aus einem externen Speicher. Berechtigungen sind bekannte Zeichenfolgenwerte, die Sie mithilfe des
<uses-permission>
Tags in Ihr Manifest einfügen. Sie teilen Android mit, dass Sie etwas tun möchten, für das Android Sie um Erlaubnis bitten soll.Hier erwartet Android, dass Sie um Erlaubnis bitten, weil es eine gewisse Rechenschaftspflicht erzwingen möchte. Sie teilen Android mit, dass Sie auf externen Speicher zugreifen müssen, und Android teilt dem Benutzer dann mit, dass dies eines der Dinge ist, die Ihre Anwendung tut, wenn sie versucht, es zu installieren. Auf diese Weise ist niemand überrascht, wenn Sie anfangen, Dinge auf seiner SD-Karte zu speichern.
In Android 4.4, KitKat, wurde diese Einschränkung gelockert. Da
Context.getExternalFilesDir(String)
ein Ordner zurückgegeben wird, der für Ihre App spezifisch ist, ist es sinnvoll, dass Sie in der Lage sein möchten, dort lebende Dateien zu lesen und zu schreiben. Unter Android 4.4 (API 19) und höher benötigen Sie diese Berechtigung für diesen Ordner nicht. (Aber Sie brauchen es immer noch für andere Arten von externem Speicher.)Fügen Sie Ihrem Manifest eine Zeile hinzu, die die Berechtigung zum Lesen des externen Speichers anfordert, jedoch nur bis zu API Listing 16.5: Anfordern der Berechtigung zum externen Speicher (
AndroidManifest.xml
)<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bignerdranch.android.criminalintent" > <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
Das Attribut maxSdkVersion bewirkt, dass Ihre App diese Berechtigung nur für Versionen von Android anfordert, die älter als API 19, Android KitKat, sind. Beachten Sie, dass Sie nur den externen Speicher lesen möchten. Es gibt auch eine
WRITE_EXTERNAL_STORAGE
Erlaubnis, aber Sie brauchen sie nicht. Sie werden nichts in den externen Speicher schreiben: Die Kamera-App erledigt das für SieDie zweite Ressource ist, dass dieser Link alles liest. Sie können jedoch auch zum Abschnitt Verwenden des externen Speichers springen .
Referenz:
Weitere Lektüre:
quelle
Dieses Thema ist etwas alt, aber ich suchte nach einer Lösung und kam nach einigen Recherchen mit dem folgenden Code, um eine Liste der verfügbaren "externen" Einhängepunkte abzurufen, die meines Wissens auf vielen verschiedenen Geräten funktionieren.
Grundsätzlich liest es verfügbare Einhängepunkte, filtert ungültige heraus, testet den Rest, wenn sie zugänglich sind, und fügt sie hinzu, wenn alle Bedingungen erfüllt sind.
Natürlich müssen die erforderlichen Berechtigungen erteilt werden, bevor der Code aufgerufen wird.
// Notice: FileSystemDevice is just my own wrapper class. Feel free to replace it with your own. private List<FileSystemDevice> getDevices() { List<FileSystemDevice> devices = new ArrayList<>(); // Add default external storage if available. File sdCardFromSystem = null; switch(Environment.getExternalStorageState()) { case Environment.MEDIA_MOUNTED: case Environment.MEDIA_MOUNTED_READ_ONLY: case Environment.MEDIA_SHARED: sdCardFromSystem = Environment.getExternalStorageDirectory(); break; } if (sdCardFromSystem != null) { devices.add(new FileSystemDevice(sdCardFromSystem)); } // Read /proc/mounts and add all mount points that are available // and are not "special". Also, check if the default external storage // is not contained inside the mount point. try { FileInputStream fs = new FileInputStream("/proc/mounts"); String mounts = IOUtils.toString(fs, "UTF-8"); for(String line : mounts.split("\n")) { String[] parts = line.split(" "); // parts[0] - mount type // parts[1] - mount point if (parts.length > 1) { try { // Skip "special" mount points and mount points that can be accessed // directly by Android's functions. if (parts[0].equals("proc")) { continue; } if (parts[0].equals("rootfs")) { continue; } if (parts[0].equals("devpts")) { continue; } if (parts[0].equals("none")) { continue; } if (parts[0].equals("sysfs")) { continue; } if (parts[0].equals("selinuxfs")) { continue; } if (parts[0].equals("debugfs")) { continue; } if (parts[0].equals("tmpfs")) { continue; } if (parts[1].equals(Environment.getRootDirectory().getAbsolutePath())) { continue; } if (parts[1].equals(Environment.getDataDirectory().getAbsolutePath())) { continue; } if (parts[1].equals(Environment.getExternalStorageDirectory().getAbsolutePath())) { continue; } // Verify that the mount point is accessible by listing its content. File file = new File(parts[1]); if (file.listFiles() != null) { try { // Get canonical path for case it's just symlink to another mount point. String devPath = file.getCanonicalPath(); for(FileSystemDevice device : devices) { if (!devices.contains(devPath)) { devices.add(new FileSystemDevice(new File(devPath))); } } } catch (Exception e) { // Silently skip the exception as it can only occur if the mount point is not valid. e.printStackTrace(); } } } catch (Exception e) { // Silently skip the exception as it can only occur if the mount point is not valid. e.printStackTrace(); } } } fs.close(); } catch (FileNotFoundException e) { // Silently skip the exception as it can only occur if the /proc/mounts file is unavailable. // Possibly, another detection method can be called here. e.printStackTrace(); } catch (IOException e) { // Silently skip the exception as it can only occur if the /proc/mounts file is unavailable. // Possibly, another detection method can be called here. e.printStackTrace(); } return devices; }
quelle
Hier ist eine Möglichkeit, eine neue Datei im externen Speicher zu erstellen (SDCard, falls im Gerät vorhanden, oder externer Speicher des Geräts, falls nicht). Ersetzen Sie einfach "Ordnername" durch den Namen Ihres gewünschten Zielordners und "Dateiname" durch den Namen der Datei, die Sie speichern. Natürlich können Sie hier sehen, wie Sie eine generische Datei speichern. Jetzt können Sie suchen, wie Sie Bilder speichern können, vielleicht hier oder was auch immer in einer Datei.
try { File dir = new File(Environment.getExternalStorageDirectory() + "/foldername/"); if (!dir.exists()){ dir.mkdirs(); } File sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileName ); int num = 1; String fileNameAux = fileName; while (sdCardFile.exists()){ fileNameAux = fileName+"_"+num; sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileNameAux); num++; }
Dies steuert auch, dass eine Datei vorhanden ist, und fügt am Ende des Namens der neuen Datei eine Nummer hinzu, um sie zu speichern.
Ich hoffe es hilft!
EDIT: Entschuldigung, ich habe vergessen, dass Sie
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in Ihrem Manifest nachfragen müssen (oder programmgesteuert, wenn Sie es vorziehen, von Marshmallow)quelle
Für Versionen unter Marshmallow können Sie die Berechtigungen direkt im Manifest angeben.
Bei Geräten mit Marshmallow und höher müssen Sie jedoch die Berechtigungen zur Laufzeit erteilen.
Durch die Nutzung
Sie können direkt auf die externe SD-Karte (gemountete) zugreifen. Ich hoffe, dies hilft.
quelle
Environment.getExternalStorageDirectory();
gibt Ihnen den Pfad zur geräteinternen SD-Karte.