Android - R / W на съемную SD-карту

Вы можете сделать что-то вроде этого ...

#include<iostream>

using namespace std;

//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            *(a+ i*rows + j)+=10.0;
        }
    }
}

//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
    cout<<"Printing your array...\n";
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            cout<<*(a+ i*rows + j)<<"  ";
        }
    cout<<"\n";
    }
}

int main(){
    //declare and initialize your array
    double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};

    //the 1st argument is the address of the first row i.e
    //the first 1D array
    //the 2nd argument is the no of rows of your array
    //the 3rd argument is the no of columns of your array
    myFunc(a[0],2,2);

    //same way as myFunc
    printArray(a[0],2,2);

    return 0;
}

Ваш выход будет следующим:

11.5  12.5
13.5  14.5
0
задан Fely 3 March 2019 в 19:38
поделиться

1 ответ

Начиная с API 19 (KitKat) почти невозможно напрямую записать содержимое SDcard как простое File, потому что они смонтированы как ТОЛЬКО ЧТЕНИЕ, по крайней мере, для пользователя по умолчанию (система все еще может писать в него).

DocumentsProvider API довольно запутанный (даже образец в документах трудно читаемый), поэтому было добавлено DocumentFile для имитации поведения File для более легкого доступа.

Предполагая, что пользователь уже предоставил разрешения на чтение / запись для хранения, нам нужно получить URI документа корневого каталога SDcard (в Activity):

var sdCardUri : Uri? = null

private fun requestSDCardPermissions(){
    if(Build.VERSION.SDK_INT < 24){
        startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), REQ_PICK_DIRECTORY)
        return
    }
    // find removable device using getStorageVolumes
    val sm = getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val sdCard = sm.storageVolumes.find { it.isRemovable }
    if(sdCard != null){
        startActivityForResult(sdCard.createAccessIntent(null), REQ_SD_CARD_ACCESS)
    }
}

Перед тем, как пользователю API 24 нужно открыть средство выбора документов и вручную выберите SD-карту сами. Это не идеально, но команда Android упустила из виду тот факт, что отсутствует API SD-карт.

В более новой версии getStorageVolumes() позволяет нам находить SD-карту через код и отображать только явное предупреждение пользователю о том, что к нему будет произведен доступ. Это НЕ тот же диалог, что и у разрешения на чтение / запись.

Теперь для обработки полученного Uri нам нужно только взять data.data результата. Это может быть хорошим местом для сохранения его в общих настройках, чтобы не просить пользователя снова и снова:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if(requestCode == REQ_SD_CARD_ACCESS || requestCode == REQ_PICK_DIRECTORY){
        if(resultCode == RESULT_OK) {
            if(data == null){
                Log.e(TAG, "Error obtaining access")
            }else{
                sdCardUri = data.data
                Log.d("StorageAccess", "obtained access to $sdCardUri")
                // optionally store uri in preferences as well here { ... }
            }
        }else
            Toast.makeText(this, "access denied", Toast.LENGTH_SHORT).show()
        return
    }
    super.onActivityResult(requestCode, resultCode, data)
}

Я пропущу большинство проверок ошибок / проверок существующих файлов, но теперь вы можете использовать полученные sdCardUri ] вот так (копирование файла «sample.txt» из корня внутреннего хранилища в корень SDcard):

private fun copyToSDCard(){
    val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
    val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
    // get or create file
    val sdCardFile = sdCardRoot.findFile("sample.txt") ?: sdCardRoot.createFile(null, "sample.txt")
    val outStream = contentResolver.openOutputStream(sdCardFile.uri)
    outStream.write(internalFile.readBytes())
    outStream.flush()
    outStream.close()
    Toast.makeText(this, "copied to SDCard", Toast.LENGTH_SHORT).show()
}

И наоборот (из SDcard во внутреннее хранилище):

private fun copyToInternal(){
    val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
    val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
    val sdCardFile = sdCardRoot.findFile("sample.txt")
    val inStream = contentResolver.openInputStream(sdCardFile.uri)
    internalFile.writeBytes(inStream.readBytes())
    inStream.close()
    Toast.makeText(this, "copied to internal", Toast.LENGTH_SHORT).show()
}
0
ответ дан Pawel 3 March 2019 в 19:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: