一、分類
文件讀寫作為Android四大數據存儲方式之一,又分為內部存儲和外部存儲兩種:
(1)內部存儲(Internal storage):
- 總是可用。
- 文件默認情況存儲在/data/data/包名/files,緩存文件存儲在/data/data/包名/cache中,默認情況下只能只能被本APP操作,當然可以在openFileOutput()中指定是否可被其他app讀寫。
- 當使用者卸載你的app時,系統會自動從內部存儲中刪除安排app的所有文件。
(2)外部存儲(External storage):
1.並不是總是可用,因為用戶有可能將SD卡作為USB存儲掛載或者在某些情況下將SD卡從設備上卸下,因此需要使用getExternalStorageState()來查詢外部存儲的狀態,當返回的狀態是MEDIA_MOUNTED時才能讀寫。
2.保存在外部存儲的文件是world-readable的,所以保存在外部存儲的文件可能被其他應用讀取。
3.當用戶卸載app時,只用當你調用getExternalFilesDir()來保存文件時系統才會從外部存儲中移除app的文件。
4.權限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
向SD卡寫入數據權限,隱式授予了讀取權限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
當app只需要讀取而非寫入權限的時候更適合使用該權限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
在SD卡中創建和刪除文件權限
二、方法介紹
1)getFilesDir():返回/data/data/包名/files
2)getCacheDir():返回/data/data/包名/cache,在確定緩存文件不再需要時刪除掉,為app使用的內存量實現一個合理的大小限制,比如1M。如果系統在存儲空間低的時候運行,可能會在沒有警告的時候刪除緩存文件。
3)FileInputStream openFileInput(String name):打開應用程序文件夾下的nam文件對應的輸入流。
4)FileOutputStream openFileOutput(String name,int mode):打開應用程序文件夾下的nam文件對應的輸出流(若文件不存在則創建),第二個參數指定打開文件的模式:
MODE_PRIVATE:該文件只能被當前程序讀寫
MODE_APPEND:已追加方式打開該文件
MODE_WORLD_READABLE:該文件可被其他程序讀取
MODE_WORLD_WRITEABLE:該文件可被其他程序讀寫
5)getDir(String name,int mode):在應用程序的數據文件夾下獲取或創建app_name對應的子目錄
第二個參數:
MODE_PRIVATE:默認模式,該文件只能被當前程序訪問
MODE_WORLD_READABLE:該文件可被其他程序訪問(在API17被棄用)
MODE_WORLD_WRITEABLE:該文件可被其他程序讀寫(在API17被棄用)
6)String[] fileList():返回應用程序的數據文件夾下的全部文件名
7)deleteFile(String name):刪除應用程序的數據文件夾下指定文件
8)Environment.getExternalStorageState():判斷手機是否插入SD卡,當返回MEDIA_MOUNTED時才能對其進行讀寫
9)getExternalStorageDirectory():返回SD卡的根目錄 /storage/emulated/0
10)getExternalStoragePublicDirectory(String type):在SD卡的根目錄創建一個由type指定的特定類型的文件夾
例如:/storage/emulated/0/Pictures
11)getExternalFilesDir(String type):在SD卡中對應應用的數據文件夾中創建一個由type指定的特定類型的文件夾
例如:storage/emulated/0/Android/data/應用包名/files/Pictures
type可選項:
DIRECTORY_MUSIC 標准音樂目錄
,
DIRECTORY_PODCASTS
,
DIRECTORY_RINGTONES 鈴聲
,
DIRECTORY_ALARMS 警報音
,
DIRECTORY_NOTIFICATIONS 通知音
,
DIRECTORY_PICTURES 圖片
,
DIRECTORY_MOVIES 電影
,
DIRECTORY_DOWNLOADS 下載
,
DIRECTORY_DCIM 由camera拍攝的照片和視頻存放目錄
TIPS:(1)需要注意的是getExternalStoragePublicDirectory()與getExternalFilesDir()的區別在於前者所創建的文件不會在用戶卸載被系統刪除,而后者在SD卡創建的應用程序數據文件會被系統刪除。
(2)當用戶卸載APP的時候系統會刪除所有在內部存儲中對應APP的文件以及由getExternalFilesDir()調用創建的文件。
三、代碼示例
內部存儲:
import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class MainActivity extends AppCompatActivity { final String FILE_NAME="test.txt"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button read= (Button) findViewById(R.id.read); final Button write= (Button) findViewById(R.id.write); final EditText editText= (EditText) findViewById(R.id.edit_area); write.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { write(editText.getText().toString()); editText.setText(""); } }); read.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { editText.setText(read()); } }); findViewById(R.id.delete).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { delete(FILE_NAME,MainActivity.this); } }); } private String read(){ try { FileInputStream fis=openFileInput(FILE_NAME); byte[] buff=new byte[1024]; int hasRead=0; StringBuffer sb=new StringBuffer(); while ((hasRead=fis.read(buff))>0){ sb.append(new String(buff,0,hasRead)); } fis.close(); return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } private void delete(String name,Context context){ context.deleteFile(name); } private void write(String content){ try { FileOutputStream fos=openFileOutput(FILE_NAME,MODE_PRIVATE); try { fos.write(content.getBytes()); } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } }
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <EditText android:id="@+id/edit_area" android:lines="5" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/read" android:layout_below="@id/edit_area" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="讀入"/> <Button android:id="@+id/write" android:layout_toRightOf="@id/read" android:layout_below="@id/edit_area" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="寫入"/> <Button android:id="@+id/delete" android:layout_below="@id/edit_area" android:text="刪除" android:layout_toRightOf="@id/write" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
外部存儲:
package com.example.administrator.externalfile; import android.content.Context; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.RandomAccessFile; public class MainActivity extends AppCompatActivity { private String TAG="ENTERNAL"; private String FILE_NAME="/test.txt"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "ExternalStoragePublicDir=" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)); Log.d(TAG, "ExternalFilesDir=" + MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES)); Log.d(TAG,"ExternalStorageDir="+Environment.getExternalStorageDirectory()); final EditText editText= (EditText) findViewById(R.id.edit_area); Button read= (Button) findViewById(R.id.read); final Button write= (Button) findViewById(R.id.write); read.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { editText.setText(read()); } }); write.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { write(editText.getText().toString()); editText.setText(""); } }); } public boolean isExternalStorageWritable(){ String state= Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)){ return true; } return false; } public boolean isExternalStorageReadable(){ String state=Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)||Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){ return true; } return false; } /** * 獲取外部公用存儲路徑 * @param albumName * @return */ public File getAlbumStorageDir(String albumName){ File file=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),albumName); if (!file.mkdirs()){ Log.d(TAG,"Directory not create"); } return file; } /** * 獲取私有外部存儲目錄 * @param context * @param albumName * @return */ public File getAlbumStorageDir(Context context,String albumName){ File file=new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),albumName); if (!file.mkdirs()){ Log.d(TAG,"Directory not create"); } return file; } private String read(){ if (isExternalStorageWritable()){ // File sdCard=Environment.getExternalStorageDirectory(); File sdCard=getAlbumStorageDir(MainActivity.this,"test"); try { FileInputStream fis=new FileInputStream(sdCard.getCanonicalPath()+FILE_NAME); StringBuilder sb=new StringBuilder(""); byte[] buff=new byte[1024]; int hasRead=0; while ((hasRead=fis.read(buff))!=-1){ sb.append(new String(buff,0,hasRead)); } return sb.toString(); } catch (IOException e) { e.printStackTrace(); } } return null; } private void write(String content){ if (isExternalStorageWritable()){ // File sdCard=Environment.getExternalStorageDirectory(); File sdCard=getAlbumStorageDir(MainActivity.this,"test"); try { File targetFile=new File(sdCard.getCanonicalPath()+FILE_NAME); RandomAccessFile raf=new RandomAccessFile(targetFile,"rw"); raf.seek(targetFile.length()); raf.write(content.getBytes()); raf.close(); } catch (IOException e) { e.printStackTrace(); } } } }
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <EditText android:id="@+id/edit_area" android:lines="5" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/read" android:layout_below="@id/edit_area" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="讀入"/> <Button android:id="@+id/write" android:layout_toRightOf="@id/read" android:layout_below="@id/edit_area" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="寫入"/> <Button android:id="@+id/delete" android:layout_below="@id/edit_area" android:text="刪除" android:layout_toRightOf="@id/write" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
參考自:
http://developer.android.com/training/basics/data-storage/files.html