1. 程式人生 > >Android資料儲存 SharedPreferences及SDCard

Android資料儲存 SharedPreferences及SDCard

一、資料儲存選項:Data Storage ——Storage Options

1、Shared Preferences

Store private primitive data in key-value pairs.

儲存簡單的鍵值對資料。

2、Internal Storage

Store private data on the device memory.

在手機記憶體中儲存不對外共享的資訊。

3、External Storage

Store public data on the shared external storage.

在外部儲存裝置上儲存公共的資料資訊。主要指儲存在SDCard

上。

4、SQLite Databases

Store structured data in a private database.

將結構化的資料儲存進資料庫。

5、Network Connection

Store data on the web with your own network server.

將資料儲存到自己的遠端伺服器上。

【備註:】

  • 內部儲存空間十分有限,因而顯得可貴,另外,它也是系統本身和系統應用程式主要的資料儲存所在地,一旦內部儲存空間耗盡,手機也就無法使用了。 
  • 所以對於內部儲存空間,我們要儘量避免使用。Shared Preferences和SQLite資料庫都是儲存在內部儲存
    空間上的。內部儲存一般用Context來獲取和操作。 
  • getFilesDir()獲取你app的內部儲存空間,相當於你的應用在內部儲存上的根目錄。
  • 最容易混淆的是外部儲存,如果說pc上區分出外部儲存和內部儲存的話,那麼自帶的硬碟算是內部儲存,U盤或者行動硬碟算是外部儲存,因此我們很容易帶著這樣的理解去看待安卓手機,認為機身固有儲存是內部儲存,而擴充套件的SDCard卡是外部儲存。比如Nexus 4有16G的內部儲存,普通消費者可以這樣理解,但是安卓的程式設計中不能,這16GB仍然是外部儲存。

二、SharedPreferences:

(一)、概念:

    SharedPreferences是Android系統提供的一個通用的資料持久化

框架,用於儲存和讀取key-value型別的原始基本資料型別對,目前支援string、int、long、float、boolean等基本型別的儲存,對於自定義的物件資料型別,無法使用SharedPreferences來儲存。

        SharedPreferences主要用於儲存系統的配置資訊。例如上次登入的使用者名稱,上次最後設定的配置資訊(如:是否開啟音效、是否使用振動,小遊戲的玩家積分等)。當再次啟動程式後依然保持原有設定。SharedPreferences用鍵值對方式儲存,方便寫入和讀取。

(二)、使用SharedPreferences的步驟

1、獲取SharedPreferences物件;

        SharedPreferences本身是一個介面,無法直接建立例項,通過Context的getSharedPreferences(String name, int  mode)方法來獲取例項。

        該方法的第二個引數有以下三個值:【檔案讀寫的操作模式

  • Context.MODE_PRIVATE:  指定該SharedPreferences的資料只能被本應用程式讀、寫;
  • Context.MODE_APPEND:新內容追加到原內容後;
  • Context.MODE_WORLD_READABLE:  指定 SharedPreferences資料能被其他應用程式讀,但是不支援寫;
  • Context.MODE_WORLD_WRITEABLE:  指定 SharedPreferences資料能被其他應用程式讀、寫。會覆蓋原資料。 
  • 可以使用  +  連線這些許可權

2、呼叫edit()方法獲取SharedPreferences.Editor;

3、通過SharedPreferences.Editor介面提供的put()方法對SharedPreferences進行更新;

4、呼叫SharedPreferences.Editor的commit()方法,將更新提交到SharedPreferences中。

(三)、核心程式碼:

button_main_savedata.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                prefs = getSharedPreferences("myaccount", Context.MODE_PRIVATE);
                                SharedPreferences.Editor editor = prefs.edit();
                                editor.putInt("age", 38);
                                editor.putString("username", "wangxiangjun");
                                editor.putString("pwd", "123456");
                                editor.putString("username", "xiangjun");
                                editor.putString("age", "I'm 40 years old!");
                                editor.commit();
                        }
                });

                button_main_readdata.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                prefs = getSharedPreferences("myaccount", Context.MODE_PRIVATE);
                                String name = prefs.getString("username", "wxj");
                                String pwd = prefs.getString("pwd", "000");
                                int age = prefs.getInt("age", 20);
                                System.out.println("====>" + name + ":" + pwd + ":" + age);
                        }
                });

(四)、儲存之後的SharedPreferences資料檔案:

        SharedPreferences資料總是以xml格式儲存在:/data/data/包名/shared_prefs目錄下;

例如:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>

<map>

    <string name="pwd">123456</string>

    <string name="username">xiangjun</string>

    <int  name="age">20</int>

</map>

(五)、SharedPreferences的設定Setting功能:

1、引入:

        手機中常有這樣的設定頁面,如果做這樣的頁面呢?是不是需要寫一個複雜的佈局檔案,再寫一堆事件監聽來完成呢?

2、PreferenceActivity的簡單用法:

    1)、步驟:

  • 將setting.xml檔案放到res的xml目錄下;
  • 將arrays.xml檔案放到values目錄下;
  • 寫一個頁面SettingActivity。

    2)、目錄結構:

    3)、核心程式碼:

    //在SettingActivity中。不再需要setContentView(R.layout.activity_main)方法來載入佈局了。
    protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // setContentView(R.layout.activity_main);
                addPreferencesFromResource(R.xml.setting);  
                //備註:This method was deprecated in API level 11. This function is not relevant for a modern fragment-based PreferenceActivity.這個方法在11版本以上就已經不推薦使用了。
        }

(六)、藉助SharedPreferences實現黑名單管理

1、示例程式碼: publicclass MainActivity extends Activity { private ListView listView_main_blockList; private EditText editText_main_number; private TextView textView_main_emptyinfo; private SharedPreferences prefs = null; private Editor editor = null; private ArrayAdapter<String> adapter = null; @Override protectedvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText_main_number = (EditText) findViewById(R.id.editText_main_number); listView_main_blockList = (ListView) findViewById(R.id.listView_main_blocklist); textView_main_emptyinfo = (TextView) findViewById(R.id.text_main_emptyinfo); prefs = getSharedPreferences("blocklist", Context.MODE_PRIVATE); editor = prefs.edit(); List<String> list = getBlocklist(); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list); // 注意setEmptyView()的用法。當介面卡為空的時候,設定ListView中的展示內容。 listView_main_blockList.setEmptyView(textView_main_emptyinfo); listView_main_blockList.setAdapter(adapter); } publicvoid clickButton(View view) { switch (view.getId()) { case R.id.button_main_add: String mpnumber = editText_main_number.getText().toString(); editor.putString(mpnumber, mpnumber); editor.commit(); fillListView(); break; case R.id.button_main_clear: editor.clear(); editor.commit(); fillListView(); break; default: break; } } /* * 獲取SharedPreferences中的全部資料,放到List集合中。形成介面卡的資料來源 */ private List<String> getBlocklist() { List<String> list = new ArrayList<String>(); try { Map<String, ?> map = prefs.getAll(); // 增強for迴圈,實現對Map集合的遍歷 for (Map.Entry<String, ?> entry : map.entrySet()) { list.add(entry.getKey()); } return list; } catch (Exception e) { returnnull; } } /* * 填充ListView控制元件,實現重新整理顯示資料的效果 */ privatevoid fillListView() { adapter.clear(); adapter.addAll(getBlocklist()); } @Override publicboolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); returntrue; } }

三、External Storage之SDCard操作:

(一)、引入:Android中提供了特有的兩個方法來進行IO操作(openFileInput()和openFileOutput() ),但是畢竟手機內建儲存空間很有限,為了更好地儲存應用程式的大檔案資料,需要讀寫SD卡上的檔案。SD卡大大擴充了手機的儲存能力。

(二)、讀寫SD卡的步驟:

1、先判斷手機是否有sd卡;

        呼叫Environment的getExternalStorageState()方法判斷手機是否插上sdcard。

2、獲取sdcard的路徑;

        呼叫Environment的getExternalStorageDirectory()方法來獲取外部儲存器的目錄。

3、此外還可以獲取SDCard可用磁碟空間的大小(藉助StatFs類來實現);

4、清單檔案中設定讀寫sdcard的許可權;

        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>   在sdcard中建立與刪除檔案的許可權

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>   向sdcard寫入許可權

5、執行讀寫操作(基本IO流操作)。

【備註:】

Environment.getExternalStorageDirectory().getPath()來獲取sdcard路徑,如果您需要往sdcard中儲存特定型別的內容,可以考慮使用Environment.getExternalStoragePublicDirectory(String type)方法,該方法可以返回特定型別的目錄,目前支援如下型別:

  1. DIRECTORY_ALARMS //警報的鈴聲 
  2. DIRECTORY_DCIM //相機拍攝的圖片和視訊儲存的位置 
  3. DIRECTORY_DOWNLOADS //下載檔案儲存的位置 
  4. DIRECTORY_MOVIES //電影儲存的位置, 比如 通過google play下載的電影 
  5. DIRECTORY_MUSIC //音樂儲存的位置 
  6. DIRECTORY_NOTIFICATIONS //通知音儲存的位置 
  7. DIRECTORY_PICTURES //下載的圖片儲存的位置 
  8. DIRECTORY_PODCASTS //用於儲存podcast(部落格)的音訊檔案 
  9. DIRECTORY_RINGTONES //儲存鈴聲的位置

【備註:】

        應用程式在執行的過程中如果需要向手機上儲存資料,一般是把資料儲存在SDcard中的。大部分應用是直接在SDCard的根目錄下建立一個資料夾,然後把資料儲存在該資料夾中。這樣當該應用被解除安裝後,這些資料還保留在SDCard中,留下了垃圾資料。如果你想讓你的應用被解除安裝後,與該應用相關的資料也清除掉,該怎麼辦呢?

  • 通過Context.getExternalFilesDir()方法可以獲取到 SDCard/Android/data/應用的包名/files/ 目錄,一般放一些長時間儲存的資料  【設定->應用->應用詳情裡面的”清除資料 Clear Data
  • 通過Context.getExternalCacheDir()方法可以獲取到 SDCard/Android/data/應用包名/cache/目錄,一般存放臨時快取資料            【設定->應用->應用詳情裡面的”清除快取“ Clear Cache
  • 如果使用上面的方法,當你的應用在被使用者解除安裝後,SDCard/Android/data/你的應用的包名/ 這個目錄下的所有檔案都會被刪除,不會留下垃圾資訊。

        而且上面二個目錄分別對應 設定->應用->應用詳情裡面的”清除資料“與”清除快取“選項。當然如果要儲存下載的內容,就不要放在以上目錄下。

(三)、SDCard私有檔案目錄:

1、私有目錄的files目錄下有分為以下7種(無DIRECTORY_DCIM和DIRECTORY_DOWNLOADS):

  • DIRECTORY_ALARMS 
  • DIRECTORY_MOVIES
  • DIRECTORY_MUSIC 
  • DIRECTORY_NOTIFICATIONS 
  • DIRECTORY_PICTURES  
  • DIRECTORY_PODCASTS 
  • DIRECTORY_RINGTONES 

2、私有目錄的cache目錄:

(三)、封裝SDCard的工具類:SDCardHelper類

   package com.steven.sdcardhelper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import andoid.ontent.Context;
import android.os.Environment;
import android.os.StatFs;
public class SDCardHelper {
	// 判斷SD卡是否被掛載
	public static boolean isSDCardMounted() {
		// return Environment.getExternalStorageState().equals("mounted");
		return Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED);
	}
	// 獲取SD卡的根目錄
	public static String getSDCardBaseDir() {
		if (isSDCardMounted()) {
			return Environment.getExternalStorageDirectory().getAbsolutePath();
		}
		return null;
	}
	// 獲取SD卡的完整空間大小,返回MB
	public static long getSDCardSize() {
		if (isSDCardMounted()) {
			StatFs fs = new StatFs(getSDCardBaseDir());
			int count = fs.getBlockCount();
			int size = fs.getBlockSize();
			return count * size / 1024 / 1024;
		}
		return 0;
	}
	// 獲取SD卡的剩餘空間大小
	public static long getSDCardFreeSize() {
		if (isSDCardMounted()) {
			StatFs fs = new StatFs(getSDCardBaseDir());
			int count = fs.getFreeBlocks();
			int size = fs.getBlockSize();
			return count * size / 1024 / 1024;
		}
		return 0;
	}
	// 獲取SD卡的可用空間大小
	public static long getSDCardAvailableSize() {
		if (isSDCardMounted()) {
			StatFs fs = new StatFs(getSDCardBaseDir());
			int count = fs.getAvailableBlocks();
			int size = fs.getBlockSize();
			return count * size / 1024 / 1024;
		}
		return 0;
	}
 
	// 往SD卡的公有目錄下儲存檔案
	public static boolean saveFileToSDCardPublicDir(byte[] data, String type,
			String fileName) {
		BufferedOutputStream bos = null;
		if (isSDCardMounted()) {
			File file = Environment.getExternalStoragePublicDirectory(type);
			try {
				bos = new BufferedOutputStream(new FileOutputStream(new File(
						file, fileName)));
				bos.write(data);
				bos.flush();
				return true;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return false;
	}
 
	// 往SD卡的自定義目錄下儲存檔案
	public static boolean saveFileToSDCardCustomDir(byte[] data, String dir,
			String fileName) {
		BufferedOutputStream bos = null;
		if (isSDCardMounted()) {
			File file = new File(getSDCardBaseDir() + File.separator + dir);
			if (!file.exists()) {
				file.mkdirs();// 遞迴建立自定義目錄
			}
			try {
				bos = new BufferedOutputStream(new FileOutputStream(new File(
						file, fileName)));
				bos.write(data);
				bos.flush();
				return true;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return false;
	}
 
	// 往SD卡的私有Files目錄下儲存檔案
	public static boolean saveFileToSDCardPrivateFilesDir(byte[] data,
			String type, String fileName, Context context) {
		BufferedOutputStream bos = null;
		if (isSDCardMounted()) {
			File file = context.getExternalFilesDir(type);
			try {
				bos = new BufferedOutputStream(new FileOutputStream(new File(
						file, fileName)));
				bos.write(data);
				bos.flush();
				return true;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return false;
	}
 
	// 往SD卡的私有Cache目錄下儲存檔案
	public static boolean saveFileToSDCardPrivateCacheDir(byte[] data,
			String fileName, Context context) {
		BufferedOutputStream bos = null;
		if (isSDCardMounted()) {
			File file = context.getExternalCacheDir();
			try {
				bos = new BufferedOutputStream(new FileOutputStream(new File(
						file, fileName)));
				bos.write(data);
				bos.flush();
				return true;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return false;
	}
 
	// 從SD卡獲取檔案
	public static byte[] loadFileFromSDCard(String fileDir) {
		BufferedInputStream bis = null;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
		try {
			bis = new BufferedInputStream(
					new FileInputStream(new File(fileDir)));
			byte[] buffer = new byte[8 * 1024];
			int c = 0;
			while ((c = bis.read(buffer)) != -1) {
				baos.write(buffer, 0, c);
				baos.flush();
			}
			return baos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				baos.close();
				bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
 
	// 獲取SD卡公有目錄的路徑
	public static String getSDCardPublicDir(String type) {
		return Environment.getExternalStoragePublicDirectory(type).toString();
	}
 
	// 獲取SD卡私有Cache目錄的路徑
	public static String getSDCardPrivateCacheDir(Context context) {
		return context.getExternalCacheDir().getAbsolutePath();
	}
 
	// 獲取SD卡私有Files目錄的路徑
	public static String getSDCardPrivateFilesDir(Context context, String type) {
		return context.getExternalFilesDir(type).getAbsolutePath();
	}
}

(四)、案例:
1、功能:點選按鈕,實現從網路上訪問圖片,將圖片儲存進SDCard中。點選另外一按鈕,可以獲取到剛才儲存進SDCard中的圖片,將其載入的頁面中的ImageView控制元件中。

2、示例程式碼:、示例程式碼:


publicclass MainActivity extends Activity {

private ImageView imageView_main_img;

private String urlString = "http://t2.baidu.com/it/u=2,1891512358&fm=19&gp=0.jpg";




     @Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

           setContentView(R.layout.activity_main);

imageView_main_img = (ImageView) findViewById(R.id.imageView_main_img);

   }




publicvoid clickButton(View view) {

switch (view.getId()) {

case R.id.button_main_save:

new MyTask(this).execute(urlString);

break;

case R.id.button_main_show:

                   String filepath = SDCardHelper.getSDCardPath() + File.separator

                                       + "mydir" + File.separator + "firstimg.jpg";

byte[] data = SDCardHelper.loadFileFromSDCard(filepath);

if (data != null) {

                           Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);

imageView_main_img.setImageBitmap(bm);

                   } else {

                           Toast.makeText(this, "沒有該圖片!", Toast.LENGTH_LONG).show();

                   }

break;

default:

break;

           }

   }




class MyTask extends AsyncTask<String, Void, byte[]> {

private Context context;

private ProgressDialog pDialog;




public MyTask(Context context) {

this.context = context;

pDialog = new ProgressDialog(context);

pDialog.setIcon(R.drawable.ic_launcher);

pDialog.setMessage("圖片載入中...");

           }




             @Override

protectedvoid onPreExecute() {

super.onPreExecute();

pDialog.show();

           }




             @Override

protectedbyte[] doInBackground(String... params) {

                   BufferedInputStream bis = null;

                   ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {

                           URL url = new URL(params[0]);

                           HttpURLConnection httpConn = (HttpURLConnection) url

                                           .openConnection();

                           httpConn.setDoInput(true);

                           httpConn.connect();




if (httpConn.getResponseCode() == 200) {

                                   bis = new BufferedInputStream(httpConn.getInputStream());

byte[] buffer = newbyte[1024 * 8];

int c = 0;




while ((c = bis.read(buffer)) != -1) {

                                           baos.write(buffer, 0, c);

                                           baos.flush();

                                   }

return baos.toByteArray();

                           }




                   } catch (Exception e) {

                           e.printStackTrace();

                   }

returnnull;

           }




             @Override

protectedvoid onPostExecute(byte[] result) {

super.onPostExecute(result);

if (result == null) {

                           Toast.makeText(context, "圖片載入失敗!", Toast.LENGTH_LONG).show();

                   } else {

                              // 將位元組陣列轉成Bitmap,然後將bitmap載入的imageview控制元件中

                              // Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0,

                              // result.length);

                              // imageView_main_img.setImageBitmap(bitmap);

if (SDCardHelper.saveFileToSDCard(result, "mydir",

                                               "firstimg.jpg")) {

                                   Toast.makeText(context, "圖片儲存OK!", Toast.LENGTH_LONG)

                                                   .show();

                           } else {

                                   Toast.makeText(context, "圖片儲存失敗!", Toast.LENGTH_LONG)

                                                   .show();

                           }

                   }

pDialog.dismiss();

           }

   }




     @Override

publicboolean onCreateOptionsMenu(Menu menu) {

           getMenuInflater().inflate(R.menu.main, menu);

returntrue;

   }

}

 

 

(五)、案例:SDCard檔案瀏覽器

2、原理:利用File物件的listFile()方法獲得File[]陣列。將陣列產生的資訊填充在listview中。

核心程式碼中的重要方法:

  1. listFiles()
  2. isFile()
  3. isDirectory()
  4. getAbsolutePath()
  5. getParentFile()
  6.  

3、核心示例程式碼:


publicclass MainActivity extends Activity {
private TextView textView_main_currentpath;
private ListView listView_main_fileList;


private File currentFile = null;
private File[] arrCurrentFiles = null;


     @Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);


                textView_main_currentpath = (TextView) findViewById(R.id.text_main_currentpath);
                listView_main_fileList = (ListView) findViewById(R.id.listView_main_filelist);


if (SDCardHelper.isSDCardMounted()) {
currentFile = new File(SDCardHelper.getSDCardPath());
                      fillListView(currentFile);
              } else {
                      Toast.makeText(MainActivity.this, "SDCARD不存在!", Toast.LENGTH_LONG)
                                      .show();
              }


                listView_main_fileList
                              .setOnItemClickListener(new OnItemClickListener() {


                                     @Override
publicvoid onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (arrCurrentFiles[position].isDirectory()) {
                                                      File[] arrSubFiles = arrCurrentFiles[position]
                                                                      .listFiles();
if (arrSubFiles.length == 0) {
                                                              Toast.makeText(MainActivity.this, "您點選的是空目錄!",
                                                                              2000).show();
                                                      } else {
                                                              fillListView(arrCurrentFiles[position]);
                                                      }


                                              } else {
                                                      Toast.makeText(MainActivity.this, "您點選的不是目錄!",
                                                                      Toast.LENGTH_LONG).show();
                                              }
                                      }
                              });


      }


publicvoid clickButton(View view) {
switch (view.getId()) {
case R.id.imageView_main_back:
if (!currentFile.getAbsolutePath().equals(
                                      SDCardHelper.getSDCardPath())) {
                              fillListView(currentFile.getParentFile());
                      }
break;
default:
break;
              }
      }


publicvoid fillListView(File file) {
                currentFile = file;
                arrCurrentFiles = currentFile.listFiles();


              List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < arrCurrentFiles.length; i++) {
                      Map<String, Object> map = new HashMap<String, Object>();
if (arrCurrentFiles[i].isDirectory()) {
                              map.put("imgId", R.drawable.folder);
                      } else {
                              map.put("imgId", R.drawable.file);
                      }
                      map.put("filename", arrCurrentFiles[i].getName());
                      list.add(map);
              }


              SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, list,
                           R.layout.item_listview_main,
new String[] { "imgId", "filename" }, newint[] {
                                           R.id.imageView_item_listview_type,
                                           R.id.text_item_listview_filename });
listView_main_fileList.setAdapter(adapter);
                textView_main_currentpath.setText(currentFile.getAbsolutePath());
      }


}

 

 

三、Android資料持久化總結:

檔案儲存:資料從持久化

SharedPreferences

內部儲存

外部儲存

資料庫儲存

路徑

1、data/data/包名【內部儲存目錄】

1.1 data/data/包名/shared_prefs

1.2 data/data/包名/databases

1.3 data/data/包名/files

context.getFilesDir()

1.4 data/data/包名/cache

context.getCacheDir()

2、data/app/apk

3、mnt【外部儲存】

mnt/sdcard

4、storage【外部儲存】

4.1 storage/sdcard

Environment.getExternalStorageDir()

公有目錄(九大公有目錄)

Environment.getExternalStoragePublicDir(String type)

該type引數是Environment中的常量

4.2 私有目錄

storage/sdcard/data/包名/files

context.getExternalFilesDir()

storage/sdcard/data/包名/cache

context.getExternalCacheDir()