Android 4.0以降の外部SDカードパスを取得するにはどうすればよいですか?


93

Samsung Galaxy S3には、外部SDカードスロットが搭載されてい/mnt/extSdCardます。

どうすればこのパスを取得できEnvironment.getExternalStorageDirectory()ますか?

これはを返しmnt/sdcard、外部SDカードのAPIが見つかりません。(または一部のタブレットではリムーバブルUSBストレージ。)


なぜこれが欲しいのですか?Androidでこのようなことを行うことは非常に推奨されません。おそらく、あなたのモチベーションを共有すれば、この種のことのベストプラクティスの方向を示すことができます。
rharter 2014年

2
ユーザーが電話を変更し、SDカードを新しい電話に接続すると、最初の電話では/ sdcard、2番目の電話では/ mnt / extSdCardになり、ファイルパスを使用するすべてのものがクラッシュします。相対パスから実際のパスを生成する必要があります。
Romulus Urakagi Ts'ai 2014

私は今このトピックは古いですが、これは役立つかもしれません。このメソッドを使用する必要があります。System.getenv(); デバイスに接続されているすべてのストレージにアクセスするには、プロジェクトEnvironment3を参照してください。 github.com/omidfaraji/Environment3
Omid Faraji 2016年


ここではヌガーまで働く私の解決策だ:stackoverflow.com/a/40205116/5002496
Gokul NC

回答:


58

ここで見つけたソリューションのバリエーションがあります

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

元のメソッドはテストされ、

  • Huawei X3(在庫)
  • Galaxy S2(在庫)
  • Galaxy S3(在庫)

彼らがテストされたとき、私はこれらがどのアンドロイドバージョンであったかわかりません。

私は修正したバージョンをテストしました

  • Moto Xoom 4.1.2(在庫)
  • Galaxy Nexus(cyanogenmod 10)、OTGケーブルを使用
  • HTC Incredible(cyanogenmod 7.2)これは内部と外部の両方を返しました。getExternalStorage()が代わりにsdcardへのパスを返すため、このデバイスは内部がほとんど使用されないという点で、ちょっと変わったものです。

また、SDカードをメインストレージとして使用する単一のストレージデバイス

  • HTC G1(cyanogenmod 6.1)
  • HTC G1(在庫)
  • HTC Vision / G2(在庫)

Incredibleを除いて、これらすべてのデバイスはリムーバブルストレージのみを返しました。たぶん、追加のチェックがいくつかあるはずですが、これは、これまでに見つけたどのソリューションよりも少なくとも少しは優れています。


3
元のフォルダに/ mnt / SdCardのような大文字が含まれている場合、ソリューションで無効なフォルダ名が表示されると思います
Eugene Popovich

1
私はいくつかのモトローラ、サムスン、LGデバイスでテストしましたが、完璧に動作しました。
pepedeutico 2013年

2
@KhawarRaza、このメソッドはキットカット以降機能しなくなりました。プリミクスデバイスをサポートしている場合のフォールバックとして、Dmitriy Lozenkoの方法を使用します。
Gnathonic 2014年

1
HUAWEI Honor 3cで動作します。ありがとう。
li2

2
これは、銀河注3に私のため4.0+の代わりに/ストレージ/ mntにを返している
小野

54

システム内のすべてのSD-CARDへのパスを取得するより信頼性の高い方法を見つけました。これは、すべてのAndroidバージョンで機能し、すべてのストレージ(エミュレート済みを含む)へのパスを返します。

すべてのデバイスで正しく動作します。

PS:Environmentクラスのソースコードに基づいています。

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は何だったと思いますか?
cYrixmorten 2013年

1
そのコードの上部に設けられ@cYrixmorten ..そのA Patternのために/
Ankit Bansalは

Lolipopでこのソリューションをテストした人はいますか?
lenrok258 2015年

Lenovo P780でこの方法を試しましたが、機能しません。
Satheesh Kumar

2
Lollipopまで動作します。がSystem.getenv("SECONDARY_STORAGE")返されるMarshmallow(Galaxy Tab A w / 6.0.1)では機能しません/storage/sdcard1。その場所は存在しませんが、実際の場所はです/storage/42CE-FD0A。ここで、42CE-FD0Aはフォーマットされたパーティションのボリュームシリアル番号です。
DaveAlden、2016

32

私はあなたがこれを使用する必要がある外部SDカードを使用すると思います:

new File("/mnt/external_sd/")

または

new File("/mnt/extSdCard/")

あなたの場合...

の代わりに Environment.getExternalStorageDirectory()

私のために働く。最初にディレクトリmntの内容を確認し、そこから作業する必要があります。


使用するSDカードを選択するには、いくつかのタイプの選択方法を使用する必要があります。

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

1
実際、ハードコードパスではなくメソッドが必要ですが、/ mnt /リストで問題ありません。ありがとうございました。
Romulus Urakagi Ts'ai

問題ない。パスを選択する設定にオプションがあり、メソッドを使用してこれを取得します。
FabianCook 2012

10
残念ながら、外部SDカードは/ mntとは別のフォルダにある可能性があります。たとえば、Samsung GT-I9305では/ storage / extSdCardですが、内蔵SDカードにはパス/ storage / sdcard0があります
iseeall

2
それでは、SDカードの場所を取得してから、その親ディレクトリを取得します。
FabianCook 2013年

Android 4.0以降の外部SDカード(OTGケーブルを介してタブレットに接続されているペンドライブ用)のパスは何ですか?
osimer pothe

15

すべての外部ストレージを取得するには(SDカードであるか、リムーバブルでない内部ストレージであるかにかかわらず)、次のコードを使用できます。

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

または、System.getenv( "EXTERNAL_STORAGE")を使用してプライマリ外部ストレージディレクトリ("/ storage / sdcard0"など)を取得しSystem.getenv( "SECONDARY_STORAGE")を使用してすべてのセカンダリディレクトリ(例:" / storage / extSdCard:/ storage / UsbDriveA:/ storage / UsbDriveB ")。この場合も、USBドライブを除外するために、セカンダリディレクトリのリストをフィルタリングしたい場合があることに注意してください。

いずれにせよ、ハードコードされたパスを使用することは常に悪いアプローチであることに注意してください(特に、すべての製造元が満足できるように変更する場合)


System.getenv( "SECONDARY_STORAGE")は、Nexus 5およびNexus 7のOTGケーブルを介して接続されたUSBデバイスに対して機能しませんでした
Khawar Raza

ここではヌガーまで働く私の解決策だ:stackoverflow.com/a/40205116/5002496
Gokul NC

14

Asus Zenfone2Marshmallow 6.0.1を確認してソリューションが機能しなくなるまで、Dmitriy Lozenkoのソリューションを使用していました。EMULATED_STORAGE_TARGETを取得するときに、特にmicroSDパス(/ storage / F99C-10F4 /など)でソリューションが失敗しました。コードを編集して、エミュレートされたアプリケーションパスからエミュレートされたルートパスを直接取得し、より既知の電話モデル固有の物理パスを追加しました。context.getExternalFilesDirs(null);

私たちの生活を楽にするために、ここにライブラリを作成しまし。gradle、maven、sbt、およびleiningenビルドシステムを介して使用できます。

昔ながらの方法が好きな場合は、ここから直接ファイルをコピーして貼り付けることもできますが、手動でチェックしないと、将来のアップデートがあるかどうかわかりません。

ご質問やご提案がございましたら、お知らせください


1
私はこれを広範囲に使用していませんが、これは私の問題にうまく機能します。
デビッド

1
素晴らしい解決策!ただし、アプリケーションがアクティブなときにSDカードが取り外されるcontext.getExternalFilesDirs(null)null、いずれかのファイルが返され、次のループで例外が発生します。if (file == null) continue;ループの最初の行として追加することをお勧めします。
Koger

1
@コジャーは提案をありがとう、私はそれを追加して私の答えにタイプミスを修正しました
HendraWD

13

朗報!KitKatには、これらのセカンダリ共有ストレージデバイスとやり取りするためのパブリックAPIがあります。

新しいメソッドContext.getExternalFilesDirs()Context.getExternalCacheDirs()メソッドは、プライマリデバイスとセカンダリデバイスの両方を含む複数のパスを返すことができます。あなたは、それらを反復して確認することができますEnvironment.getStorageState()し、File.getFreeSpace()あなたのファイルを保存するのに最適な場所を決定します。これらのメソッドはContextCompat、support-v4ライブラリでも利用できます。

またContext、によって返されるディレクトリの使用のみに関心がある場合は、READ_またはWRITE_EXTERNAL_STORAGE権限は不要になることにも注意してください。今後は、これらのディレクトリへの読み取り/書き込みアクセス権が常に付与され、追加の権限は必要ありません。

アプリは、次のように許可リクエストを終了することで、古いデバイスでも引き続き動作できます。

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

ありがとうございました。私はあなたが書いたものに従ういくつかのコードを作りました、そしてそれはすべてのsdカードのパスを見つけるのにうまくいくと思います。見ていただけますか?ここ:stackoverflow.com/a/27197248/878126。ところで、理論的には実行時に空き容量が変化する可能性があるため、「getFreeSpace」を使用しないでください。
Android開発者


10

すべての外部sdカードにアクセスするために、次のことを行いました。

と:

File primaryExtSd=Environment.getExternalStorageDirectory();

プライマリ外部SDへのパスを取得します。

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

プライマリ外部ストレージの親ディレクトリを取得し、すべての外部sdの親でもあります。これで、すべてのストレージをリストして、必要なストレージを選択できます。

お役に立てれば幸いです。


これは受け入れられる答えであるはずです、そしてそれは役に立ちますありがとうございます。
Meanman 2017年

9

SDカードパス(プライマリ外部ストレージを除く)のリストを取得する方法は次のとおりです。

  /**
   * 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()これは災害のレシピです。これを行っている場合は、必要なパスをハードコードするだけでよいでしょう。4つの親以外のキャッシュディレクトリを取得すると、NullPointerExceptionまたは間違ったパスが返されます。
rharter 2014年

@rharter正解。この問題も修正しました。ぜひご覧ください。
Android開発者

ドキュメント(developer.android.com/reference/android/content/…)は、「ここに返される外部ストレージデバイスは、エミュレートされた外部ストレージと、バッテリー内のSDカードなどの物理メディアスロットの両方を含む、デバイスの永続的な部分と見なされます。コンパートメント。返されるパスには、USBフラッシュドライブなどの一時的なデバイスは含まれません。」SDカードスロットも含まれていないようです。つまり、バッテリーの下に置かずにSDカードを取り外すことができる場所です。わかりにくいですが。
LarsH

1
@LarsHまあ、私はSGS3(および実際のSDカード)で自分でテストしたので、他のデバイスでも動作するはずです。
Android開発者

5

皆さん、特に@SmartLemonから提供された手がかりをありがとう、私は解決策を得ました。他の誰かがそれを必要とする場合、私はここに私の最終的な解決策を置きます(最初にリストされた外部SDカードを見つけるために):

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

そこに外部SDカードがない場合は、オンボードストレージを返します。SDカードが存在しない場合は使用しますが、変更する必要がある場合があります。


1
これは、Androidバージョン19ではnullをスローします。rootDir.listFiles()はnullを返します。私はそれをネクサス7、エミュレーター、ギャラクシーノートでテストしました。
Manu Zi

3

私のコードを参照してください、あなたに役立つことを願っています:

    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

実際、一部のデバイスでは、外部SDカードのデフォルト名がとして表示されextSdCard、他のデバイスではデフォルト名が表示されますsdcard1

このコードスニペットは、その正確なパスを見つけ、外部デバイスのパスを取得するのに役立ちます。

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

これは私を非常に助けました。
ドロイドクリス

「/ storage / external_sd」(LG G3 KitKat)を使用するデバイスがいくつかあり、Marshmallowにはいくつかの異なるスキームがあり、Android 6.0を使用するNexus 5Xの内部ストレージは「/ mnt / sdcard」であり、外部SDカードは「/ storage」にあります/ XXXX-XXXX」
AB

2

はい。製造元によって、Samsung Tab 3のextsdのように異なるSDカード名を使用し、他のサムスンデバイスでは、この異なる製造元が異なる名前を使用するようにsdcardを使用します。

私はあなたと同じ要件を持っていました。だから私は私のプロジェクトからサンプルのサンプルを作成しましたandroi-dirchooserライブラリを使用するこのリンクAndroid Directory Chooserサンプルに移動します この例では、SDカードを検出してすべてのサブフォルダーを一覧表示し、デバイスに複数のSDカードがあるかどうかも検出します。

コードの一部は次のようになります。完全な例については、リンクAndroid Directory Chooserに移動してください。

/**
* Returns the path to internal storage ex:- /storage/emulated/0
 *
* @return
 */
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
 }

