Android学习笔记<20140113> External Storage的用法

本文介绍了Android应用程序如何使用外部存储器,包括读写权限、判断可读写性、保存私有文件、公共文件和缓存文件的方法。还提供了一个示例程序,演示了创建、读取、删除外部存储器上不同类型的文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 设备的内部存储空间有限,读写外部存储器可以让应用程序能够存取更大更多的文件。
  2. 应用程序在对外部存储器进行读写之前,需要获得对外部存储器操作的权限。一般情况下需要添加的权限有两条:
    在外部存储器上创建/删除文件的权限:<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    向外部存储器上写入数据的权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    添加完向外部存储器中写入数据的权限时,也同时包含了从外部存储器中读取数据的权限。
    从Android4.4开始,读写外部存储器上应用程序私有文件夹中文件不再需要在AndroidMenifest.xml文件中添加读写权限。
  3. 保存在外部存储器上的文件全局可读,只要一个应用程序添加有WRITE_EXTERNAL_STORAGE权限,就可以读取外部存储器上的任何文件,包括外部存储器上应用程序的私有文件夹的文件。当用户允许USB大容量存储器连接到计算机上后,用户也可以修改存储在外部存储器上的文件。如果用户把外部存储器mount到计算机上或拔出,外部存储器将不可访问。
  4. 在对外部存储器进行读写之前需要调用Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)判断对外部存储器是否可读写,如果设备中插有SD卡且在AndroidMenifest.xml中已经添加了操作外部存储器的权限,上面函数会返回true.
  5. 调用Environment.getExternalStorageDirectory()获取指向外部存储器目录的文件,调用文件的getCanonicalPath()方法获取外部存储器的绝对路径。
  6. 向外部存储器中写入数据:首先,获得要写入数据的文件的绝对路径,其次,从文件的绝对路径得到对应该绝对路径的文件targetFile,然后,从targetFile创建RandomAccess对象,调用RandomAccess对象的seek(int)方法和write(byte[])方法写入内容,最后,关闭输出流。当应用程序被卸载时,保存在这里的文件不会被删除。
  7. 从外部存储器中读取数据:首先,获得要读取数据的文件的绝对路径,其次,从文件绝对路径得到FileInputStream,并把FileInputStream包装成InputStreamReader,继而包装成BufferedReader,然后,调用BufferedReader的readLine()方法读取文件内容,最后,关闭输入流。
  8. 应用程序在外部存储器上新建的文件,如果它们是供用户和其它应用程序可以访问的,且它们是多媒体文件,应该把它们保存在公共目录下,如Music/, Pictures/,这样其它应用程序可以方便地访问它们,用户也可以方便地操作它们。把文件保存在这些媒体相关的公共目录下后,系统的媒体管理器可以在系统中分类管理这些文件。调用getExternalStoragePublicDirectory()并传入文件夹类型参数可以获得该类型对应的公共文件夹目录文件,获得公共文件夹后,就可以在其下创建目录或文件。若想让系统的媒体管理器扫描不到你的文件,在你的文件所在的文件夹中添加一个名为".nomedia"的文件,这样媒体管理器就扫描不到你的文件,但如果这些文件是应用程序私有的,这种方式并不是最好的,应该把它们保存在应用程序的私有文件夹中。当应用程序卸载时,保存在公共文件夹下的文件不会被删除。
  9. 应用程序在外部存储器上新建的文件,如果不想让MediaStore content provider识别,应该保存在外部存储器上的私有文件夹中。调用getExternalFilesDir(String)方法返回指向应用程序在外部存储器上的私有文件夹或其子文件夹的文件,应用程序在外部存储器上私有文件夹的根路径在.../sdcard/Android/data/<package nage>/files/,方法中参数表示应用程序在外部存储器上私有文件夹的子文件夹的类型,若为空,方法返回一个指向应用程序在外部存储器上私有文件夹根目录的文件,若传入参数DIRECTORY_MOVIES等,方法返回一个指向根目录下Movies/文件夹的文件,其它类推。当程序被卸载时,存储在外部存储器上的私有文件夹也会被卸载。虽然保存在外部存储器私有文件夹下的文件不会被MediaStore content provider识别, 但是其它具有READ_EXTERNAL_STORAGE权限的应用程序,都可以访问外部存储器上的所有文件,包括外部存储器上的私有文件,所以如果想让自己的数据完全私有,不被其它应用程序访问到,应该把它们保存在内部存储器上自己的私有文件夹中,即保存在路径/data/data/<package name>/路径下。
    当向应用程序在外部存储器的私有文件夹中添加文件后,.../sdcard/Android/data/<package nage>/files/如下图所示:
    
  10. 向外部存储器的私有文件夹中保存缓存文件,首先要调用getExternalCacheDir()方法获取指向缓存文件夹的文件,外部存储器上缓存文件夹的根路径在.../sdcard/Android/data/<package name>/cache/,若开始时cache/文件夹不存在,调用该方法后会创建出一个空cache/目录。然后可以调用File的构造函数File(File, String)在cache目录下创建目录或文件,进而进行读写。
    当向应用程序在外部存储器上的缓存文件中写入文件后,.../sdcard/Android/data/<package name>/cache/目录如下图所示:
    
  11. Android的文件系统中可以存放应用程序文件的地方有两块,一个是私有文件夹,在绝对路径/data/data/<package name>/下,一个是SD卡,在外部存储器/sdcard/下,Android文件系统的其它路径应用程序不能访问。在/data/data/<package name>/下保存的是私有数据,主要有4种:在shared_prefs目录下保存的Preferences,在files目录下保存的私有文件,在cache目录下保存的缓存文件,在database目录下保存的SQLite数据库。在SD卡上保存的文件主要有3种:保存在.../sdcard/Android/data/目录下的私有文件,保存在公共目录下的文件,保存在其它目录下的文件。

  例子程序,功能:
    1. 在外部存储器根目录上创建一个名为"myExternalFile.txt"文本文件。
    2. 读取外部存储器根目录下名为"myExternalFile.txt"的文本文件的内容。
    3. 在外部存储器下公共文件夹/Pictures下创建一个图片文件。
    4. 在外部存储器私有文件夹的files/文件夹下创建文件夹和文件。
    5. 删除在外部存储器私有文件夹的files/文件夹下创建的文件夹和文件。
     6. 在外部存储器私有文件夹的/cache/文件夹下创建缓存文件。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText 
            android:id="@+id/edit_write"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="@string/input_message"/>
        <Button 
            android:id="@+id/button_write"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/write"/>
    </LinearLayout>
    
    <TextView 
        android:id="@+id/text_read"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="8dp"
        android:background="#ddddee"/>
    
    <Button 
        android:id="@+id/button_read"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/read"/>
    
    <Button 
        android:id="@+id/button_create_public"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/store_public"/>
    
    <Button 
        android:id="@+id/button_create_external_private"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/create_external_private_file"/>
    
    <Button 
        android:id="@+id/button_delete_external_private"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/delete_external_private_file"/>
    
    <Button 
        android:id="@+id/button_create_external_cache"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/create_external_cache"/>

