Android的檔案操作
從應用資料目錄下可以看出,資料檔案可以分成兩類,一類是放置在擴充儲存空間中的檔案,即/sdcard/目錄下的檔案,它們可以被各個應用共用;而另一類則是放在該應用資料目錄下檔案,它們僅能被各個應用獨享,不能被其他應用讀寫。
(1)擴充儲存空間中的檔案讀寫方式跟標準的java檔案處理無異。
我們可以建立一個FileUtil的工具類來協助我們處理檔案的I/O操作,首先我們先判斷SD卡的狀態,看看SD卡是否可用,還有多少可用容量等。建立一個FileUtil的Class,加入方法
1 // =================get SDCard information=================== 2 public static boolean isSdcardAvailable() { 3 String status = Environment.getExternalStorageState(); 4 //Environment.MEDIA_MOUNTED表示SD卡正常掛載 5 if (status.equals(Environment.MEDIA_MOUNTED)) { 6 return true; 7 } 8 return false; 9 }10 11 public static long getSDAllSizeKB() {12 //sd卡的位置13 File path = Environment.getExternalStorageDirectory();14 //StatFs擷取的都是以block為單位的15 StatFs sf = new StatFs(path.getPath());16 // 得到單個block的大小17 long blockSize = sf.getBlockSize();18 // 擷取所有資料區塊數19 long allBlocks = sf.getBlockCount();20 // 返回SD卡大小21 return (allBlocks * blockSize) / 1024; // KB22 }23 24 /**25 * free size for normal application26 * @return27 */28 public static long getSDAvalibleSizeKB() {29 File path = Environment.getExternalStorageDirectory();30 StatFs sf = new StatFs(path.getPath());31 long blockSize = sf.getBlockSize();32 long avaliableSize = sf.getAvailableBlocks();33 return (avaliableSize * blockSize) / 1024;// KB34 }Environment.getExternalStorageDirectory()表示擷取擴充儲存空間的目錄。(建議使用此方法動態擷取,因為sdcard這個目錄路徑是可配置的)
StatFs.getBlockSize在API18後變為StatFs.getBlockSizeLong,其他類似的getBlock方法也一樣,關於StatFs,詳情可以看這篇博文
然後在activity中的button1加入事件
case R.id.button1: { Log.d("TEST", "sdcard?"+FileUtil.isSdcardAvailable()); Log.d("TEST", "全部容量"+(float)FileUtil.getSDAllSizeKB()/1024/1024); Log.d("TEST", "可用容量"+(float)FileUtil.getSDAvalibleSizeKB()/1024/1024); Toast.makeText(this, "status", Toast.LENGTH_SHORT).show(); break; }運行結果如下
接下來我們來判斷某個檔案夾是否存在在SD卡中以及建立一個檔案夾
/** * @param director 檔案夾名稱 * @return */ public static boolean isFileExist(String director) { File file = new File(Environment.getExternalStorageDirectory() + File.separator + director); return file.exists(); } /** * create multiple director * @param path * @return */ public static boolean createFile(String director) { if (isFileExist(director)) { return true; } else { File file = new File(Environment.getExternalStorageDirectory() + File.separator + director); if (!file.mkdirs()) { return false; } return true; } }其中File.separator是表示分隔字元,在不同作業系統下是不同的,如windows就是代表"/",而在Linux下卻是代表"\"。所以介意使用File.separator來代替分隔字元。File.mkdirs()表示建立一個檔案夾,且可附帶建立父目錄,而mkdir()不行,詳情的File大家可以查看官方文檔,或者看看這篇博文
然後在activity中的button2加入響應事件
case R.id.button2: { Log.d("TEST", "example檔案夾存在?"+FileUtil.isFileExist("example")); Log.d("TEST", "建立forexample檔案夾"+FileUtil.createFile("forexample")); Toast.makeText(this, "IsFile", Toast.LENGTH_SHORT).show(); break; } 運行後可以看到
我們會發現在手機的sdcard目錄下建立了一個forexample的檔案夾。
最後我們來實現檔案的讀和寫
寫:
/** * * @param director * (you don‘t need to begin with * Environment.getExternalStorageDirectory()+File.separator) * @param fileName * @param content * @param encoding * (UTF-8...) * @param isAppend * : Context.MODE_APPEND * @return */ public static File writeToSDCardFile(String directory, String fileName, String content, String encoding, boolean isAppend) { // mobile SD card path +path File file = null; OutputStream os = null; try { if (!createFile(directory)) { return file; } file = new File(Environment.getExternalStorageDirectory() + File.separator + directory + File.separator + fileName); os = new FileOutputStream(file, isAppend); if (encoding.equals("")) { os.write(content.getBytes()); } else { os.write(content.getBytes(encoding)); } os.flush(); } catch (IOException e) { Log.e("FileUtil", "writeToSDCardFile:" + e.getMessage()); } finally { try { if (os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } } return file; } /** * write data from inputstream to SDCard */ public File writeToSDCardFromInput(String directory, String fileName, InputStream input) { File file = null; OutputStream os = null; try { if (createFile(directory)) { return file; } file = new File(Environment.getExternalStorageDirectory() + File.separator + directory + File.separator + fileName); os = new FileOutputStream(file); byte[] data = new byte[bufferd]; int length = -1; while ((length = input.read(data)) != -1) { os.write(data, 0, length); } // clear cache os.flush(); } catch (Exception e) { Log.e("FileUtil", "" + e.getMessage()); e.printStackTrace(); } finally { try { os.close(); } catch (Exception e) { e.printStackTrace(); } } return file; }從上面可以看到有兩種寫入的方法,一種是將字串直接寫入,另一種是將資料流寫到檔案中。還有一點要提的是file的預設目錄就是sdcard的目錄,所以開頭不必每次都要加sdcard的目錄路徑。
FileOutputStream(file, isAppend) 兩個參數,左邊是File檔案,而右邊是一個boolean值,為true時,資料將會接在原來檔案的後面寫入,而false是則會覆蓋。
讀:
public static String ReadFromSDCardFile(String directory,String fileName){ String res=""; File file = null; file = new File(Environment.getExternalStorageDirectory() + File.separator + directory + File.separator + fileName); try { FileInputStream fis = new FileInputStream(file); int length = fis.available(); byte [] buffer = new byte[length]; fis.read(buffer);
//將位元組按照編碼格式轉成字串 res = EncodingUtils.getString(buffer, "UTF-8"); fis.close(); return res; }catch (FileNotFoundException e) { // TODO Auto-generated catch block Log.d("TEST", "FileNotFound"); e.printStackTrace(); }catch (Exception e) { Log.d("TEST", "Can Not Open File"); e.printStackTrace(); } return null; }編碼預設是UTF-8,若是想要改變的話,將其作為參數傳入就行。
Activity中在按鈕中加入響應
case R.id.button3: { FileUtil.writeToSDCardFile("forexample", "test.txt", editText.getText().toString(), "UTF-8", true); Toast.makeText(this, "WriteFile", Toast.LENGTH_SHORT).show(); break; } case R.id.button4: { textView.setText(FileUtil.ReadFromSDCardFile("forexample", "test.txt")); Toast.makeText(this, "ReadFile", Toast.LENGTH_SHORT).show(); break; }在文字編輯框上寫入“我是cpacm”,先點擊writefile按鈕,再點擊ReadFile,得到運行結果
同時在根目錄下的forexample檔案夾裡會找到test.txt,裡面有著“我是cpacm”的一行字。到此,檔案的讀寫成功。
(2)放在該應用資料目錄下的檔案讀寫
儲存在應用目錄下的私人資料目錄,通常不會通過File類的方式直接讀寫,而是利用一些封裝過的類或函數來操作。一般可以通過Context.openFileOutput來執行。
在Activity加入兩個方法,分別為檔案的讀和寫
public void writeFile(String fileName,String writestr){ try{ FileOutputStream fout =openFileOutput(fileName,MODE_PRIVATE); byte [] bytes = writestr.getBytes(); fout.write(bytes); fout.close(); } catch(Exception e){ e.printStackTrace(); } } //讀資料 public String readFile(String fileName){ String res=""; try{ FileInputStream fin = openFileInput(fileName); int length = fin.available(); byte [] buffer = new byte[length]; fin.read(buffer); res = EncodingUtils.getString(buffer, "UTF-8"); fin.close(); } catch(Exception e){ e.printStackTrace(); } return res; }同時在按鈕的響應中加入
case R.id.button5: { writeFile("test2.txt",editText.getText().toString()); Toast.makeText(this, "WritePrivateFile", Toast.LENGTH_SHORT).show(); break; } case R.id.button6: { textView.setText(readFile("test2.txt")); Toast.makeText(this, "ReadPrivateFile", Toast.LENGTH_SHORT).show(); break; }跟上張一樣。
最後不要忘記在設定檔中聲明許可權
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />