Bagaimana cara mendapatkan jalur kartu SD eksternal untuk Android 4.0+?


94

Samsung Galaxy S3 memiliki slot kartu SD eksternal, yang dipasang ke /mnt/extSdCard.

Bagaimana saya bisa mendapatkan jalan ini dengan sesuatu seperti Environment.getExternalStorageDirectory()?

Ini akan kembali mnt/sdcard, dan saya tidak dapat menemukan API untuk kartu SD eksternal. (Atau penyimpanan USB yang dapat dilepas pada beberapa tablet.)


Kenapa kamu menginginkan ini? Sangat tidak disarankan di Android untuk melakukan hal seperti ini. Mungkin jika Anda berbagi motivasi, kami dapat mengarahkan Anda ke arah praktik terbaik untuk hal semacam ini.
rharter

2
Ketika pengguna Anda mengganti ponsel mereka, colokkan kartu SD ke ponsel baru, dan di ponsel pertama itu / sdcard, di ponsel kedua itu / mnt / extSdCard, apa pun yang menggunakan jalur file macet. Saya perlu menghasilkan jalur nyata dari jalur relatifnya.
Romulus Urakagi Ts'ai

Saya sekarang topik ini sudah tua tetapi ini dapat membantu. Anda harus menggunakan metode ini. System.getenv (); lihat Project Environment3 untuk mengakses semua penyimpanan yang terhubung ke perangkat Anda. github.com/omidfaraji/Environment3
Omid Faraji


Inilah solusi saya yang berfungsi hingga Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

Jawaban:


58

Saya memiliki variasi solusi yang saya temukan di sini

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

Metode asli telah diuji dan dikerjakan

  • Huawei X3 (saham)
  • Galaxy S2 (stok)
  • Galaxy S3 (stok)

Saya tidak yakin versi Android apa ini saat diuji.

Saya telah menguji versi modifikasi saya dengan

  • Moto Xoom 4.1.2 (stok)
  • Galaxy Nexus (cyanogenmod 10) menggunakan kabel OTG
  • HTC Incredible (cyanogenmod 7.2) ini mengembalikan baik internal maupun eksternal. Perangkat ini agak aneh karena sebagian besar internalnya tidak digunakan karena getExternalStorage () mengembalikan jalur ke sdcard sebagai gantinya.

dan beberapa perangkat penyimpanan tunggal yang menggunakan kartu sd sebagai penyimpanan utamanya

  • HTC G1 (cyanogenmod 6.1)
  • HTC G1 (stok)
  • HTC Vision / G2 (stok)

Kecuali Incredible, semua perangkat ini hanya mengembalikan penyimpanan yang dapat dilepas. Mungkin ada beberapa pemeriksaan tambahan yang harus saya lakukan, tetapi ini setidaknya sedikit lebih baik daripada solusi apa pun yang saya temukan sejauh ini.


3
Saya pikir solusi Anda akan memberikan nama folder yang tidak valid jika yang asli berisi huruf kapital seperti / mnt / SdCard
Eugene Popovich

1
Saya telah menguji beberapa perangkat Motorola, Samsung dan LG dan itu bekerja dengan sempurna.
pepedeutico

2
@KawarRaza, metode ini berhenti berfungsi sejak kitkat. Gunakan metode Dmitriy Lozenko, dengan ini sebagai cadangan jika Anda mendukung perangkat pra-ics.
Gnathonic

1
Bekerja pada HUAWEI Honor 3c. Terima kasih.
li2

2
ini mengembalikan / mnt alih-alih / penyimpanan pada 4.0+ untuk saya di Galaxy Note 3
ono

54

Saya menemukan cara yang lebih andal untuk mendapatkan jalur ke semua SD-CARD dalam sistem. Ini berfungsi pada semua versi Android dan mengembalikan jalur ke semua penyimpanan (termasuk emulasi).

Bekerja dengan benar di semua perangkat saya.

PS: Berdasarkan kode sumber kelas Lingkungan.

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
Apa DIR_SEPORATOR yang seharusnya?
cYrixmorten

1
@cYrixmorten disediakan di atas kode .. ini Patternuntuk/
Ankit Bansal

Adakah yang menguji solusi ini di Lolipop?
lenrok258

Saya mencoba metode ini di lenovo P780. Itu tidak berfungsi.
Satheesh Kumar

2
Bekerja hingga Lollipop; tidak berfungsi di Marshmallow (Galaxy Tab A w / 6.0.1) tempat System.getenv("SECONDARY_STORAGE")pengembalian /storage/sdcard1. Lokasi itu tidak ada, tetapi lokasi sebenarnya adalah /storage/42CE-FD0A, di mana 42CE-FD0A adalah nomor seri volume dari partisi yang diformat.
DaveAlden

32

Saya kira untuk menggunakan sdcard eksternal Anda perlu menggunakan ini:

new File("/mnt/external_sd/")

ATAU

new File("/mnt/extSdCard/")

dalam kasusmu ...

sebagai pengganti Environment.getExternalStorageDirectory()

Bekerja untuk saya. Anda harus memeriksa apa yang ada di direktori mnt terlebih dahulu dan bekerja dari sana ..


Anda harus menggunakan beberapa jenis metode pemilihan untuk memilih kartu sd mana yang akan digunakan:

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

1
Sebenarnya saya menginginkan metode daripada jalur kode keras, tetapi / mnt / list seharusnya baik-baik saja. Terima kasih.
Romulus Urakagi Ts'ai

Tidak masalah. Memiliki opsi dalam pengaturan yang Anda pilih jalur dari, kemudian gunakan metode untuk mengambil ini.
FabianCook

10
Sayangnya, kartu SD eksternal mungkin berada di folder yang berbeda dari / mnt. Misalnya pada Samsung GT-I9305 itu / penyimpanan / extSdCard sedangkan kartu SD built-in memiliki jalur / penyimpanan / sdcard0
iseeall

2
Maka Anda akan mendapatkan lokasi sdcard, lalu mendapatkan direktori induknya.
FabianCook

Apa jalur kartu SD Eksternal (untuk flashdisk yang terhubung ke tablet melalui kabel OTG) untuk Android 4.0+?
osimer pothe

15

Untuk mengambil semua Penyimpanan Eksternal (apakah itu kartu SD atau penyimpanan internal yang tidak dapat dilepas ), Anda dapat menggunakan kode berikut:

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

Atau, Anda dapat menggunakan System.getenv ("EXTERNAL_STORAGE") untuk mengambil direktori Penyimpanan Eksternal utama (mis. "/ Storage / sdcard0" ) dan System.getenv ("SECONDARY_STORAGE") untuk mengambil kembali daftar semua direktori sekunder (mis. " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB " ). Ingatlah bahwa, juga dalam kasus ini, Anda mungkin ingin memfilter daftar direktori sekunder untuk mengecualikan drive USB.

Bagaimanapun, harap dicatat bahwa menggunakan jalur hard-code selalu merupakan pendekatan yang buruk (terutama ketika setiap pabrikan dapat mengubahnya sesuka hati).


System.getenv ("SECONDARY_STORAGE") TIDAK berfungsi untuk perangkat USB yang terpasang melalui kabel OTG pada Nexus 5 dan Nexus 7.
Khawar Raza

Inilah solusi saya yang berfungsi hingga Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

14

Saya menggunakan solusi Dmitriy Lozenko sampai saya memeriksa pada Asus Zenfone2 , Marshmallow 6.0.1 dan solusinya tidak berfungsi. Solusi gagal saat mendapatkan EMULATED_STORAGE_TARGET , khusus untuk jalur microSD, yaitu: / storage / F99C-10F4 / . Saya mengedit kode untuk mendapatkan jalur root yang diemulasi langsung dari jalur aplikasi yang diemulasi dengan context.getExternalFilesDirs(null);dan menambahkan jalur fisik khusus model telepon yang lebih dikenal .

Untuk mempermudah hidup kita, saya membuat perpustakaan di sini . Anda dapat menggunakannya melalui sistem build gradle, maven, sbt, dan leiningen.

Jika Anda menyukai cara kuno, Anda juga dapat melakukan copy paste file langsung dari sini , tetapi Anda tidak akan tahu jika ada update di masa mendatang tanpa memeriksanya secara manual.

Jika Anda memiliki pertanyaan atau saran, beri tahu saya


1
Saya belum pernah menggunakan ini secara ekstensif, tetapi ini bekerja dengan baik untuk masalah saya.
David

1
Solusi bagus! Namun satu catatan - jika kartu SD dihapus saat aplikasi aktif, context.getExternalFilesDirs(null)akan kembali nulluntuk salah satu file dan akan ada pengecualian di loop berikutnya. Saya sarankan menambahkan if (file == null) continue;sebagai baris pertama dalam lingkaran.
Koger

1
@Koger terima kasih atas sarannya, saya telah menambahkannya dan memperbaiki kesalahan ketik pada jawaban saya
HendraWD

13

Kabar baik! Di KitKat sekarang ada API publik untuk berinteraksi dengan perangkat penyimpanan bersama sekunder ini.

Metode Context.getExternalFilesDirs()dan baru Context.getExternalCacheDirs()dapat mengembalikan beberapa jalur, termasuk perangkat primer dan sekunder. Anda kemudian dapat mengulanginya dan memeriksa Environment.getStorageState()serta File.getFreeSpace()menentukan tempat terbaik untuk menyimpan file Anda. Metode ini juga tersedia ContextCompatdi pustaka support-v4.

Perhatikan juga bahwa jika Anda hanya tertarik menggunakan direktori yang dikembalikan oleh Context, Anda tidak lagi memerlukan izin READ_atau WRITE_EXTERNAL_STORAGE. Ke depannya, Anda akan selalu memiliki akses baca / tulis ke direktori ini tanpa izin tambahan yang diperlukan.

Aplikasi juga dapat terus berfungsi pada perangkat yang lebih lama dengan menghentikan permintaan izinnya seperti ini:

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

Terima kasih. Saya telah membuat beberapa kode yang mengikuti apa yang Anda tulis, dan saya pikir itu berfungsi dengan baik dalam menemukan semua jalur kartu sd. Bisakah kamu melihatnya? Di sini: stackoverflow.com/a/27197248/878126. BTW, Anda tidak boleh menggunakan "getFreeSpace" karena secara teoritis, ruang kosong dapat berubah selama runtime.
pengembang android


10

Saya melakukan hal berikut untuk mendapatkan akses ke semua kartu sd eksternal.

Dengan:

File primaryExtSd=Environment.getExternalStorageDirectory();

Anda mendapatkan jalur ke SD eksternal primer Kemudian dengan:

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

Anda mendapatkan dir induk dari penyimpanan eksternal primer, dan itu juga merupakan induk dari semua sd eksternal. Sekarang, Anda dapat membuat daftar semua penyimpanan dan memilih yang Anda inginkan.

Semoga bermanfaat.


Ini harus menjadi jawaban yang diterima, dan terima kasih bermanfaat.
Meanman

9

