Existe uma maneira universal de encontrar a localização de um cartão SD externo?
Por favor, não confunda com armazenamento externo .
Environment.getExternalStorageState()
retorna o caminho para o ponto de montagem SD interno, como "/ mnt / sdcard". Mas a questão é sobre o SD externo. Como obtenho um caminho como "/ mnt / sdcard / external_sd" (pode variar de dispositivo para dispositivo)?
Acho que vou terminar com a filtragem da saída do mount
comando pelo nome do sistema de arquivos. Mas não tenho certeza se esse caminho é suficientemente robusto.
Respostas:
Não,
Environment.getExternalStorageDirectory()
refere-se ao que o fabricante do dispositivo considerou "armazenamento externo". Em alguns dispositivos, essa mídia é removível, como um cartão SD. Em alguns dispositivos, essa é uma parte do flash no dispositivo. Aqui, "armazenamento externo" significa "o material acessível via modo USB Mass Storage quando montado em uma máquina host", pelo menos para o Android 1.xe 2.x.O Android não tem um conceito de "SD externo", além do armazenamento externo, conforme descrito acima.
Se um fabricante de dispositivos optou por ter armazenamento externo com flash integrado e também possui um cartão SD, será necessário entrar em contato com esse fabricante para determinar se você pode ou não usar o cartão SD (não garantido) e para que servem as regras usá-lo, como qual caminho usar para ele.
ATUALIZAR
Duas coisas recentes a serem observadas:
Primeiro, no Android 4.4 ou superior, você não tem acesso de gravação à mídia removível (por exemplo, "SD externo"), exceto para quaisquer locais nessa mídia que possam ser retornados por
getExternalFilesDirs()
egetExternalCacheDirs()
. Veja a excelente análise de Dave Smith sobre isso, principalmente se você deseja os detalhes de baixo nível.Segundo, para que ninguém questione se o acesso à mídia removível é ou não parte do SDK do Android, aqui está a avaliação de Dianne Hackborn :
fonte
Eu vim com a seguinte solução com base em algumas respostas encontradas aqui.
CÓDIGO:
USO:
fonte
Eu tinha um aplicativo que usava um
ListPreference
local em que o usuário precisava selecionar o local em que queria salvar alguma coisa.Nesse aplicativo, digitalizei
/proc/mounts
e encontrei/system/etc/vold.fstab
pontos de montagem de sdcard. Armazenei os pontos de montagem de cada arquivo em doisArrayList
s .Depois, comparei uma lista com a outra e descartei os itens que não estavam nas duas listas. Isso me deu uma lista de caminhos raiz para cada sdcard.
De lá, eu testei os caminhos com
File.exists()
,File.isDirectory()
eFile.canWrite()
. Se qualquer um desses testes fosse falso, descartei esse caminho da lista.Tudo o que foi deixado na lista, converti em uma
String[]
matriz para que pudesse ser usada peloListPreference
atributo values.Você pode visualizar o código aqui: http://sapienmobile.com/?p=204
fonte
Você pode tentar usar a função da biblioteca de suporte chamada ContextCompat.getExternalFilesDirs () :
O primeiro é o armazenamento externo primário e o restante deve ser o caminho real dos cartões SD.
O motivo do múltiplo ".getParentFile ()" é subir outra pasta, pois o caminho original é
EDIT: aqui está uma maneira mais abrangente que eu criei, para obter os caminhos dos cartões SD:
fonte
App
,ContextCompact
,EnvironmentCompact
Para recuperar todos os armazenamentos externos (sejam cartões SD ou armazenamentos internos não removíveis ), você pode usar o seguinte código:
Como alternativa, você pode usar System.getenv ("EXTERNAL_STORAGE") para recuperar o diretório primário de armazenamento externo (por exemplo, "/ storage / sdcard0" ) e System.getenv ("SECONDARY_STORAGE") para recuperar a lista de todos os diretórios secundários (por exemplo " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB " ). Lembre-se de que, também nesse caso, convém filtrar a lista de diretórios secundários para excluir as unidades USB.
De qualquer forma, observe que o uso de caminhos codificados é sempre uma abordagem ruim (especialmente quando todos os fabricantes podem alterá-lo conforme desejado).
fonte
System.getenv("SECONDARY_STORAGE")
também pode fazer algumas referências, pois parece não documentado./mnt
também pode haver várias outras árvores fs, não apenas cartões SD e unidades USB. Seu código também listaria quaisquer montagens de sistema de arquivos internas (talvez até virtuais), se bem entendi, enquanto a pergunta deseja apenas cartões SD .Como Richard, eu também uso o arquivo / proc / mounts para obter a lista de opções de armazenamento disponíveis
fonte
printStackTrace
? Quando temosandroid.util.Log.e
?É possível encontrar onde quaisquer cartões SD adicionais são montados lendo
/proc/mounts
(arquivo padrão do Linux) e verificando os dados antigos (/system/etc/vold.conf
). E observe que o local retornado porEnvironment.getExternalStorageDirectory()
pode não aparecer na configuração vold (em alguns dispositivos, o armazenamento interno não pode ser desmontado), mas ainda precisa ser incluído na lista. No entanto, não encontramos uma boa maneira de descrevê-los ao usuário .fonte
mount
é mais compatível do que a leitura do/proc
sistema de arquivos. O problema é que o cartão SD não é necessário formatado como FAT. Além disso, o ponto de montagem do cartão pode variar de ROM para ROM. Além disso, poderia haver vários outros VFAT partições ...mount
executável, especialmente porque o desencadeamento de executáveis é desencorajado.Eu tento todas as soluções contidas neste tópico neste momento. Mas todos eles não funcionaram corretamente em dispositivos com uma placa externa (removível) e uma interna (não removível). O caminho do cartão externo não é possível obter do comando 'mount', do arquivo 'proc / mounts' etc.
E eu crio minha própria solução (na de Paulo Luan):
fonte
Se você olhar o código-fonte
android.os.Environment
, verá que o Android depende muito de variáveis de ambiente para caminhos. Você pode usar a variável de ambiente "SECONDARY_STORAGE" para encontrar o caminho para o cartão SD removível.Exemplo de uso:
fonte
Simplesmente use isso:
fonte
SECONDARY_STORAGE
há vários caminhos separados por dois pontos (":"). É por isso que eu divido a String (veja minha resposta acima).Por via universal , se você quer dizer via oficial; sim há um.
Em nível de API 19 ou seja, na versão Android 4.4 Kitkat, eles adicionaram
File[] getExternalFilesDirs (String type)
noContext
classe que permite que aplicativos para armazenar dados / arquivos em cartões micro SD.O Android 4.4 é o primeiro lançamento da plataforma que permite que os aplicativos usem cartões SD para armazenamento. Qualquer acesso a cartões SD antes do nível 19 da API era por meio de APIs privadas não suportadas.
getExternalFilesDirs (tipo String) retorna caminhos absolutos para diretórios específicos de aplicativos em todos os dispositivos de armazenamento compartilhado / externo. Isso significa que ele retornará caminhos para a memória interna e externa. Geralmente, o segundo caminho retornado seria o caminho de armazenamento para o cartão microSD (se houver).
Mas note que,
A terminologia de armazenamento interno e externo, de acordo com os documentos oficiais do Google / Android, é bem diferente do que pensamos.
fonte
getExternalFilesDirs()
geralmente retorna cartões SD que não são removíveis; portanto, essa não é uma maneira universal de encontrar o local de um cartão SD removível.Aqui está a maneira que eu uso para encontrar o cartão externo. Use mount cmd return e analise a parte vfat.
fonte
Esta solução lida com o fato de que
System.getenv("SECONDARY_STORAGE")
não serve para o Marshmallow.Testado e trabalhando em:
Samsung Galaxy Tab A (Android 6.0.1 - Estoque)
fonte
Desde a minha resposta original acima, a digitalização do vold não é mais viável entre os vários fabricantes.
Eu desenvolvi um método mais confiável e direto.
roots conterá todos os diretórios raiz graváveis no sistema, incluindo todos os dispositivos usb conectados por usb.
NOTA: O método canWrite precisa da permissão android.permission.WRITE_EXTERNAL_STORAGE.
fonte
/external_sd
é o cartão microSD externo; em alguns LGs, é/_ExternalSD
; em alguns dispositivos é/sdcard
. Talvez o último seja um link simbólico/storage/sdcard0
ou similar, mas será que esses outros serão realmente cobertos por/storage/*
e/mount/*
?pathname.canWrite()
e exigir permissão WRITE_EXTERNAL_STORAGE? Por que não apenas ligarpathname.canRead()
?Foi tão tarde, mas finalmente consegui algo que testei a maioria dos dispositivos (por fabricante e versões do Android) e está funcionando no Android 2.2+. se você achar que não está funcionando, comente com o nome do seu dispositivo. eu irei consertar isso. se alguém estiver interessado, vou explicar como funciona.
fonte
Ao escrever o código abaixo, você obterá o local:
/ storage / 663D-554E / Android / data / app_package_name / files /
que armazena os dados do seu aplicativo em / android / local de dados dentro do sd_card.
Eu testei esse código em um moto g4 plus e no dispositivo Samsung (tudo funciona bem).
espero que isso possa ser útil.
fonte
Aqui está o método que eu uso para encontrar um removível cartão SD . É complexo e provavelmente exagero em algumas situações, mas funciona em uma ampla variedade de versões do Android e fabricantes de dispositivos que testei nos últimos anos. Não conheço nenhum dispositivo desde o nível 15 da API no qual não encontra o cartão SD, se houver um montado. Na maioria dos casos, ele não retornará falsos positivos, especialmente se você der o nome de um arquivo conhecido para procurar.
Informe-me se você encontrar algum caso em que não funcione.
PS
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
no manifesto. E no nível 23 da API e superior, usecheckSelfPermission
/requestPermissions
.findSdCardPath(),
vez de recalculá-lo sempre que precisar.Log.d()
) no código acima. Ajuda a diagnosticar os casos em que o caminho certo não foi encontrado. Comente se você não deseja fazer logon.fonte
A única solução de trabalho que encontrei foi essa que usa reflexão
fonte
Não sei por que, mas preciso chamar .createNewFile () em um arquivo criado nos diretórios de armazenamento público antes de usá-lo. Na estrutura, os comentários para esse método dizem que não é útil. Aqui está uma amostra ...
fonte
Eu criei um método utils para verificar se um cartão SD está disponível no dispositivo ou não e obter o caminho do cartão SD no dispositivo, se disponível.
Você pode copiar dois métodos abaixo na classe do seu projeto que precisar. Isso é tudo.
fonte
Seu trabalho para todos os dispositivos externos, mas certifique-se de obter apenas o nome da pasta do dispositivo externo e, em seguida, você precisa obter o arquivo de um determinado local usando a classe File.
A ligar:
Obtendo acesso ao armazenamento externo
Para ler ou gravar arquivos no armazenamento externo, seu aplicativo deve adquirir as permissões do sistema READ_EXTERNAL_STORAGE ou WRITE_EXTERNAL_STORAGE . Por exemplo:
fonte
/ sdcard => Armazenamento interno (é um link simbólico, mas deve funcionar)
/ mnt / extSdCard => Sdcard externo
Isto é para Samsung Galaxy S3
Você provavelmente pode acreditar que isso é verdade para a maioria ... no entanto, verifique novamente!
fonte
/sdcard
é um link simbólico para externo no meu sony 2305.