●補充說明和程式說明
(一)讀寫外部空間資料--在規劃好的資料夾中
1.寫入
=>用android device moniter看檔案位置會在如下圖的地方,這裡不需要使用權限,但當別的程式有完整讀取sd卡的權限時,就可以讀取到這邊的檔案,隱私性安全較差
讀寫外部資料與設定讀寫外部資料權限
public void outWrite(View view) {
    String path = getExternalFilesDir("file").getAbsolutePath();
    String fname=path + File.separator "test1.txt";
    try {
        FileWriter fw = new FileWriter(fname);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write("happy to find you");
        bw.newLine();
        bw.write("it is sad");
        bw.close();
        fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
**說明:
1. 取得外部存檔的資料夾位置:getExternalFilesDir(檔案類型):參數的檔案類型可以自訂
=>File getExternalFilesDir (String type)
=>Returns absolute paths to application-specific directories on all shared/external storage devices where the application can place persistent files it owns.
2.後面做法都跟之前(BufferReader and BufferWriter)一樣
 
2.讀取
public void outRead(View view) {
String path = getExternalFilesDir("file").getAbsolutePath();
String fname=path + File.separator + "test1.txt";
try {
FileReader fr = new FileReader(fname);
BufferedReader br = new BufferedReader(fr);
String str;
while ((str=br.readLine()) != null)
{
Log.d("FNAME", "Read:" + str);
}
br.close();
fr.close();
 
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
 
(二)讀寫外部空間資料(自由的尋覽sd卡)
=>但現在android不建議如此做,基於隱私的考量以及避免在外部空間製造很多垃圾
=>先在AndroidManifest.xml設定權限(只要想要存取規劃的資料夾外的資料都要設定權限)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
1.android6(api<23)以前的寫入
File f = Environment.getExternalStorageDirectory();
Log.d("FNAME","read"+f.getAbsolutePath());
File f2 = new File(f.getAbsolutePath() 
              + File.separator "mydata");
f2.mkdir();
File txtFile = new File(f2.getAbsolutePath() 
                 + File.separator "data5.txt");
try {
    FileWriter fw = new FileWriter(txtFile);
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write("this is test");
    bw.newLine();
    bw.write("This is test2");
    bw.close();
    fw.close();
catch (IOException e) {
    e.printStackTrace();
}
**說明
1.Environment.getExternalStorageDirectory():取得sd卡路徑
=>File getExternalStorageDirectory ()
=>Return the primary shared/external storage directory.
=>前面兩筆是使用getExternalFilesDir("file").getAbsolutePath();取得的路徑=>是android指定的不需要授權的資料夾
=>後面一筆是使用Environment.getExternalStorageDirectory().getAbsolutePath();取得的路徑
 讀寫外部資料與設定讀寫外部資料權限
 
2.mkdir()=>Creates the directory named by this abstract pathname.(建立資料夾mydata)
3.建立資料夾內容
4.android6以前的權限設定如上即可,使用早期版本的模擬器測試,只要有上面權限設定,寫入後就會在sdcard資料夾中產生我們要的資料夾
讀寫外部資料與設定讀寫外部資料權限
 
 
2.android6(api<23)以前的讀取
File f = Environment.getExternalStorageDirectory();
Log.d("FNAME", f.getAbsolutePath());
File f2 = new File(f.getAbsolutePath() 
           + File.separator "mydata");
File txtFile = new File(f2.getAbsolutePath() 
          + File.separator "data5.txt");
try {
    FileReader fr = new FileReader(txtFile);
    BufferedReader br = new BufferedReader(fr);
    String str;
    while ((str=br.readLine()) != null)
    {
        Log.d("FNAME""Read:" + str);
    }
    br.close();
    fr.close();
 
catch (FileNotFoundException e) {
    e.printStackTrace();
catch (IOException e) {
    e.printStackTrace();
}
**說明:
1.當使用android6以後的模擬器,只在AndroidManifest.xml設定權限會不夠,用android6以後的模擬器測試這段讀取程式,就會出現下列exception:FileNotFoundException,因為在android6以後的模擬器寫入不成功,所以也讀不到檔案
讀寫外部資料與設定讀寫外部資料權限
2.做法有兩種一種是讓使用者自己設定,在手機=>設定=>app設定=>app permisssions=>storage permissions=>我們app開啟讀寫外部資料與設定讀寫外部資料權限
但這是不好的做法,應該是把設定寫在程式裡
 
3.android6以後的寫入與讀取
=>程式的流程應該是在每次要使用時,都會檢查程式是否有被授予權限,如果沒有就要跳出視窗詢問使用者是否授予權限,且這個跳出的視窗是android訂好的規格,我們不能改變或自訂
=>使用者決定允許或拒絕後,callback結果
=>參考檔案可以發現WRITE和READ是同一類權限,有開WRITE則READ就會有開
=>實際上讀取應該也要加權限,否則若是還沒有授權寫入或是被取消授權後直接按讀取就會有問題
 public void nolimitwrite(View view) {
    int permission = ActivityCompat.checkSelfPermission(this,
            WRITE_EXTERNAL_STORAGE);
    if (permission != PackageManager.PERMISSION_GRANTED) {
        //未取得權限,向使用者要求允許權
       //因為要辨別使用者允許的是寫入還是讀取所以這邊的string只放write
        ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE},
                REQUEST_EXTERNAL_STORAGE); 
    }else{
        //已有權限,可進行檔案存取
        sdwrite();

    }
}

@Override
public void onRequestPermissionsResult
    (int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode==REQUEST_EXTERNAL_STORAGE){
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //取得權限,進行檔案存取
            String str=permissions[0];
             //這邊用if判斷時要用equals(),不能用==
            if(str.equals("android.permission.WRITE_EXTERNAL_STORAGE") ){  
                sdwrite();
            }else {
                sdread();
            }

        } else {
            //使用者拒絕權限,停用檔案存取功能
        }
    }
}

private void sdwrite(){
    File f = Environment.getExternalStorageDirectory();
    Log.d("FNAME","read"+f.getAbsolutePath());
    File f2 = new File(f.getAbsolutePath() + File.separator + "mydata");
    f2.mkdir();
    File txtFile = new File(f2.getAbsolutePath() + File.separator + "data5.txt");
    try {
        FileWriter fw = new FileWriter(txtFile);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write("this is test");
        bw.newLine();
        bw.write("This is test2");
        bw.close();
        fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void nolimitread(View view) {
    int permission = ActivityCompat.checkSelfPermission(this,
            READ_EXTERNAL_STORAGE);
    if (permission != PackageManager.PERMISSION_GRANTED) {
        //未取得權限,向使用者要求允許權
        ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE},
                REQUEST_EXTERNAL_STORAGE);
    }else{
        //已有權限,可進行檔案存取
        sdread();
    }
}

private void sdread(){
    File f = Environment.getExternalStorageDirectory();
    Log.d("FNAME", f.getAbsolutePath());
    File f2 = new File(f.getAbsolutePath() + File.separator + "mydata");
    File txtFile = new File(f2.getAbsolutePath() + File.separator + "data5.txt");
    try {
        FileReader fr = new FileReader(txtFile);
        BufferedReader br = new BufferedReader(fr);
        String str;
        while ((str=br.readLine()) != null)
        {
            Log.d("FNAME", "Read:" + str);
        }
        br.close();
        fr.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
**說明
1.先檢查是否已經取得使用者的授權,檢查權限語法:int checkSelfPermission(Context context, String permission)
=>Determine whether you have been granted a particular permission.
=>String: The name of the permission being checked.
=>return int:PERMISSION_GRANTED if you have the permission, or PERMISSION_DENIED if not.
=>PackageManager.PERMISSION_GRANTED
int PERMISSION_GRANTED
Permission check result: this is returned by checkPermission(String, String) if the permission has been granted to the given package.
Constant Value: 0 (0x00000000)
=>PackageManager.PERMISSION_DENIED
int PERMISSION_DENIED
Permission check result: this is returned by checkPermission(String, String) if the permission has not been granted to the given package.
Constant Value: -1 (0xffffffff)
 
2.如果沒有取得權限,跳出允許授權對話框
=>requestPermissions:void requestPermissions (Activity activity, String[] permissions, int requestCode)
=>第一個參數是context,第二個參數是要求允許的權限,第三個參數是本次請求的辨識編碼(因為callback時要辨認是哪裡callback的)
=>因為後面要辨別這邊帶入的權限是write還是read,所以兩個click放的參數不同
 
3.把寫入和讀取的程式寫成兩個method,當授權ok或是已經有授權的時候直接呼叫這兩個方法
 
4.當跳出授權對話框後,對使用者的確認與取消授權做處理,用onRequestPermissionsResult
=>void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)
Callback for the result from requesting permissions. 
=>requestCodeint: The request code passed in requestPermissions(android.app.Activity, String[], int)
=>permissionsString: The requested permissions. Never null.
=>grantResultsint: The grant results for the corresponding permissions which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null.
 
5.先確認requestCode正確,再確認授權結果必須為GRANTED,再判斷傳回的permission為哪一個,來決定下一步是要寫入還是讀取,這邊的permissions陣列判斷不可以用==而是要用equals,因為在前面有new String,是不同物件不能用==,==兩邊必須是相同的參考物件,相關資訊可以參考說明:https://ppt.cc/fam5fx
 
6.如果想要查詢pemissions字串中的內容,可以用log看
Log.d("permission","read:"+permissions[0]);
讀寫外部資料與設定讀寫外部資料權限
 

 

●程式參考(GitHub):讀寫外部資料與設定讀寫外部資料權限

 

arrow
arrow

    muchone 發表在 痞客邦 留言(0) 人氣()