Inilah cara saya mendapatkan daftar jalur kartu SD (tidak termasuk penyimpanan eksternal utama):

  /**
   * 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()Ini adalah resep bencana. Jika Anda melakukan ini, Anda mungkin juga hanya membuat kode keras jalur yang Anda inginkan karena, jika Anda mendapatkan dir cache dengan apa pun selain 4 orang tua, Anda akan mendapatkan NullPointerException atau jalur yang salah.
rharter

@rarter Benar. Memperbaiki masalah ini juga. Mohon dilihat.
pengembang android

Dokumen ( developer.android.com/reference/android/content/… ) mengatakan "Perangkat penyimpanan eksternal yang dikembalikan di sini dianggap sebagai bagian permanen dari perangkat, termasuk penyimpanan eksternal yang diemulasi dan slot media fisik, seperti kartu SD di baterai kompartemen. Jalur yang dikembalikan tidak termasuk perangkat sementara, seperti flash drive USB. " Sepertinya mereka juga tidak menyertakan slot kartu SD, yaitu tempat Anda dapat mengeluarkan kartu SD tanpa harus menghabiskan baterai. Sulit untuk mengatakannya.
LarsH

1
@LarsH Ya, saya sudah mengujinya sendiri di SGS3 (dan SD-card asli), jadi saya pikir ini juga bisa berfungsi di perangkat lain.
Pengembang android

5

Terimakasih atas petunjuk yang diberikan oleh kalian khususnya @SmartLemon, saya dapat solusinya. Jika orang lain membutuhkannya, saya meletakkan solusi terakhir saya di sini (untuk menemukan kartu SD eksternal pertama yang terdaftar):

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

Jika tidak ada kartu SD eksternal di sana, maka itu mengembalikan penyimpanan papan. Saya akan menggunakannya jika sdcard tidak ada, Anda mungkin perlu mengubahnya.


1
ini melempar null pada Android Versi 19. rootDir.listFiles () mengembalikan null. Saya sudah mengujinya dengan nexus 7, emulator dan galaxy note.
Manu Zi

3

lihat kode saya, semoga bermanfaat untuk Anda:

    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

Sebenarnya di beberapa perangkat nama default sdcard eksternal ditampilkan sebagai extSdCarddan untuk yang lain itu sdcard1.

Cuplikan kode ini membantu menemukan jalur yang tepat dan membantu Anda mengambil jalur perangkat eksternal.

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

Ini sangat membantu saya.
Droid Chris

Ada beberapa perangkat yang menggunakan "/ storage / external_sd" (LG G3 KitKat), Marshmallow memiliki beberapa skema yang berbeda, Penyimpanan Internal pada Nexus 5X yang menggunakan Android 6.0 adalah "/ mnt / sdcard" dan kartu SD eksternal ada di bawah "/ storage / XXXX-XXXX "
AB

2

Iya. Pabrikan yang berbeda menggunakan nama SDcard yang berbeda seperti di Samsung Tab 3 extsdnya, dan perangkat samsung lainnya menggunakan sdcard seperti ini pabrikan yang berbeda menggunakan nama yang berbeda.

Saya memiliki persyaratan yang sama seperti Anda. jadi saya telah membuat contoh contoh untuk Anda dari proyek saya, goto tautan ini, contoh pemilih Direktori Android yang menggunakan pustaka androi-dirchooser. Contoh ini mendeteksi kartu SD dan mencantumkan semua subfolder dan juga mendeteksi jika perangkat memiliki lebih dari satu kartu SD.

Bagian dari kode terlihat seperti ini. Untuk contoh lengkap, buka tautan Pemilih Direktori Android

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

Solusi ini (dikumpulkan dari jawaban lain untuk pertanyaan ini) menangani fakta (seperti yang disebutkan oleh @ono) yang System.getenv("SECONDARY_STORAGE")tidak ada gunanya dengan Marshmallow.

Diuji dan dikerjakan:

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

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

Kondisi rawSecondaryStoragesStr.contains(path)ini memungkinkan penyimpanan internal juga ditambahkan; kami dapat lebih baik menghapus kondisi itu .. Saya menghadapi masalah itu, karena perangkat saya mengembalikan direktori penyimpanan internal dengan System.getenv("SECONDARY_STORAGE"), tetapi mengembalikan jalur Kartu Memori Eksternal dengan System.getenv(EXTERNAL_STORAGE)pada KitKat; tampaknya vendor yang berbeda telah menerapkan ini secara berbeda tanpa standar sialan ..
Gokul NC

Inilah solusi saya yang berfungsi hingga Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

1

Pada beberapa perangkat (misalnya samsung galaxy sII) kartu memori internal mabe harus di vfat. Dalam hal ini gunakan rujuk kode terakhir, kami memperoleh jalur kartu memori internal (/ mnt / sdcad) tetapi tidak ada kartu eksternal. Kode rujuk di bawah memecahkan masalah ini.

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

Saya yakin kode ini pasti akan menyelesaikan masalah Anda ... Ini berfungsi dengan baik untuk saya ... \

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 () seharusnya tidak memberi Anda lokasi pasti dari sdcard eksternal atau lokasi usb. Cukup parsing ke lokasi "/ proc / mounts" lalu / dev / fuse / storage / sdcard1 "akan memberi Anda lokasi apakah sdcard Anda benar terpasang atau tidak sama untuk usb juga. Dengan cara ini Anda dapat dengan mudah mendapatkannya..Cheers..Sam
Sam

0

itu tidak benar. / mnt / sdcard / external_sd dapat tetap ada meskipun kartu SD tidak dipasang. aplikasi Anda akan macet ketika Anda mencoba menulis ke / mnt / sdcard / external_sd ketika tidak dipasang.

Anda perlu memeriksa apakah kartu SD dipasang terlebih dahulu menggunakan:

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

7
Ini tidak ada artinya ketika getExternalStorageState()mengembalikan penyimpanan internal daripada kartu SD eksternal, saya kira.
Romulus Urakagi Ts'ai

Apakah mereka menyediakan fungsi untuk mendapatkan kartu SD eksternal sekarang? Saya tidak dapat menemukan petunjuk apapun setelah mencari-cari selama satu jam. Jika ini masalahnya, maka ini sangat aneh setelah begitu banyak versi diperbarui.
rml

Ketika Anda mengatakan "itu tidak benar", apa yang Anda maksud? Aku tahu, itu 2,5 tahun yang lalu ...
LarsH

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

4
Itu tidak berhasil. Ini mengembalikan jalur Penyimpanan Internal. yaitu / penyimpanan / ditiru / 0

0

Anda dapat menggunakan sesuatu seperti - Context.getExternalCacheDirs () atau Context.getExternalFilesDirs () atau Context.getObbDirs (). Mereka memberikan direktori khusus aplikasi di semua perangkat penyimpanan eksternal tempat aplikasi dapat menyimpan file-nya.

Jadi, sesuatu seperti ini - Context.getExternalCacheDirs () [i] .getParentFile (). GetParentFile (). GetParentFile (). GetParent () dapat memberi Anda jalur root perangkat penyimpanan eksternal.

Saya tahu perintah ini untuk tujuan yang berbeda tetapi jawaban lain tidak berhasil untuk saya.

Tautan ini memberi saya petunjuk bagus - https://possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")mengembalikan null untuk Marshmallow. Ini adalah cara lain untuk menemukan semua direktori eksternal. Anda dapat memeriksa apakah itu dapat dilepas yang menentukan apakah internal / eksternal

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

Saya telah mencoba solusi yang disediakan oleh Dmitriy Lozenko dan Gnathonic di Samsung Galaxy Tab S2 saya (Model: T819Y) tetapi tidak ada yang membantu saya mengambil jalur ke direktori Kartu SD eksternal. mounteksekusi perintah berisi jalur yang diperlukan ke direktori Kartu SD eksternal (yaitu / Storage / A5F9-15F4) tetapi tidak cocok dengan ekspresi reguler sehingga tidak dikembalikan. Saya tidak mendapatkan mekanisme penamaan direktori yang diikuti oleh Samsung. Mengapa mereka menyimpang dari standar (yaitu extsdcard) dan menghasilkan sesuatu yang sangat mencurigakan seperti dalam kasus saya (yaitu / Storage / A5F9-15F4) . Apakah ada yang saya lewatkan? Bagaimanapun, mengikuti perubahan ekspresi reguler Gnathonic's solusi membantu saya mendapatkan direktori sdcard yang valid:

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;

Saya tidak yakin apakah ini adalah solusi yang valid dan apakah itu akan memberikan hasil untuk tablet Samsung lainnya tetapi itu telah memperbaiki masalah saya untuk saat ini. Berikut adalah metode lain untuk mengambil jalur Kartu SD yang dapat dilepas di Android (v6.0). Saya telah menguji metode ini dengan android marshmallow dan berhasil. Pendekatan yang digunakan di dalamnya sangat mendasar dan pasti akan berfungsi untuk versi lain juga, tetapi pengujian itu wajib. Beberapa wawasan tentang itu akan membantu:

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

Mohon bagikan jika Anda memiliki pendekatan lain untuk menangani masalah ini. Terima kasih


Inilah solusi saya yang berfungsi hingga Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

Saya sebenarnya memiliki masalah yang sama dengan Anda di Asus Zenfone 2, tetapi saya mengubah kode dari Dmitriy Lozenko sebagai gantinya untuk menyelesaikan masalah stackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD solusi yang Anda sarankan mungkin tidak berfungsi dengan Android Marshmallow (6.0) karena dukungan untuk variabel lingkungan dihapus di dalamnya. Saya tidak dapat mengingatnya dengan tepat tetapi saya pikir saya telah mencobanya.
Abdul Rehman

@GokulNC Saya akan mencobanya. tampaknya sah :)
Abdul Rehman

@GokulNC ya, itulah mengapa saya menggunakan context.getExternalFilesDirs (null); alih-alih langsung menggunakan jalur fisik saat versinya> Marshmallow
HendraWD

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

File externalsdpath = new File(secStore);

Ini akan mendapatkan jalur penyimpanan sekunder sd eksternal.


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

Ini adalah alternatif untuk pemula setidaknya mendapatkan stringList dari semua driver yang dipasang di perangkat.
Emre Kilinc Arslan

0

Untuk mengakses file di kartu SD saya , di HTC One X (Android) saya, saya menggunakan jalur ini:

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

Perhatikan tripple "/"!


-1

Pada Galaxy S3 Android 4.3, jalur yang saya gunakan adalah ./storage/extSdCard/Card/ dan itu berfungsi . Semoga membantu,


-1

Langkah-langkah berikut berhasil untuk saya. Anda hanya perlu menulis baris ini:

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

Baris pertama akan memberi nama direktori sd, dan Anda hanya perlu menggunakannya dalam metode replace untuk string kedua. String kedua akan berisi jalur untuk sd internal dan removable (/ storage / dalam kasus saya) . Saya hanya membutuhkan jalur ini untuk aplikasi saya tetapi Anda dapat melangkah lebih jauh jika Anda membutuhkannya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.