/**
 * Returns the SDcard storage path for samsung ex:- /storage/extSdCard
 *
 * @return
 */
    private String getSDcardDirectoryPath() {
    return System.getenv("SECONDARY_STORAGE");
}


 mSdcardLayout.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        String sdCardPath;
        /***
         * Null check because user may click on already selected buton before selecting the folder
         * And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
         */

        if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
            mCurrentInternalPath = mSelectedDir.getAbsolutePath();
        } else {
            mCurrentInternalPath = getInternalDirectoryPath();
        }
        if (mCurrentSDcardPath != null) {
            sdCardPath = mCurrentSDcardPath;
        } else {
            sdCardPath = getSDcardDirectoryPath();
        }
        //When there is only one SDcard
        if (sdCardPath != null) {
            if (!sdCardPath.contains(":")) {
                updateButtonColor(STORAGE_EXTERNAL);
                File dir = new File(sdCardPath);
                changeDirectory(dir);
            } else if (sdCardPath.contains(":")) {
                //Multiple Sdcards show root folder and remove the Internal storage from that.
                updateButtonColor(STORAGE_EXTERNAL);
                File dir = new File("/storage");
                changeDirectory(dir);
            }
        } else {
            //In some unknown scenario at least we can list the root folder
            updateButtonColor(STORAGE_EXTERNAL);
            File dir = new File("/storage");
            changeDirectory(dir);
        }


    }
});

2

このソリューション(この質問に対する他の回答から集められたもの)System.getenv("SECONDARY_STORAGE")は、マシュマロでは役に立たない(@onoによって言及された)事実を処理します。

テスト済みで作業中:

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

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

条件rawSecondaryStoragesStr.contains(path)により、内部ストレージも追加される可能性があります。私はその状態をよりよく取り除くことができます。私のデバイスはで内部ストレージディレクトリをSystem.getenv("SECONDARY_STORAGE")返しますがSystem.getenv(EXTERNAL_STORAGE)、KitKatでは外部メモリカードパスを返すため、この問題に直面しました。...異なるベンダーがどのいまいましい標準なしで異なり、これを実装していたようだ
Gokul NC

ここではヌガーまで働く私の解決策だ:stackoverflow.com/a/40205116/5002496
Gokul NC

1

一部のデバイス(samsung galaxy sIIなど)では、内部メモリカードがvfatになっています。この場合、最後の参照コードを使用して、パス内部メモリカード(/ mnt / sdcad)を取得しますが、外部カードは取得しません。以下のコードを参照してこの問題を解決してください。

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

このコードで問題が確実に解決されると思います...これは私にとってはうまく機能しています... \

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()は、外部sdカードまたはusbの場所の正確な場所を提供するべきではありません。「/ proc / mounts」の場所を解析するだけで、/ dev / fuse / storage / sdcard1は、sdカードが適切かどうかの場所を提供しますマウントされているか、USBでも同じではありません。これにより、簡単に入手できます。乾杯..
サム

0

それは真実ではない。/ mnt / sdcard / external_sdは、SDカードがマウントされていなくても存在できます。マウントされていないときに/ mnt / sdcard / external_sdに書き込もうとすると、アプリケーションがクラッシュします。

最初にSDカードがマウントされているかどうかを確認する必要があります。

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

7
getExternalStorageState()外付けのSDカードではなく、内部のストレージを返却しても意味がないと思います。
Romulus Urakagi Ts'ai、

