Android文件操作,數據讀寫,數據存儲,存儲路徑,一篇全部搞定

       得學會寫博客,以前是覺得逼格,現在發現是爲了總結自己的所學,項目做完了不代表會了,東西學完了不代表懂了。總結之後不會、不懂也無所謂,自己的接口調了就行了。當然了,啪啦啪啦,寫完做完還不會的,我也不想說什麼。看完這篇不會,下次就直接調我的接口吧。代碼已經上傳到 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裏面去,我這樣寫,純粹是爲了對比給大家看。 比較的學習,我一直認爲是比較好用。

謝謝大家,錯誤之處 還望不吝賜教。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章