得學會寫博客,以前是覺得逼格,現在發現是爲了總結自己的所學,項目做完了不代表會了,東西學完了不代表懂了。總結之後不會、不懂也無所謂,自己的接口調了就行了。當然了,啪啦啪啦,寫完做完還不會的,我也不想說什麼。看完這篇不會,下次就直接調我的接口吧。代碼已經上傳到 github上面去了,網址:https://github.com/KEYD111/AndroidFileOperation
經過ARM板-RK3288和小米手機的測試。親測可以使用。
博客中寫的欠缺的地方,無所謂,直接去看代碼,裏面的註釋很詳細。程序員看代碼就行了,每個函數全部封裝好了,廢話不多話。博客很長,大家慢慢看,看完一勞永逸,以後直接調我的函數就行了,但是講的很詳細,全部都是對比的來實現,方便大家的閱讀。
總體:大家依據直接餓的需求去看
一、先大體的介紹一下理論部分,這裏還是很重要的。
二、常見的存儲數據的方式
三、IO 文件流的讀取方式
四、sharedPreference 存儲
五、SQLite的存儲方式
六、assets的存儲方式
七、res的存儲方式
八、raw的存儲方式
一、先大體的介紹一下理論部分,這裏還是很重要的。
安卓存儲文件、數據的地方: RAM、ROM、內存(內部存儲器)、APP程序裏面(Assets,raw,res),SD卡(早期的安卓的可以插卡,現在的不支持了,但是有些 arm板 嵌入式方向的還是帶卡槽的),總體上來說就是這些了,網絡。
接下來再細分:
1、RAM、ROM 這些東西我們就別碰了,不然一大堆問題,Environment.getRootDirectory() 需要獲取root權限,不合適
2、內存和SD卡 大家得理解 Environment.getExternalStorageState() 代表的是什麼意思,不是插卡的SD卡,而是說你買了開發板、手機,廠家送你的存儲地方(直接你得讓他送你哈)。 這部分作爲主要的存儲路徑,小數據和大數據都適用。
3、SD卡,黑色那張卡,老古董,現在手機都沒有了,不建議大家使用,非要去使用,我也寫了相關的代碼(根據機型,不通用,切記,不能用不能怪我,這個只提供思路)。
4、網絡,請求自己的服務器,讀取數據,URI的方式,httpClient post 和 get 兩種請求數據的方式
存儲的地方就這麼多了。
二、常見的存儲數據的方式
1、sharedPreference, 將數據保存爲 xml 的格式,
2、數據庫 將SQLite的方式
3、contentprovider APP之間交互數據的方式。(這裏不講,沒有用過,沒有發言權)
4、文件的讀取(IO流) 和 Java的操作類似。
5、Android內部的存儲 assets,res, raw, 三者的區別
assets 和 raw 是不會隨着 APP進行編譯, res下的文件會隨着app一起編譯,每次 shift+alt+x 都要等好久
assets目錄下可以創建子文件夾 raw 不可以
三、IO 文件流的讀取方式
IO文件流最常見了,你得知道文件的存儲路徑纔可以看代碼中:
/**
* @Function: 常見的文件路徑的讀取只是簡單的介紹一下(沒什麼用)
* 根據自己的需要,根據實際的要求來進行操作。私有 和 APP綁定 生成文件
* 簡單的測試幾個路徑的例子
* @Return:
*/
private void getFilePath(String definedPath) {
String a = Environment.getDataDirectory().toString();
String b = getFilesDir().getAbsolutePath();
String c = getCacheDir().getAbsolutePath();
String d = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath();
String e = Environment.getExternalStorageDirectory().getPath();
String f = getExternalFilesDir("Documents").getPath();
Log.i(LOG_Info + "a: ", "Environment.getDataDirectory().toString():-----" + a);
Log.i(LOG_Info + "b: ", "getFilesDir().getAbsolutePath():----- " + b);
Log.i(LOG_Info + "c: ", "getCacheDir().getAbsolutePath():----- " + c);
Log.i(LOG_Info + "d: ", "Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath():----- " + d);
Log.i(LOG_Info + "e: ", "Environment.getExternalStorageDirectory().getPath():----- " + e);
Log.i(LOG_Info + "f: ", "getExternalFilesDir(\"Documents\").getPath():----- " + f);
}
常用的路徑存儲方式:大家看看就行了 我着重講三種的存儲方式,最有用。
/**
* 會了這常見的三種方式足夠了
* 一種是跟 app 綁定在一起的 數據庫SQLite操作的時候需要使用 跟隨着APP的生命週期而變換 apk私有目錄 不會導致數據殘留 卸載就沒了 但是重新燒錄不會改變數據庫 數據庫操作(親測)
* 一種是存在內存當中的,會一直存在 圖片保存 數據庫操作 (親測)Environment 方式獲取路徑 公共目錄
* 還有一種就是掛載的SD卡 這類就比較煩 而且是特別煩,除非必須使用,一般不推薦使用 容易出錯 現在的手機不支持外部SD卡了, 保存圖片 親測可以用
*/
/**
* @param FileDirName:你想創建的文件夾的名字
* @Function: 測試內部存儲
* @attention: 數據跟APP綁定 app卸載後就沒有了
* 生成的文件 存儲在 NANDFlash --> Android --> data 裏面是的 app的包名 com.XXX.......---> files 這種格式 找到對應的就可以了
* @Return: 返回文件夾的路徑,可以在文件夾下繼續創建文件
*/
private String TestFilePathApkPrivate(Context context, String FileDirName) {
//不需要掛載測試,因爲 app 都可以裝 爲什麼 會沒有數據
String filedirpath = context.getExternalFilesDir(FileDirName).getPath(); //文件夾
File fileDir = new File(filedirpath); //創建文件夾
if (fileDir.exists()) { //判斷文件是否存在 很重要 別每次都會去覆蓋數據
fileDir.setWritable(true);
Log.i(LOG_Info, "文件夾已經存在 TestFilePathInternalData()");
} else {
try {
fileDir.mkdir();
Log.i(LOG_Info, "文件夾創建成功 TestFilePathExternalData()");
} catch (Exception e) {
e.printStackTrace();
Log.i(LOG_Error, "文件夾創建錯誤 TestFilePathExternalData()" + e.getMessage());
}
}
return filedirpath;
}
上面的這種方式 數據會隨着的app的生命週期而變換,卸載就沒有了
/**
* @param filesname: 文件夾的名字
* @Function: 測試內部存儲 在公共存儲目錄下新建文件夾
* @attention: 一直存在 app卸載後依然存在 存儲在文件的公共目錄下的 比如說 打開 NANDFlash 會出現 Movies Pictures Downlaod 等等
* @Return:
*/
private String TestFilePathExternalData(String filesname) {
String pulicfileDir = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //測試是否掛載SD卡,並且是否加載了權限
pulicfileDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath();
File filedir = new File(pulicfileDir, filesname);
if (filedir.exists()) {
Log.i(LOG_Info, "文件夾已經存在 TestFilePathExternalData()");
} else {
try {
filedir.mkdir();
Log.i(LOG_Info, "文件夾創建成功 TestFilePathExternalData()");
} catch (Exception e) {
e.printStackTrace();
Log.i(LOG_Error, "文件夾創建錯誤 TestFilePathExternalData()" + e.getMessage());
}
}
} else
Log.i(LOG_Error, "沒有掛載SD卡或是沒有打開權限");
return (pulicfileDir + File.separator + filesname); //返回的是文件的目錄
}
上面的這種方式 數據不會隨着的app的生命週期而變換,一直會存在,只能去手動刪除
/**
* @Function: 外部SD卡
* @attention: 注意getExternal 和 SD 卡是不一樣的 這種騷氣的寫法,在我的開發板上測試可以,但是強烈不推薦大家去使用
* @Return:
*/
private void TestFilePathSDCard() {
File fileDir1 = new File("/mnt/sdcard/SQLite1"); //這是內部掛載的SD卡 和 公共的是同級目錄,無法靠代碼獲取,經驗
File fileDir2 = new File("/mnt/sdcard2/SQLite2"); //這是外部插卡式的SD卡,ARM板上支持,絕大部分手機已經涼了
fileDir1.mkdir();
fileDir2.mkdir();
}
上面的這種方式 數據存儲在 黑色的插卡的SD卡中,氣自求多福,不同的手機的路徑是不一樣的。而且無法用代碼獲取
你非要用 用手機找到 那個目錄——————>找到屬性--->查看路徑 ----> 將路徑複製到 代碼去使用,,,理論上是可以的,我試過。
IO流文件數據的讀寫操作 基本上常用的方法都有了
/**
* @param content: 要寫的內容
* @param filedirname 文件夾的名字
* @param filename: 文件的名字
* @param mode: 以什麼方式往裏面去寫 0 1 2 3
* @param ways: 兩種方式 Buffer RandomAccessFile Print 0 1 2
* @Function: 將content寫到指定的文件的指定的目錄下去
* @Return:
*/
private void WriteDataToStorage(String content, String filedirname, String filename, int mode, int ways) {
String FileName = filedirname + File.separator + filename; //拼接字符串 文件的存儲路徑
File subfile = new File(FileName); //文件夾路徑和文件路徑 判斷文件是否存在
if (subfile.exists()) {
subfile.setWritable(true);
boolean readable = subfile.canRead();
boolean writeable = subfile.canWrite();
Log.i(LOG_Info, "文件創建成功" + "readable:" + readable + " writeable:" + writeable);
} else {
try {
subfile.createNewFile();
} catch (IOException e) {
Log.i(LOG_Error, "文件創建出錯 " + e.getMessage());
e.printStackTrace();
}
}
int Context_Mode = mode;
int Ways = ways;
if (Context_Mode == 0) {
Context_Mode = Context.MODE_PRIVATE; //該文件只能被當前程序讀寫。
} else if (Context_Mode == 1) {
Context_Mode = Context.MODE_APPEND; //以追加方式打開該文件,應用程序可以向該文件中追加內容。
} else if (Context_Mode == 2) {
Context_Mode = Context.MODE_WORLD_READABLE; //該文件的內容可以被其他應用程序讀取。
} else if (Context_Mode == 3) {
Context_Mode = Context.MODE_WORLD_WRITEABLE; //該文件的內容可由其他程序讀、寫。
} else {
Context_Mode = Context.MODE_WORLD_WRITEABLE; //省的煩 反正都可以讀
}
if (Ways == 0) {
Log.i(LOG_Info, "BufferWriter");
FileOutputStream fileOutputStream = null;
BufferedWriter bufferedWriter = null;
OutputStreamWriter outputStreamWriter = null;
try {
//fileOutputStream = openFileOutput(FileName, Context_Mode); contains a path separator 報錯
fileOutputStream = new FileOutputStream(subfile);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream, "utf-8")); //解決輸入中文的問題
bufferedWriter.write(content + "\t");
bufferedWriter.flush();
bufferedWriter.close();
//outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8"); //兩種方式都可以
//outputStreamWriter.write(content);
//outputStreamWriter.flush();
//outputStreamWriter.close();
} catch (Exception e) {
e.printStackTrace();
Log.i(LOG_Error, "寫入數據出錯 " + e.getMessage());
} finally {
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else if (Ways == 1) {
Log.i(LOG_Info, "RandomAccessFile");
try {
RandomAccessFile raf = new RandomAccessFile(subfile, "rw");
raf.seek(subfile.length());
raf.write(content.getBytes());
raf.close();
} catch (Exception e) {
e.printStackTrace();
Log.i(LOG_Error, "寫入數據出錯 " + e.getMessage());
}
} else if (Ways == 2) {
Log.i(LOG_Info, "Printer");
try {
FileOutputStream fileoutputStream = new FileOutputStream(subfile);
//openFileOutput("text2", Context.MODE_PRIVATE);
PrintStream ps = new PrintStream(fileoutputStream);
ps.print(content + "\t");
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else
Ways = 0;
}
/**
* @param fileDirName: 文件夾的路徑
* @Function: 列出文件夾下所有文件的名字
* @Return:
*/
private File[] ListFileDirName(String fileDirName) {
File fileDir = new File(fileDirName);
File[] files = new File[0];
if (fileDir.isDirectory()) {
files = fileDir.listFiles();
}
for (File a : files) { //可以利用適配器做成界面 完成爲了玩沒意思
Log.i(LOG_Info, a.toString());
}
return files;
/* /storage/emulated/0/Documents/SQLite/abcd.txt 手機的測試結果
/mnt/internal_sd/Documents/SQLite/abcd.txt ARM板的測試結果*/
}
/**
* @param fileDirName:文件夾目錄
* @param fileName:文件名字
* @param ways:讀取文件的方式
* @Function: 從存儲路徑中讀出數據
* @Return:
*/
private void ReadDataFromStorage(String fileDirName, String fileName, int ways) throws IOException {
File file = new File(fileDirName, fileName);
int Ways = ways;
if (Ways == 0) {
Log.i(LOG_Info, "FileInputStream");
try {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
String result = new String(bytes);
Log.i(LOG_Info, "讀取的內容是:" + result);
} catch (Exception e) {
e.printStackTrace();
}
} else if (Ways == 1) { //最好使用 Buffer 緩衝流,安全機制 大量的文件
Log.i(LOG_Info, "Bufferreader");
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String readline = "";
StringBuffer stringBuffer = new StringBuffer();
while ((readline = bufferedReader.readLine()) != null) {
stringBuffer.append(readline);
}
if (bufferedReader != null) {
bufferedReader.close();
Log.i(LOG_Info, "讀取的內容是:" + stringBuffer);
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (Ways == 2) {
Log.i(LOG_Info, "Input+Buffer");
try {
String fileContent = null;
InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
BufferedReader reader = new BufferedReader(read);
String line;
while ((line = reader.readLine()) != null) {
fileContent += line;
}
reader.close();
read.close();
Log.i(LOG_Info, fileContent);
} catch (Exception e) {
e.printStackTrace();
Log.i(LOG_Error, e.getMessage());
}
} else
Ways = 2;
}
/**
* @param file: 文件/文件夾的路徑
* @Function: 文件夾 文件的刪除
* @Return:
*/
private void DeleteFileDirORFile(File file) {
if (file.exists() == false) {
return;
} else {
if (file.isFile()) {
file.delete();
return;
}
if (file.isDirectory()) {
File[] childFile = file.listFiles();
if (childFile == null || childFile.length == 0) {
return;
}
if (childFile.length > 1) {
for (File f : childFile) {
DeleteFileDirORFile(f);
}
}
}
}
}
我想到的 IO 流的讀取方式都在這了,,親測可以使用,能力有限,漏的方法,大家自行百度,網絡數據的請求,請參考另外一篇博客 httpClient 的請求,和第三方框架的使用。
四、sharedPreference 存儲
使用與小數據的讀取,理論的操作方式,網上一搜一大堆,我只貼代碼
//從 SharedPreferences在中讀出數據
private void ReadFromSharedPrefernces() {
// 讀取字符串數據
String time = preferences.getString("time", null);
// 讀取int類型的數據
int randNum = preferences.getInt("random", 0);
String result = time == null ? "您暫時還未寫入數據" : "寫入時間爲:"
+ time + "\n上次生成的隨機數爲:" + randNum;
// 使用Toast提示信息
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
}
//往SharedPreferences中寫入數據
private void WriteToSharedPrefernces() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 "
+ "hh:mm:ss");
// 存入當前時間
editor.putString("time", sdf.format(new Date())); // 存入一個隨機數
editor.putInt("random", (int) (Math.random() * 100));
// 提交所有存入的數據
editor.commit();
}
sharedPrefernces的存儲方式和 map是一樣的,存儲爲 .xml 文件,大家可以在這個目錄下找到
DeviceFileExplorer:
找不到的,跟權限有關
五、SQLite的存儲方式
數據的存儲方式,我使用的 xUtils的第三方框架,具體的使用看我另外一篇博客 SQLite 的使用方法,在我的github上可以找到具體的SQLite和ROS的實戰項目。更加利用大家的學習,這邊只給出代碼。大家可以下載。
六、assets的存儲方式
assets 目錄可以繼續建立 多個子文件夾 注意建立後修改路徑
/**
* @param fileName: 文件名字
* @param index:文件類型 文本 圖片 音樂 0 1 2
* @Function: 讀取 Assets下的文件
* @Return:
*/
public void getTextFromAssets(String fileName, int index) {
if (index == 0) { //文本操作
String Result = "";
try {
InputStreamReader inputReader = new InputStreamReader(getResources().getAssets().open(fileName));
BufferedReader bufReader = new BufferedReader(inputReader);
String line = "";
while ((line = bufReader.readLine()) != null)
Result += line;
Log.i(LOG_Info + "Assets", Result);
} catch (Exception e) {
e.printStackTrace();
}
} else if (index == 1) { //圖片操作
Bitmap bitmap = null;
InputStream is = null;
try {
is = getAssets().open(fileName);
bitmap = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
}
DC_ImageViewShow = (ImageView) findViewById(R.id.DC_ImageViewShow);
DC_ImageViewShow.setImageBitmap(bitmap);
} else if (index == 2) { //音樂操作
try {
// 打開指定音樂文件,獲取assets目錄下指定文件的AssetFileDescriptor對象
AssetFileDescriptor afd = assetManager.openFd(fileName);
mPlayer.reset();
// 使用MediaPlayer加載指定的聲音文件。
mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
// 準備聲音
mPlayer.prepare();
// 播放
mPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
} else
Log.i(LOG_Error, "ERROR");
}
七、res的存儲方式
相信 findbyId 沒有人不會吧。
八、raw的存儲方式
public String getTextFromRaw() {
String Result = "";
try {
InputStreamReader inputReader = new InputStreamReader(getResources().openRawResource(R.raw.abc));
BufferedReader bufReader = new BufferedReader(inputReader);
String line = "";
while ((line = bufReader.readLine()) != null)
Result += line;
Log.i(LOG_Info + "Raw", Result);
} catch (Exception e) {
e.printStackTrace();
}
return Result;
}
總結: Android 上面所有的文件操作都在這裏了,註釋很詳細了,大家可以下載 github上面的代碼,網址: https://github.com/KEYD111/AndroidFileOperation
好好去研究,不要怕麻煩,因爲小編以前也是每次寫代碼,Ctrl + c ctrl +v 人家的代碼,這個不行,換一個,往往不知道問題出在哪裏,大家用的時候,可以將路徑直接放到 read和writer裏面去,我這樣寫,純粹是爲了對比給大家看。 比較的學習,我一直認爲是比較好用。
謝謝大家,錯誤之處 還望不吝賜教。