彼らは今、外部SDカードを取得する機能を提供していますか?1時間探しても手がかりが見つかりません。これが事実である場合、非常に多くのバージョンが更新された後、これは非常に奇妙です。
rml 2013年

「それは本当じゃない」と言ったとき、何を言っていましたか?私は知っています、それは2.5年前
でした

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

4
動作しません。内部ストレージのパスを返します。つまり、/ storage /

0

-Context.getExternalCacheDirs()、Context.getExternalFilesDirs()、Context.getObbDirs()などを使用できます。これらは、アプリケーションがファイルを保存できるすべての外部ストレージデバイスにアプリケーション固有のディレクトリを提供します。

したがって、このようなもの-Context.getExternalCacheDirs()[i] .getParentFile()。getParentFile()。getParentFile()。getParent()は、外部ストレージデバイスのルートパスを取得できます。

これらのコマンドが別の目的で使用されていることはわかっていますが、他の回答ではうまくいきませんでした。

このリンクは私に良い指針を与えました-https ://possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")マシュマロの場合はnullを返します。これは、すべての外部ディレクトリを見つける別の方法です。あなたはそれが内部/外部かどうかを決定する取り外し可能かどうかを確認することができます

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

私はによって提供ソリューション試してみましたドミトリLozenkoGnathonic上の私のサムスンギャラクシータブS2(モデル:T819Y)が、どれも私は、外部SDカードのディレクトリへのパスを取得助けません。mountコマンドの実行には、外部SDカードディレクトリへの必要なパス(/ Storage / A5F9-15F4など)が含まれていましたが、正規表現と一致しなかったため、返されませんでした。サムスンが続いているディレクトリ命名メカニズムがわかりません。なぜ標準(extsdcardなど)から逸脱して、私の場合(/ Storage / A5F9-15F4など)のように本当に魚のようなものを思いついたのですか。不足しているものはありますか?とにかく、の正規表現の変更に続いて Gnathonicの ソリューションは私が有効なSDカードディレクトリを取得するのに役立ちました:

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;

これが有効なソリューションであるかどうか、また他のSamsungタブレットで結果が得られるかどうかはわかりませんが、今のところ問題は解決しています。以下は、Android(v6.0)でリムーバブルSDカードのパスを取得する別の方法です。私はAndroidマシュマロでメソッドをテストしましたが、動作します。その中で使用されるアプローチは非常に基本的で、他のバージョンでも確実に機能しますが、テストは必須です。それにいくつかの洞察が役立つでしょう:

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

この問題を処理する他のアプローチがある場合は、親切に共有してください。ありがとう


ここではヌガーまで働く私の解決策だ:stackoverflow.com/a/40205116/5002496
Gokul NC

Asus Zenfone 2でも実際に同じ問題が発生しますが、問題を解決するためにコードをDmitriy Lozenkoから変更しましたstackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD環境変数のサポートが削除されているため、提案しているソリューションはAndroid Marshmallow(6.0)では機能しない可能性があります。正確には思い出せませんが、試してみたと思います。
Abdul Rehman 2016年

@GokulNCやってみます。正当なようです:)
Abdul Rehman 2016年

@GokulNCはい、それが私がcontext.getExternalFilesDirs(null);を使用する理由です。バージョンが>マシュマロである場合代わりに、直接の物理的なパスを使用する
HendraWD

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

File externalsdpath = new File(secStore);

これにより、外部sdセカンダリストレージのパスが取得されます。


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

これは、デバイスにマウントされているすべてのドライバーのstringListを少なくとも取得する初心者のための代替方法です。
Emre Kilinc Arslan 2017

0

SDカードのファイルにアクセスするには、HTC One X(Android)で次のパスを使用します。

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

3つの「/」に注意してください



-1

次の手順でうまくいきました。あなたはこの行を書くだけです:

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

最初の行はsdディレクトリの名前を示し、2番目の文字列のreplaceメソッドでそれを使用する必要があるだけです。2番目の文字列には、内部およびリムーバブルsd(私の場合は/ storage /)のパスが含まれます。アプリにこのパスが必要だったのですが、必要に応じてさらに先に進むことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.