No primeiro post sobre
escrita e leitura de arquivos no Android descrevi como ler e escrever na memória interna do Android. Este post descreve como escrever e ler em arquivos armazenados no cartão SD do dispositivo.
Antes de optar em gravar informações no cartão SD do dispositivo, lembre-se que o usuário terá acesso as informações deste arquivo e poderá apagá-lo a qualquer momento. Também não existe a garantia do arquivo não ser apagado durante a conexão ou desconexão do dispositivo com o microcomputador, caso o mesmo seja desconectado de forma incorreta.
Para demonstrar a leitura e escrita no cartão SD, vou utilizar o mesmo layout do projeto da
parte I do post:
Antes de criar e escrever em um arquivo no cartão SD de um dispositivo, é necessário verificar se o cartão está inserido, quais são as permissões de escrita e leitura, se o sistema de arquivo é reconhecido pelo dispositivo, entre outras informações.
Foi criada a classe
ManageFile com o método
getStateSDcard() que verifica o estado do cartão SD, o método
WriteFile() que faz a escrita do texto e o método
ReadFile() que faz a leitura do texto armazenado no cartão SD.
public class ManageFile {
private static final String TAG = "ManageFile";
private Context context;
private boolean sdCardAvailable;
private boolean sdCardWritableReadable;
private boolean sdCardReadableOnly;
public ManageFile(Context context){
this.context = context;
}
/**
* Escreve no arquivo texto.
* @param text Texto a ser escrito.
* @return True se o texto foi escrito com sucesso.
*/
public boolean WriteFile(String text){
try {
File file = new File(context.getExternalFilesDir(null),
"romar.txt");
FileOutputStream out = new FileOutputStream(file, true);
out.write(text.getBytes());
out.write("\n".getBytes());
out.flush();
out.close();
return true;
} catch (Exception e) {
Log.e(TAG, e.toString());
return false;
}
}
/**
* Faz a leitura do arquivo
* @return O texto lido.
* @throws FileNotFoundException
* @throws IOException
*/
public String ReadFile() throws FileNotFoundException, IOException{
File textfile = new File(context.getExternalFilesDir(null),
"romar.txt");
FileInputStream input = new FileInputStream(textfile);
byte[] buffer = new byte[(int)textfile.length()];
input.read(buffer);
return new String(buffer);
}
public void getStateSDcard(){
// Obtêm o status do cartão SD
String status = Environment.getExternalStorageState();
if (Environment.MEDIA_BAD_REMOVAL.equals(status)) {
// Midia foi removida antes de ser montada
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia removida.");
}
else if (Environment.MEDIA_CHECKING.equals(status)) {
// Midia está presente e está sendo feita a verificação
sdCardAvailable = true;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia sendo verificada.");
}
else if (Environment.MEDIA_MOUNTED.equals(status)) {
// A midia está presente e montada neste momento com
// permissão de escrita e leitura
sdCardAvailable = true;
sdCardWritableReadable = true;
sdCardReadableOnly = false;
Log.d(TAG, "Midia com permissão de escrita e leitura.");
}
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(status)) {
// A midia está presente e montada neste momento com
// permissão somente de leitura
sdCardAvailable = true;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia com permissão somente leitura.");
}
else if (Environment.MEDIA_NOFS.equals(status)) {
// A midia está presente, mas está vazia ou utilizando um
// sistema de arquivos não suportado
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia com sistema de arquivos não compatível.");
}
else if (Environment.MEDIA_REMOVED.equals(status)) {
// A midia não está presente
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia não presente.");
}
else if (Environment.MEDIA_SHARED.equals(status)) {
// A midia está presente, não montada e compartilhada
// via USB
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia compartilhada via USB.");
}
else if (Environment.MEDIA_UNMOUNTABLE.equals(status)) {
// A midia está presente mas não pode ser montada
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia não pode ser montada");
}
else if (Environment.MEDIA_UNMOUNTED.equals(status)) {
// A midia está presente mas não montada
sdCardAvailable = false;
sdCardWritableReadable = false;
sdCardReadableOnly = false;
Log.d(TAG, "Midia não montada.");
}
}
public boolean isSdCardAvailable() {
return sdCardAvailable;
}
public void setSdCardAvailable(boolean sdCardAvailable) {
this.sdCardAvailable = sdCardAvailable;
}
public boolean isSdCardWritableReadable() {
return sdCardWritableReadable;
}
public void setSdCardWritableReadable(boolean sdCardWritableReadable) {
this.sdCardWritableReadable = sdCardWritableReadable;
}
public boolean isSdCardReadableOnly() {
return sdCardReadableOnly;
}
public void setSdCardReadableOnly(boolean sdCardReadableOnly) {
this.sdCardReadableOnly = sdCardReadableOnly;
}
}
No método
getStateSDcard() foi utilizado o método
getExternalStorageState() da classe
Environment do Android que retorna o estado do cartão SD. Para cada estado retornado é setado um flag para indicar se o cartão está disponível, se permite escrita e leitura, ou se permite somente somente leitura.
No método
WriteFile() foi utilizado o método
getExternalFilesDir() do Android para obter o diretório do cartão SD. Foi passado o valor
null como parâmetro, para que seja retornada a raiz do diretório da aplicação na área de armazenamento externa, no nosso caso o cartão SD (válido para a API 8, vide nota abaixo).
O arquivo vai ser escrito no diretório:
/Android/data/<nome_pacote>/files/
onde
nome_pacote
é o pacote da aplicação, no nosso caso br.com.romar.
NOTA: O método
getExternalFilesDir() deve ser utilizado em projetos que rodam a partir da API 8. Para projetos que rodam na API 7 ou inferior, deverá ser utilizado o método
getExternalStorageDirectory(), que irá retornar a raiz do diretório do cartão SD. Neste caso o arquivo será gravado na raiz do cartão e não no diretório da aplicação. No caso da API 8, quando a aplicação for desinstalada os arquivos que estiverem no cartão SD no diretório /Android/data/<nome_pacote>/files serão apagados.
No método
ReadFile() foi utilizado o mesmo método
getExternalFilesDir() do Android para abrir o arquivo gravado anteriormente para leitura.
Na Activity principal do projeto foi criado um botão para escrita e leitura do arquivo. Segue o código que trata o click em cada um dos botões:
@Override
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.btnRead: // Faz a leitura do arquivo
// Verifica se o sdcard tem permissão para leitura
if (managefile.isSdCardAvailable() &&
(managefile.isSdCardReadableOnly() ||
managefile.isSdCardWritableReadable())) {
managefile.getStateSDcard();
textRead.setText(managefile.ReadFile());
}
else {
Toast.makeText(this,
"O cartão SD não está disponível, ou não permite" +
" leitura", Toast.LENGTH_SHORT).show();
}
break;
case R.id.btnWrite: // Faz a escrita do arquivo
// Verifica se o sdcard tem permissão para escrita
if (managefile.isSdCardAvailable() &&
managefile.isSdCardWritableReadable()) {
// Avisa o usuário se a gravação foi bem sucedida
if(managefile.WriteFile(editText.getText().toString()) ==
true){
Toast.makeText(this,
"Texto gravado com sucesso.",
Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(this,
"Não foi possível escrever o texto.",
Toast.LENGTH_SHORT).show();
}
}
else {
Toast.makeText(this,
"O cartão SD não está disponível,
ou não permite" +
" escrita.", Toast.LENGTH_SHORT).show();
}
// Reseta o campo do texto
editText.setText("");
break;
default:
break;
}
} catch (FileNotFoundException e) {
Log.e(TAG, e.toString());
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
Antes de fazer a escrita ou leitura no arquivo, o código verifica primeiro se o cartão SD está disponível e permite escrita ou leitura dependendo do caso.
O cartão SD do dispositivo por padrão possui somente permissão de leitura. Para que seja possível escrever no cartão é necessário que no momento da instalação da aplicação o usuário dê a permissão de escrita na área de armazenamento externo. Para que a aplicação tenha a permissão de escrita é necessário inserir no arquivo AndroidManifest.xml da aplicação a seguinte tag:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />