page.title=Salvando arquivos page.tags=armazenamento de dados helpoutsWidget=true trainingnavtop=true @jd:body

Esta lição ensina a

  1. Escolher entre armazenamento interno e externo
  2. Obter permissões para armazenamento externo
  3. Salvar arquivos em armazenamento interno
  4. Salvar arquivos em armazenamento externo
  5. Consultar espaço livre
  6. Excluir um arquivo

Leia também

O Android usa um sistema de arquivos parecido com sistemas de arquivos em disco de outras plataformas. Esta lição explica como trabalhar com o sistema de arquivos Android para ler e gravar arquivos com APIs {@link java.io.File} .

Um objeto {@link java.io.File} é adequado para ler ou gravar grandes quantidades de dados em ordens crescente sem pular nenhum item. Por exemplo, é bom para arquivos de imagens ou qualquer troca executada por uma rede.

Esta lição demonstra como executar tarefas básicas relacionadas a arquivos em seu aplicativo. Assume-se que você já esteja familiarizado com os fundamentos do sistema de arquivos Linux e com APIs de entrada/saída de arquivos padrão no {@link java.io}.

Escolher entre armazenamento interno e externo

Todos os dispositivos Android têm duas áreas de armazenamento de arquivos: armazenamento “interno” e “externo”. Estes nomes têm origem no início do Android, quando a maior parte de seus dispositivos oferecia memória embutida não volátil (armazenamento interno), além de uma mídia de armazenamento removível, como micro cartões SD (armazenamento externo). Alguns dispositivos dividem o espaço de armazenamento permanente em partições “interna” e “externa”. Assim, mesmo sem uma mídia de armazenamento removível, sempre há dois espaços de armazenamento e o comportamento da API permanece inalterado independentemente da remoção do armazenamento externo. A lista a seguir resume as principais informações sobre cada tipo de espaço de armazenamento.

Armazenamento interno:

O armazenamento interno funciona melhor quando você deseja garantir que o usuário nem outros aplicativos tenham acesso aos seus arquivos.

Armazenamento externo:

O armazenamento externo é o melhor local para arquivos que não exigem acesso restrito e para os arquivos que você deseja compartilhar com outros aplicativos ou permitir que o usuário acesse através com um computador.

Dica: embora os aplicativos sejam instalados no armazenamento interno por padrão, é possível especificar o atributo {@code android:installLocation} em seu manifesto para que o aplicativo seja instalado no armazenamento externo. Os usuários se beneficiam dessa opção quando o tamanho do APK é muito grande e ele dispõe de maior espaço em armazenamento externo do que interno. Para obter mais informações, consulte Local de instalação do aplicativo.

Obter permissões para armazenamento externo

Para gravar no armazenamento externo, você deve solicitar a permissão {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} em seu arquivo de manifesto:

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

Cuidado: atualmente, os aplicativos podem ler o armazenamento externo sem precisar de permissão especial. No entanto, isso será alterado em lançamentos futuros. Se seu aplicativo precisar ler o armazenamento externo (mas não gravar nele), será necessário declarar a permissão {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}. Para garantir que o aplicativo continue a funcionar adequadamente, declare essa permissão agora antes que as mudanças entrem em vigor.

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

No entanto, se seu aplicativo usa a permissão {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} , já existe uma permissão implícita para leitura do armazenamento externo.

Não é necessária permissão para salvar arquivos no armazenamento interno. Seu aplicativo sempre terá permissão para ler e gravar arquivos em seu diretório de armazenamento interno.

Salvar arquivos em armazenamento interno

Ao salvar um arquivo no armazenamento interno, você pode obter o diretório adequado como um {@link java.io.File} chamando um destes dois métodos:

