Android 4.0+ için harici SD kart yolunu nasıl edinebilirim?


94

Samsung Galaxy S3 , üzerine takılı harici bir SD kart yuvasına sahiptir /mnt/extSdCard.

Böyle bir yolla bu yola nasıl ulaşabilirim Environment.getExternalStorageDirectory()?

Bu geri dönecek mnt/sdcardve harici SD kart için API bulamıyorum. (Veya bazı tabletlerde çıkarılabilir USB depolama birimi.)


Neden bunu istiyorsun Android'de böyle şeyler yapmak çok tavsiye edilmez. Belki de motivasyonunuzu paylaşırsanız, sizi bu tür şeyler için en iyi uygulama yönüne yönlendirebiliriz.
rharter

2
Kullanıcınız telefonunu değiştirdiğinde, SD kartı yeni telefona takın ve ilk telefonda / sdcard, ikinci telefonda / mnt / extSdCard, dosya yolunu kullanan herhangi bir şey çöktü. Onun göreceli yolundan gerçek bir yol üretmem gerekiyor.
Romulus Urakagi Ts'ai

Şimdi bu konu eski ama bu yardımcı olabilir. bu yöntemi kullanmalısın. System.getenv (); cihazınıza bağlı tüm depolamaya erişmek için Environment3 projesine bakın. github.com/omidfaraji/Environment3
Omid Faraji


İşte Nougat'a kadar çalışan çözümüm: stackoverflow.com/a/40205116/5002496
Gokul NC

Yanıtlar:


58

Burada bulduğum bir çözümle ilgili bir varyasyonum var

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

Orijinal yöntem test edildi ve üzerinde çalışıldı

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

Test edildiklerinde bunların hangi android sürümünde olduklarından emin değilim.

Değiştirilmiş versiyonumu şununla test ettim:

  • Moto Xoom 4.1.2 (stok)
  • Otg kablosu kullanan Galaxy Nexus (cyanogenmod 10)
  • HTC Incredible (cyanogenmod 7.2) bu hem dahili hem de harici döndü. GetExternalStorage () bunun yerine sdcard'a bir yol döndürdüğü için iç kısmı büyük ölçüde kullanılmadığından bu aygıt biraz tuhaftır.

ve ana depolama alanı olarak bir sdcard kullanan bazı tek depolama aygıtları

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

İnanılmaz hariç tüm bu cihazlar yalnızca çıkarılabilir depolama birimlerini iade etti. Muhtemelen yapmam gereken bazı ekstra kontroller var, ancak bu en azından şu ana kadar bulduğum çözümlerden biraz daha iyi.


3
Bence, orijinal klasör / mnt / SdCard gibi büyük harfler içeriyorsa çözümünüz geçersiz klasör adı verecektir
Eugene Popovich

1
Bazı Motorola, Samsung ve LG cihazlarında test ettim ve mükemmel çalıştı.
pepedeutico

2
@KhawarRaza, bu yöntem kitkat itibariyle çalışmayı bıraktı. Önceden tanımlanmış cihazları destekliyorsanız, bununla bir geri dönüş olarak Dmitriy Lozenko'nun yöntemini kullanın.
Gnathonic

1
HUAWEI Honor 3c'de çalışır. Teşekkürler.
li2

2
bu benim için bir Galaxy Note 3'te 4.0+ üzerinde / depolama yerine / mnt döndürüyor
ono

54

Sistemdeki tüm SD-CARD'lara giden yolları bulmanın daha güvenilir yolunu buldum. Bu, tüm Android sürümlerinde çalışır ve tüm depolara dönüş yolları (öykünülmüş dahil).

Tüm cihazlarımda düzgün çalışıyor.

Not: Environment sınıfının kaynak koduna göre.

private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

/**
 * Raturns all available SD-Cards in the system (include emulated)
 *
 * Warning: Hack! Based on Android source code of version 4.3 (API 18)
 * Because there is no standart way to get it.
 * TODO: Test on future Android versions 4.4+
 *
 * @return paths to all available SD-Cards in the system (include emulated)
 */
public static String[] getStorageDirectories()
{
    // Final set of paths
    final Set<String> rv = new HashSet<String>();
    // Primary physical SD-CARD (not emulated)
    final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
    // All Secondary SD-CARDs (all exclude primary) separated by ":"
    final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    // Primary emulated SD-CARD
    final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
    if(TextUtils.isEmpty(rawEmulatedStorageTarget))
    {
        // Device has physical external storage; use plain paths.
        if(TextUtils.isEmpty(rawExternalStorage))
        {
            // EXTERNAL_STORAGE undefined; falling back to default.
            rv.add("/storage/sdcard0");
        }
        else
        {
            rv.add(rawExternalStorage);
        }
    }
    else
    {
        // Device has emulated storage; external storage paths should have
        // userId burned into them.
        final String rawUserId;
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
        {
            rawUserId = "";
        }
        else
        {
            final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
            final String[] folders = DIR_SEPORATOR.split(path);
            final String lastFolder = folders[folders.length - 1];
            boolean isDigit = false;
            try
            {
                Integer.valueOf(lastFolder);
                isDigit = true;
            }
            catch(NumberFormatException ignored)
            {
            }
            rawUserId = isDigit ? lastFolder : "";
        }
        // /storage/emulated/0[1,2,...]
        if(TextUtils.isEmpty(rawUserId))
        {
            rv.add(rawEmulatedStorageTarget);
        }
        else
        {
            rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
        }
    }
    // Add all secondary storages
    if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
    {
        // All Secondary SD-CARDs splited into array
        final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
        Collections.addAll(rv, rawSecondaryStorages);
    }
    return rv.toArray(new String[rv.size()]);
}

5
DIR_SEPORATOR ne olmalıydı?
cYrixmorten

1
@cYrixmorten, kodun üstünde sağlanmıştır .. onun Patterniçin/
Ankit Bansal,

Bu çözümü Lolipop'ta deneyen var mı?
lenrok258

Bu yöntemi lenovo P780'de denedim, çalışmıyor.
Satheesh Kumar

2
Lollipop'a kadar çalışır; Geri System.getenv("SECONDARY_STORAGE")dönen Marshmallow (Galaxy Tab A w / 6.0.1) üzerinde çalışmıyor /storage/sdcard1. Bu konum mevcut değil, ancak gerçek konum, /storage/42CE-FD0A42CE-FD0A'nın biçimlendirilmiş bölümün birim seri numarası olduğu yer.
DaveAlden

32

Sanırım harici sdcard'ı kullanmak için bunu kullanmanız gerekiyor:

new File("/mnt/external_sd/")

VEYA

new File("/mnt/extSdCard/")

Senin durumunda...

yerine Environment.getExternalStorageDirectory()

Benim için çalışıyor. Önce mnt dizininde ne olduğunu kontrol etmeli ve oradan çalışmalısınız ..


Hangi sdcard'ı kullanacağınızı seçmek için bir tür seçim yöntemi kullanmalısınız:

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

1
Aslında, sabit kod yolu yerine bir yöntem istiyorum, ancak / mnt / list iyi olmalı. Teşekkür ederim.
Romulus Urakagi Ts'ai

Sorun değil. Ayarlarda yolu seçtiğiniz bir seçeneğe sahip olun, ardından bunu almak için yöntemi kullanın.
FabianCook

10
Maalesef harici SD kart / mnt'den farklı bir klasörde olabilir. Örneğin, Samsung GT-I9305'te / storage / extSdCard, yerleşik SD kartta / storage / sdcard0 yoluna sahipken
2013

2
Peki o zaman sdcard konumunu ve ardından ana dizinini alırsınız.
FabianCook

Android 4.0+ için Harici SD kartın yolu (tablete OTG kablosuyla bağlı pendrive için) ne olacak?
osimer pothe

15

Tüm Harici Depoları geri almak için ( SD kartlar veya dahili çıkarılamaz depolar ), aşağıdaki kodu kullanabilirsiniz:

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

