Skip to content Skip to sidebar Skip to footer

Create/copy File In Android Q Using Mediastore

I am trying to find method which can handle create and copy of any file except Media files (Picture/Video/Audio) to copy from one place to other in internal storage in Android Q. I

Solution 1:

1. Create and Write File

createAndWriteButton.setOnClickListener(newView.OnClickListener() {
    @OverridepublicvoidonClick(View view) {
        try {
            ContentValuesvalues=newContentValues();

            values.put(MediaStore.MediaColumns.DISPLAY_NAME, "menuCategory");       //file name                     
            values.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain");        //file extension, will automatically add to file
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS + "/Kamen Rider Decade/");     //end "/" is not mandatoryUriuri= getContentResolver().insert(MediaStore.Files.getContentUri("external"), values);      //important!OutputStreamoutputStream= getContentResolver().openOutputStream(uri);

            outputStream.write("This is menu category data.".getBytes());

            outputStream.close();

            Toast.makeText(view.getContext(), "File created successfully", Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            Toast.makeText(view.getContext(), "Fail to create file", Toast.LENGTH_SHORT).show();
        }
    }
});

2. Find and Read File

findAndReadButton.setOnClickListener(newView.OnClickListener() {
    @OverridepublicvoidonClick(View view) {
        UricontentUri= MediaStore.Files.getContentUri("external");

        Stringselection= MediaStore.MediaColumns.RELATIVE_PATH + "=?";

        String[] selectionArgs = newString[]{Environment.DIRECTORY_DOCUMENTS + "/Kamen Rider Decade/"};

        Cursorcursor= getContentResolver().query(contentUri, null, selection, selectionArgs, null);

        Uriuri=null;

        if (cursor.getCount() == 0) {
            Toast.makeText(view.getContext(), "No file found in \"" + Environment.DIRECTORY_DOCUMENTS + "/Kamen Rider Decade/\"", Toast.LENGTH_LONG).show();
        } else {
            while (cursor.moveToNext()) {
                StringfileName= cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));

                if (fileName.equals("menuCategory.txt")) {
                    longid= cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));

                    uri = ContentUris.withAppendedId(contentUri, id);

                    break;
                }
            }

            if (uri == null) {
                Toast.makeText(view.getContext(), "\"menuCategory.txt\" not found", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    InputStreaminputStream= getContentResolver().openInputStream(uri);

                    intsize= inputStream.available();

                    byte[] bytes = newbyte[size];

                    inputStream.read(bytes);

                    inputStream.close();

                    StringjsonString=newString(bytes, StandardCharsets.UTF_8);

                    AlertDialog.Builderbuilder=newAlertDialog.Builder(view.getContext());

                    builder.setTitle("File Content");
                    builder.setMessage(jsonString);
                    builder.setPositiveButton("OK", null);

                    builder.create().show();
                } catch (IOException e) {
                    Toast.makeText(view.getContext(), "Fail to read file", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
});

3. Find and Overwrite File

findAndWriteButton.setOnClickListener(newView.OnClickListener() {
    @OverridepublicvoidonClick(View view) {
        UricontentUri= MediaStore.Files.getContentUri("external");

        Stringselection= MediaStore.MediaColumns.RELATIVE_PATH + "=?";

        String[] selectionArgs = newString[]{Environment.DIRECTORY_DOCUMENTS + "/Kamen Rider Decade/"};    //must include "/" in front and endCursorcursor= getContentResolver().query(contentUri, null, selection, selectionArgs, null);

        Uriuri=null;

        if (cursor.getCount() == 0) {
            Toast.makeText(view.getContext(), "No file found in \"" + Environment.DIRECTORY_DOCUMENTS + "/Kamen Rider Decade/\"", Toast.LENGTH_LONG).show();
        } else {
            while (cursor.moveToNext()) {
                StringfileName= cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));

                if (fileName.equals("menuCategory.txt")) {                          //must include extensionlongid= cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));

                    uri = ContentUris.withAppendedId(contentUri, id);

                    break;
                }
            }

            if (uri == null) {
                Toast.makeText(view.getContext(), "\"menuCategory.txt\" not found", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    OutputStreamoutputStream= getContentResolver().openOutputStream(uri, "rwt");      //overwrite mode, see below

                    outputStream.write("This is overwritten data。\n你就不要想起我。".getBytes());

                    outputStream.close();

                    Toast.makeText(view.getContext(), "File written successfully", Toast.LENGTH_SHORT).show();
                } catch (IOException e) {
                    Toast.makeText(view.getContext(), "Fail to write file", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
});

Demo: https://www.youtube.com/watch?v=idsUMiWjfnM

Hope this may help you.

Solution 2:

As you mentioned Environment.getExternalStoragePublicDirectory is marked deprecated. So there is no regular way to get the path to Downloads directory to save your file there. Alternatively you can use ACTION_CREATE_DOCUMENT to show path picker and then use returned uri to write file to selected location.

This is how to show picker:

// Request code for creating a document.constval CREATE_FILE = 1privatefuncreateFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "text/plain"
        putExtra(Intent.EXTRA_TITLE, "sam.txt")

        // Optionally, specify a URI for the directory that should be opened in// the system file picker before your app creates the document.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }
    startActivityForResult(intent, CREATE_FILE)
}

And this is how to get selected uri and write file:

overridefunonActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
    if (requestCode == CREATE_FILE && resultCode == Activity.RESULT_OK) {
        // The result data contains a URI for the document or directory that// the user selected.
        resultData?.data?.also { outputUri ->
            // Perform operations on the document using its URI.
            FileInputStream(inputFile).use { inputStream ->
                context.contentResolver.openFileDescriptor(outputUri, "w")?.use {
                    FileOutputStream(it.fileDescriptor).use { outputStream ->
                        FileUtils.copy(inputStream, outputStream)
                    }
                }
            }
        }
    }
}

More information can be found here.

EDIT:

To pick a directory to persist files ACTION_OPEN_DOCUMENT_TREE can be used. Then use takePersistableUriPermission method to take granted persistable permission to be able to use it after device restart. And then use DocumentFile to execute file operations.

Open directory request:

privatestaticfinalintOPEN_DIRECTORY_REQUEST_CODE=1;

voidopenDirectory() {
    Intentintent=newIntent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
    startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
}

Receive picked directory and take persistable permission:

@OverridepublicvoidonActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == OPEN_DIRECTORY_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        UridirectoryUri= data.getData();
        if (directoryUri == null)
            return;
        requireContext()
                .getContentResolver()
                .takePersistableUriPermission(directoryUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // persist picked uri to be able to reuse it later
    } elsesuper.onActivityResult(requestCode, resultCode, data);
}

And at last persist the file:

privatevoidpersistFile(@NonNull Uri directoryUri,
                         @NonNull File fileToPersist,
                         @NonNull String mimeType,
                         @NonNull String displayName) {
    DocumentFiledirFile= DocumentFile.fromSingleUri(requireContext(), directoryUri);
    if (dirFile != null) {
        DocumentFilefile= dirFile.createFile(mimeType, displayName);
        if (file != null) {
            UrioutputUri= file.getUri();
            try (ParcelFileDescriptorfd= requireContext().getContentResolver().openFileDescriptor(outputUri, "w")) {
                if (fd != null) {
                    try (FileInputStreaminputStream=newFileInputStream(fileToPersist)) {
                        try (FileOutputStreamoutputStream=newFileOutputStream(fd.getFileDescriptor())) {
                            FileUtils.copy(inputStream, outputStream);
                        }
                    }
                }
            } catch (Throwable th) {
                th.printStackTrace();
            }
        }
    }
}

Review this repo for an example of ACTION_CREATE_DOCUMENT usage.

Post a Comment for "Create/copy File In Android Q Using Mediastore"