{@link android.content.Context#getFilesDir}
Retorna um {@link java.io.File} que representa um diretório interno para seu aplicativo.
{@link android.content.Context#getCacheDir}
Retorna um {@link java.io.File} que representa um diretório interno para os arquivos de cache temporários de seu aplicativo. Certifique-se de excluir cada arquivo assim que não for mais necessário e estabeleça um limite de tamanho razoável para a quantidade de memória usada em um determinado período de tempo, como 1MB. Se o sistema começar a ficar com pouco espaço de armazenamento, ele poderá excluir arquivos de cache sem avisar.

Para criar um novo arquivo em um desses diretórios, use o construtor {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}, transmitindo o {@link java.io.File} fornecido por um dos métodos acima que especifica o diretório de armazenamento interno. Por exemplo:

File file = new File(context.getFilesDir(), filename);

Uma outra alternativa é chamar {@link android.content.Context#openFileOutput openFileOutput()} para obter um {@link java.io.FileOutputStream} que grave em um arquivo salvo no seu diretório interno. O exemplo a seguir mostra como gravar texto em um arquivo:

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

Em alternativa, caso precise colocar arquivos em cache, use {@link java.io.File#createTempFile createTempFile()}. Por exemplo, o método a seguir extrai o nome do arquivo de {@link java.net.URL} e cria um arquivo com o mesmo nome no diretório de cache interno de seu aplicativo.

public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;
}

Observação: o diretório de armazenamento interno do seu aplicativo é especificado pelo nome do pacote do aplicativo em um local específico do sistema de arquivos Android. Teoricamente, outros aplicativos poderão ler seus arquivos internos se você definir o arquivo para modo leitura. No entanto, o outro aplicativo também precisaria saber o nome do pacote do seu aplicativo e os nomes dos arquivos. Outros aplicativos não podem navegar nos diretórios internos e não têm permissão para ler ou gravar a menos que os arquivos sejam explicitamente definidos para permitir tais ações. Portanto, desde que você utilize {@link android.content.Context#MODE_PRIVATE} para seus arquivos no armazenamento interno, eles não ficarão acessíveis a outros aplicativos.

Salvar arquivos em armazenamento externo

Como o armazenamento externo pode ficar indisponível, como se o usuário ativar o armazenamento no PC ou remover o cartão SD que fornece armazenamento externo, você deve sempre verificar se o volume está disponível antes de acessá-lo. Consulte o estado de armazenamento externo chamando {@link android.os.Environment#getExternalStorageState}. Se o estado retornado for igual a {@link android.os.Environment#MEDIA_MOUNTED}, os arquivos poderão ser lidos e gravados. Os métodos a seguir ajudam a determinar a disponibilidade de armazenamento:

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

Embora o usuário e outros aplicativos possam modificar o armazenamento externo, há duas categorias de arquivos que deverão ser salvas aqui:

Arquivos públicos
Arquivos que precisam estar livremente disponíveis ao usuário e outros aplicativos. Ao desinstalar o aplicativo, o usuário deve continuar a ter acesso a esses arquivos.

Por exemplo, fotos capturadas pelo aplicativo ou outros arquivos baixados.

Arquivos privados
Arquivos que pertencem ao aplicativo e que devem ser excluídos na desinstalação . Embora esses arquivos estejam teoricamente à disposição do usuário e de outros aplicativo por estarem no armazenamento externo, na verdade são arquivos que não têm valor para o usuário fora do aplicativo. Ao desinstalar o aplicativo, o sistema exclui todos os arquivos no diretório privado externo do aplicativo.

Por exemplo, recursos adicionais baixados através do aplicativo ou arquivos de mídia temporários.

Para salvar arquivos públicos no armazenamento externo, use o método {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()} para obter um {@link java.io.File} que representa o diretório correto no armazenamento externo. O método exige um argumento que especifica o tipo de arquivo que se deseja salvar para que possa ser logicamente organizado com outros arquivos públicos , como {@link android.os.Environment#DIRECTORY_MUSIC} ou {@link android.os.Environment#DIRECTORY_PICTURES}. Por exemplo:

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

Se você deseja salvar arquivos privados do aplicativo, obtenha o diretório correto chamando {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} e informe um nome indicando o tipo de diretório desejado. Cada diretório criado dessa forma é adicionado ao diretório principal que contém todos os arquivos do armazenamento externo do aplicativo que o sistema exclui quando o usuário faz a desinstalação.

Por exemplo, este é um método que pode ser usado para criar um diretório para um álbum de fotos individual:

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

Se nenhum dos nomes de subdiretórios predefinidos se adequa aos arquivos, chame {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} e transmita {@code null}. Isso retorna o diretório raiz para o diretório privado do aplicativo no armazenamento externo.

Lembre-se de que {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} cria um diretório dentro de um diretório que é excluído quando o usuário desinstala o aplicativo. Se os arquivos salvos precisarem estar disponíveis após a desinstalação do aplicativo, como quando seu aplicativo é uma câmera e o usuário deseja manter as fotos, use {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()}.

Independentemente do uso de {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()} para arquivos compartilhados ou {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} para arquivos privados do aplicativo, é importante usar os nomes de diretório fornecidos pelas constantes de API, como {@link android.os.Environment#DIRECTORY_PICTURES}. Esses nomes de diretório garantem que os arquivos sejam tratados de forma adequada pelo sistema. Por exemplo, arquivos salvos em {@link android.os.Environment#DIRECTORY_RINGTONES} são categorizados pelo scanner de mídia dos sistema como toques e não como música.

Consultar espaço livre

Se você já souber antecipadamente a quantidade de dados a ser salvo, descubra se há espaço disponível suficiente sem fazer com que um {@link java.io.IOException} chame {@link java.io.File#getFreeSpace} ou {@link java.io.File#getTotalSpace}. Esses métodos informam o espaço disponível atual e o espaço total no volume de armazenamento. Essa informação ajuda a evitar o preenchimento do volume de armazenamento além de um determinado limite.

No entanto, o sistema não garante que será possível gravar a quantidade de bytes indicada por {@link java.io.File#getFreeSpace}. Se o número retornado tiver alguns MB além do tamanho dos dados que deseja salvar ou se o sistema de arquivos estiver abaixo de 90% cheio, é possível continuar com segurança. Caso contrário, não grave no armazenamento.

Observação: não é obrigatório verificar a quantidade de espaço disponível antes de salvar o arquivo. É possível tentar gravar o arquivo diretamente e depois obter um {@link java.io.IOException}, se houver. Essa ação é recomendada caso você não saiba exatamente quanto espaço será necessário. Por exemplo, se você alterar a codificação do arquivo antes de salvá-lo convertendo uma imagem PNG em JPEG, não é possível saber o tamanho do arquivo antecipadamente.

Excluir um arquivo

Sempre exclua arquivos que não sejam mais necessários. A forma mais simples de apagar um arquivo é fazer com que o arquivo de referência aberto chame {@link java.io.File#delete} por conta própria.

myFile.delete();

Se o arquivo estiver salvo em armazenamento interno, é possível solicitar ao {@link android.content.Context} para localizar e excluir o arquivo chamando {@link android.content.Context#deleteFile deleteFile()}:

myContext.deleteFile(fileName);

Observação: quando o usuário desinstala o aplicativo, o sistema Android também exclui:

No entanto, recomenda-se exclui manualmente todos os arquivos em cache criados com {@link android.content.Context#getCacheDir()} regularmente e outros arquivos que não sejam mais necessários.