Alternatif olarak, birincil Harici Depolama dizinini (ör. "/ Storage / sdcard0" ) almak için System.getenv ("EXTERNAL_STORAGE") ve tüm ikincil dizinlerin listesini geri almak için System.getenv ("SECONDARY_STORAGE") kullanabilirsiniz (ör. " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB " ). Bu durumda da USB sürücülerini dışlamak için ikincil dizinler listesine filtre uygulamak isteyebileceğinizi unutmayın.

Her durumda, lütfen sabit kodlu yollar kullanmanın her zaman kötü bir yaklaşım olduğunu unutmayın (özellikle her üretici bunu istediği gibi değiştirebildiğinde).


System.getenv ("SECONDARY_STORAGE"), Nexus 5 ve Nexus 7'de OTG kablosuyla bağlanan USB cihazları için
ÇALIŞMADI

İşte Nougat'a kadar çalışan çözümüm: stackoverflow.com/a/40205116/5002496
Gokul NC

14

Asus Zenfone2 , Marshmallow 6.0.1'i kontrol edene kadar Dmitriy Lozenko'nun çözümünü kullanıyordum ve çözüm çalışmıyor. Çözüm , özellikle microSD yolu için EMULATED_STORAGE_TARGET alınırken başarısız oldu , yani: / storage / F99C-10F4 / . Emüle edilmiş kök yollarını doğrudan benzetilmiş uygulama yollarından almak için kodu düzenledim ve daha çok bilinen telefon modeline özgü fiziksel yollar ekledim.context.getExternalFilesDirs(null);

Hayatımızı kolaylaştırmak için buraya bir kütüphane yaptım . Bunu gradle, maven, sbt ve leiningen inşa sistemi ile kullanabilirsiniz.

Eski usul yolu seviyorsanız, dosyayı doğrudan şuradan kopyalayıp yapıştırabilirsiniz: buradan , ancak gelecekte manuel olarak kontrol etmeden bir güncelleme olup olmadığını bilemezsiniz.

Herhangi bir sorunuz veya öneriniz varsa lütfen bize bildirin


1
Bunu kapsamlı bir şekilde kullanmadım, ancak bu benim sorunum için iyi çalışıyor.
David

1
Harika çözüm! Ancak bir not - uygulama aktifken SD kart çıkarılırsa , dosyalardan biri için context.getExternalFilesDirs(null)geri dönecek nullve sonraki döngüde istisna olacaktır. if (file == null) continue;Döngünün ilk satırı olarak eklemenizi öneririm .
Koger

1
@Koger öneri için teşekkür ederim, bunu ekledim ve
cevabıma

13

İyi haberler! KitKat'ta artık bu ikincil paylaşılan depolama cihazlarıyla etkileşim için herkese açık bir API var.

Yeni Context.getExternalFilesDirs()ve Context.getExternalCacheDirs()yöntemler, hem birincil hem de ikincil aygıtlar dahil olmak üzere birden çok yol döndürebilir. Daha sonra bunları yineleyebilir ve dosyalarınızı depolamak için en iyi yeri kontrol edebilir Environment.getStorageState()ve File.getFreeSpace()belirleyebilirsiniz. Bu yöntemler şu adreste de mevcuttur:ContextCompat , support-v4 kitaplığında .

Ayrıca, yalnızca tarafından döndürülen dizinleri kullanmakla ilgileniyorsanız Context, artık READ_veyaWRITE_EXTERNAL_STORAGE izinlerine . İleride, herhangi bir ek izin gerekmeden bu dizinlere her zaman okuma / yazma erişiminiz olacak.

Uygulamalar ayrıca izin isteklerini şu şekilde sona erdirerek eski cihazlarda çalışmaya devam edebilir:

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

Teşekkür ederim. Yazdıklarınızı izleyen bazı kodlar yaptım ve tüm sd kart yollarını bulmakta işe yaradığını düşünüyorum. Bakabilir misin ? Burada: stackoverflow.com/a/27197248/878126. BTW, "getFreeSpace" kullanmamalısınız çünkü teorik olarak boş alan çalışma sırasında değişebilir.
android geliştiricisi


11

Tüm harici SD kartlara erişim sağlamak için aşağıdakileri yaptım.

İle:

File primaryExtSd=Environment.getExternalStorageDirectory();

birincil harici SD'ye giden yolu elde edersiniz. Ardından:

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

birincil harici depolamanın üst dizinini alırsınız ve aynı zamanda tüm harici sd'nin üst dizinidir. Artık tüm depolamayı listeleyebilir ve istediğinizi seçebilirsiniz.

Umarım yararlıdır.


Kabul edilen cevap bu olmalı ve teşekkür ederim, faydalı.
Meanman

SD kartım / storage / FSAB-2345 / dizinindeydi. primaryExtSd "/ storage / emulated / 0" olarak geldi ama aslında bu benim dahili depom! Bu yüzden "/ storage" konumuna ulaşmak için primaryExtSd.getParentFile (). GetParentFile () yapmak zorunda kaldım ve bu benim harici depolama dizinimin ana dizini. Tüm depolamayı gerçekten bulmak için köke ulaştıktan sonra ağacın tam bir yürüyüşüne ihtiyaç duyulduğu anlaşılıyor.
safe_malloc

9

SD kart yollarının listesini şu şekilde elde ederim (birincil harici depolama hariç):

  /**
   * 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()Bu felaket için bir reçetedir. Bunu yapıyorsanız, istediğiniz yolu sabit bir şekilde kodlayabilirsiniz, çünkü 4 ebeveyn dışında herhangi bir önbellek dizini alırsanız, NullPointerException veya yanlış yolu alırsınız.
rharter

@rharter Doğru. Bu sorun da düzeltildi. Lütfen bir göz at.
android geliştiricisi

Dokümanlar ( developer.android.com/reference/android/content/… ) şöyle diyor: "Buraya iade edilen harici depolama cihazları, hem taklit edilmiş harici depolama hem de pildeki SD kartlar gibi fiziksel medya yuvaları da dahil olmak üzere cihazın kalıcı bir parçası olarak kabul edilir böl. Döndürülen yollar USB flash sürücüler gibi geçici cihazları içermez. " SD kart yuvalarını da içermiyorlar gibi geliyor, yani bir SD kartı pilin altına girmeden çıkarabileceğiniz yerler. Yine de söylemesi zor.
LarsH

1
@LarsH Eh, SGS3'te (ve gerçek SD kartta) kendim test ettim, bu yüzden diğer cihazlarda da çalışması gerektiğini düşünüyorum.
android geliştiricisi

5

Sağladığınız ipuçları için teşekkürler arkadaşlar, özellikle @SmartLemon, çözümü aldım. Başka birinin buna ihtiyacı olması durumunda, son çözümümü buraya koyarım (listelenen ilk harici SD kartı bulmak için):

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

Orada harici SD kart yoksa, yerleşik depolamaya geri döner. Sdcard yoksa onu kullanacağım, değiştirmeniz gerekebilir.


1
Android Sürüm 19'da bu boş atma. rootDir.listFiles () null döndürür. Nexus 7, emulator ve galaxy note ile test ettim.
Manu Zi

3

koduma bakın, umarım size yardımcı olur:

    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

Aslında bazı cihazlarda harici sdcard varsayılan adı şu şekilde extSdCardve diğerleri içinsdcard1 .

Bu kod parçacığı, tam olarak bu yolu bulmaya ve harici aygıtın yolunu almanıza yardımcı olur.

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

Bu bana çok yardımcı oldu.
Droid Chris

"/ Storage / external_sd" (LG G3 KitKat) kullanan bazı cihazlar var, Marshmallow'un bazı farklı şemaları var, Android 6.0 kullanan Nexus 5X'teki Dahili Depolama "/ mnt / sdcard" ve harici SD kart "/ storage altında bulunuyor / XXXX-XXXX "
AB

2

Evet. Farklı üreticiler, Samsung Tab 3 extsd'de olduğu gibi farklı SD kart adı kullanır ve bu farklı üreticinin farklı adlar kullandığı gibi diğer Samsung cihazları sdcard kullanır.

Seninle aynı ihtiyacım vardı. bu yüzden , projemden sizin için androi-dirchooser kitaplığını kullanan bu bağlantıya giden Android Dizini seçici örneğinden örnek bir örnek oluşturdum. Bu örnek SD kartı algılar ve tüm alt klasörleri listeler ve ayrıca cihazın birden fazla SD karta sahip olup olmadığını da tespit eder.

Kodun bir kısmı şuna benzer Tam örnek için Android Dizin Seçici bağlantısına gidin

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

Bu çözüm (bu soruya verilen diğer yanıtlardan derlenmiştir) System.getenv("SECONDARY_STORAGE")Marshmallow ile hiçbir faydası olmayan gerçeği (@ono tarafından belirtildiği gibi) ele alır .

Test edildi ve üzerinde çalışıyor:

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

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

Koşul rawSecondaryStoragesStr.contains(path), dahili depolamanın da eklenmesine izin verebilir; bu koşulu daha iyi kaldırabiliriz .. Bu sorunla karşılaştım, çünkü cihazım dahili depolama dizinini ile System.getenv("SECONDARY_STORAGE")döndürüyor, ancak KitKat'ta Harici Bellek Kartı yolunu ile geri dönüyor System.getenv(EXTERNAL_STORAGE); Görünüşe göre farklı satıcılar bunu herhangi bir standart olmadan farklı şekilde uyguladılar ..
Gokul NC

İşte Nougat'a kadar çalışan çözümüm: stackoverflow.com/a/40205116/5002496
Gokul NC

1

Bazı cihazlarda (örneğin, samsung galaxy sII) dahili hafıza kartı vfat içinde olabilir. Bu durumda, son kodu kullanın, yol dahili bellek kartı (/ mnt / sdcad) elde ederiz, ancak harici kart almayız. Aşağıdaki kod bu sorunu çözer.

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

Bu kodun sorunlarınızı kesinlikle çözeceğinden eminim ... Bu benim için iyi çalışıyor ... \

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 () size harici sd kartınızın veya usb konumunuzun tam yerini vermemelidir. "/ Proc / mounts" konumuna ayrıştırmanız yeterlidir, ardından / dev / fuse / storage / sdcard1 ", sdcard'ınızın doğru olup olmadığı konumunu size verecektir USB için de monte edilmiş veya aynı değil.Bu şekilde kolayca alabilirsiniz..Cheers..Sam
Sam

0

bu doğru değil. / mnt / sdcard / external_sd, SD kart takılı olmasa bile mevcut olabilir. Uygulamanız bağlanmadığında / mnt / sdcard / external_sd'ye yazmaya çalıştığınızda çökecek.

Önce aşağıdakileri kullanarak SD kartın takılıp takılmadığını kontrol etmeniz gerekir:

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

7
getExternalStorageState()Harici SD kart yerine dahili depolamayı döndürdüğünde bunun anlamsız olduğunu düşünüyorum.
Romulus Urakagi Ts'ai

Şimdi harici SD kart almak için bir işlev sağlıyorlar mı? Bir saat aradıktan sonra hiçbir ipucu bulamıyorum. Durum buysa, pek çok sürüm güncellendikten sonra bu çok garip.
rml

"Bu doğru değil" derken neyi kastediyordunuz? Biliyorum, bu 2,5 yıl önceydi ...
LarsH 15

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

4
Çalışmıyor. Dahili Depolama yolunu döndürür. yani / storage / emulated / 0

0

Context.getExternalCacheDirs () veya Context.getExternalFilesDirs () veya Context.getObbDirs () gibi bir şey kullanabilirsiniz. Tüm harici depolama cihazlarında, uygulamanın dosyalarını saklayabileceği uygulamaya özel dizinler sağlarlar.

Yani bunun gibi bir şey - Context.getExternalCacheDirs () [i] .getParentFile (). GetParentFile (). GetParentFile (). GetParent () size harici depolama aygıtlarının kök yolunu verebilir.

Bu komutların farklı bir amaç için olduğunu biliyorum, ancak diğer yanıtlar benim için işe yaramadı.

Bu bağlantı bana iyi ipuçları verdi - https://possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")Marshmallow için null döndürür. Bu, tüm harici dizinleri bulmanın başka bir yoludur. Dahili / harici olup olmadığını belirleyen çıkarılabilir olup olmadığını kontrol edebilirsiniz.

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

Ben sağladığı çözümler denedi Dmitriy Lozenko ve Gnathonic üzerinde benim Samsung Galaxy Tab S2 (Model: T819Y) ama hiçbiri beni harici SD Kart dizinine yolunu almak yardımcı oldu. mountkomut yürütme, harici SD Kart dizini için gerekli yolu içeriyordu (yani / Storage / A5F9-15F4), ancak normal ifadeyle eşleşmediğinden döndürülmedi. Samsung tarafından takip edilen dizin adlandırma mekanizmasını anlamıyorum. Neden standartlardan sapıyorlar (örn. Extsdcard) ve benim durumumda olduğu gibi gerçekten balık gibi bir şey buluyorlar (yani / Storage / A5F9-15F4) . Kaçırdığım bir şey var mı? Her neyse, normal ifadesindeki değişiklikleri takiben Gnathonic'in çözüm geçerli bir sdcard dizini edinmeme yardımcı oldu:

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;

Bunun geçerli bir çözüm olup olmadığından ve diğer Samsung tabletleri için sonuç verip vermeyeceğinden emin değilim ama şimdilik sorunumu çözdü. Aşağıda, Android'de (v6.0) çıkarılabilir SD Kart yolunu almak için başka bir yöntem verilmiştir. Yöntemi android hatmi ile test ettim ve işe yarıyor. İçinde kullanılan yaklaşım çok basittir ve kesinlikle diğer sürümler için de işe yarayacaktır, ancak test etmek zorunludur. Bununla ilgili bazı bilgiler yardımcı olacaktır:

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

Bu konuyu ele almak için başka bir yaklaşımınız varsa lütfen paylaşın. Teşekkürler


İşte Nougat'a kadar çalışan çözümüm: stackoverflow.com/a/40205116/5002496
Gokul NC

Asus Zenfone 2'de de sizinle aynı sorunu yaşıyorum, ancak sorunu çözmek için bunun yerine kodu Dmitriy Lozenko'dan değiştiriyorum stackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD, önerdiğiniz çözüm, ortam değişkenleri desteği kaldırıldığı için Android Marshmallow (6.0) ile çalışmayabilir. Tam olarak hatırlayamıyorum ama sanırım bir denedim.
Abdul Rehman

@GokulNC Bir deneyeceğim. okunaklı görünüyor :)
Abdul Rehman

@GokulNC evet, bu yüzden context.getExternalFilesDirs (null) kullanıyorum; sürüm> Marshmallow olduğunda doğrudan fiziksel yolları kullanmak yerine
HendraWD

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

File externalsdpath = new File(secStore);

Bu, harici sd ikincil depolamanın yolunu alacaktır.


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

Bu alternatif olarak yeni başlayanlar için en azından cihaza takılı tüm sürücülerin stringList'ini alıyor.
Emre Kılınç Arslan

0

SD kartımdaki dosyalara HTC One X (Android) cihazımda erişmek için şu yolu kullanıyorum:

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

Not üçlü "/"!


-1

Galaxy S3 Android 4.3'te kullandığım yol ./storage/extSdCard/Card/ ve işi yapıyor. Umarım yardımcı olur,


-1

Aşağıdaki adımlar benim için çalıştı. Sadece şu satırları yazmanız gerekiyor:

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

İlk satır, sd dizininin adını verecektir ve bunu, ikinci dizinin değiştirme yönteminde kullanmanız yeterlidir. İkinci dize, dahili ve çıkarılabilir SD'nin yolunu içerecektir (benim durumumda / storage /) . Sadece uygulamam için bu yola ihtiyacım vardı, ancak ihtiyacınız olursa daha da ileri gidebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.