</LinearLayout>
  
package com.example.demo0113externalstorage;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	final String FILE_NAME = "/myExternalFile.txt";
	final String LOG_TAG = "com.example.demo0113externalstorage.MainActivity";
	
	private EditText editWrite;
	private TextView textRead;
	private Button buttonWrite, buttonRead;
	private Button buttonCreateExternalPublic;
	private Button buttonCreateExternalPrivate, buttonDeleteExternalPrivate;
	private Button buttonCreateExternalCache;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		editWrite = (EditText) findViewById(R.id.edit_write);
		buttonWrite = (Button) findViewById(R.id.button_write);
		textRead = (TextView) findViewById(R.id.text_read);
		buttonRead = (Button) findViewById(R.id.button_read);
		buttonCreateExternalPublic = (Button) findViewById(R.id.button_create_public);
		buttonCreateExternalPrivate = (Button) findViewById(R.id.button_create_external_private);
		buttonDeleteExternalPrivate = (Button) findViewById(R.id.button_delete_external_private);
		buttonCreateExternalCache = (Button) findViewById(R.id.button_create_external_cache);
		
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == true) {
			buttonWrite.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					writeExternalFile(editWrite.getText().toString());
					
					editWrite.setText("");
				}
			});
			
			buttonRead.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					textRead.setText(readExternalFile());
				}
			});
			
			buttonCreateExternalPublic.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					createExternalPublic("myAlumn");
				}
			});
			
			buttonCreateExternalPrivate.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					createExternalStoragePrivateFile();
				}
			});
			
			buttonDeleteExternalPrivate.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					deleteExternalStoragePrivateFile();
				}
			});
			
			buttonCreateExternalCache.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					createExternalStorageCacheFile();
				}
			});
		} else {
			Toast.makeText(this, "不能访问到外部存储器!", Toast.LENGTH_SHORT).show();
		}
	}
	
	private void writeExternalFile(String message) {
		String filePath;
		try {
			filePath = Environment.getExternalStorageDirectory().getCanonicalPath() + FILE_NAME;
			File targetFile = new File(filePath);
			RandomAccessFile randomAccess = new RandomAccessFile(targetFile, "rw");
			
			randomAccess.seek(targetFile.length());
			randomAccess.write(message.getBytes());
			
			randomAccess.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private String readExternalFile() {
		String filePath;
		try {
			filePath = Environment.getExternalStorageDirectory().getCanonicalPath() + FILE_NAME;
			FileInputStream fis = new FileInputStream(filePath);
			BufferedReader br = new BufferedReader(new InputStreamReader(fis));
			
			StringBuilder stringBuiler = new StringBuilder("");
			String line = null;
			while ((line = br.readLine()) != null) {
				stringBuiler.append(line);
			}
			
			br.close();
			
			return stringBuiler.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	private File createExternalPublic(String albumName) {
		File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), albumName);
		
		if (file.exists() == false) {
			file.mkdirs();		// 若调用file.mkdir()创建文件夹,会失败!
		}
		
		File fileJpg = new File(file, "myBall.jpg");
		try {
			InputStream is = getResources().openRawResource(R.drawable.ball);
	        OutputStream os = new FileOutputStream(fileJpg);
	        byte[] data = new byte[is.available()];
	        is.read(data);
	        os.write(data);
	        is.close();
	        os.close();
		} catch (IOException e) {
			// Unable to create file, likely because external storage is
	        // not currently mounted.
	        Log.w("ExternalStorage", "Error writing " + fileJpg, e);
		}
		
		return file;
	}
	
	/**
	 * getExternalFilesDir(String)返回一个指向目录的文件。
	 * 若传入参数为null,返回一个指向目录.../sdcard/Android/data/<package name>/的文件
	 * 若传入参数为Environment.DIRECTORY_PICTURES,返回一个指向目录.../sdcard/Android/data/<package name>/Pictures/的文件
	 * */
	private void createExternalStoragePrivateFile() {
		// 在外部存储器私有文件夹根目录下创建一个名为"myPrivateDir"的文件夹
		// new File(File, String)第1个参数表示要创建的文件所在的目录,第2个参数表示要创建的文件的文件名。
		File fileDir = new File(getExternalFilesDir(null), "myPrivateDir");
		if (fileDir.exists() == false) {
			fileDir.mkdir();
		}
		
		// 在外部存储器私有文件夹根目录下创建一个名为"myText.txt"的文件
		File fileText = new File(getExternalFilesDir(null), "myText.txt");
		if (fileText.exists() == false) {
			try {
				fileText.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		// 在外部存储器私有文件夹中Pictures/目录下创建一个名为"myPicture.jpg"的文件,并向其中写入内容
		File fileJpg = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "myPicture.jpg");
		try {
			InputStream is = getResources().openRawResource(R.drawable.ball);
	        OutputStream os = new FileOutputStream(fileJpg);
	        byte[] data = new byte[is.available()];
	        is.read(data);
	        os.write(data);
	        is.close();
	        os.close();
		} catch (IOException e) {
			// Unable to create file, likely because external storage is
	        // not currently mounted.
	        Log.w("ExternalStorage", "Error writing " + fileJpg, e);
		}
	}

	private void deleteExternalStoragePrivateFile() {
		File fileDir = new File(getExternalFilesDir(null), "myPrivateDir");
		if (fileDir != null) fileDir.delete();
		
		File fileText = new File(getExternalFilesDir(null), "myText.txt");
		if (fileText != null) fileText.delete();
		
		File fileJpg = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "myPicture.jpg");
		if (fileJpg != null) fileJpg.delete();
	}
	
	/**
	 * 调用getExternalCacheDir()方法后会在.../sdcard/Android/data/<package name>/下创建一个空的/cache/目录。
	 * 并返回一个指向cache/目录的文件。
	 * */
	private void createExternalStorageCacheFile() {
		File fileText = new File(getExternalCacheDir(), "myCacheText.txt");
		if (fileText.exists() == false) {
			try {
				fileText.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值