hello again.
I want to backup my db from time to time. From the internal storage to my (installed) SD Card.
Like this:
I is it possible (mainly)
hello again.
I want to backup my db from time to time. From the internal storage to my (installed) SD Card.
Like this:
I is it possible (mainly)
Thank you very much Anke (Danke Anke)
So I copy the db-File to Download and then from there o the SD Card?
This should work, shouldn‘t it?
No.
(Was sollte das ändern?)
Hello Anke
I thought, that I bring the file to a ‚public‘ place and copy it thtn to the SD Card.
Wrong, wrong.
There is no way to write to the SD on Android 10or 14?
I am crying.
I was asking Gemini
How can we copy a file programmatically to an external removable sdcard on an Android device using target sdk 34? Please provide a Java snippet.
and the answer was
Ah, copying a file to a removable SD card programmatically with Target SDK 34 (Android 14) necessitates embracing the Storage Access Framework (SAF) for reliable and user-respecting file operations. The traditional WRITE_EXTERNAL_STORAGE permission has very limited scope under Scoped Storage and won't grant you broad access to the SD card.
Here's a Java snippet demonstrating how to use SAF to achieve this. The process involves:
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class CopyFileToSdCardActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> openDocumentTreeLauncher;
private Uri targetDirectoryUri;
private Uri sourceFileUri; // Assume you have the URI of the file you want to copy
private String destinationFileName = "copied_file.txt"; // Desired name for the copied file
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // Replace with your actual layout
// Assume you have a way to get the URI of the file you want to copy.
// For example, if it's in your app's internal storage:
// File sourceFile = new File(getFilesDir(), "my_source_file.txt");
// sourceFileUri = Uri.fromFile(sourceFile);
//
// For demonstration, let's assume you have a Uri to a source file.
// Replace this with your actual source file URI.
sourceFileUri = Uri.parse("content://com.example.myapp.provider/files/my_source_file.txt");
openDocumentTreeLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
if (data != null && data.getData() != null) {
targetDirectoryUri = data.getData();
// Persist the permission to access the selected directory across app restarts
getContentResolver().takePersistableUriPermission(
targetDirectoryUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
);
copyFileToSelectedDirectory();
} else {
Toast.makeText(this, "Directory selection failed.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Directory selection cancelled.", Toast.LENGTH_SHORT).show();
}
}
);
// Button to trigger the directory selection
findViewById(R.id.select_sdcard_button).setOnClickListener(v -> selectTargetDirectory());
}
public void selectTargetDirectory() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
openDocumentTreeLauncher.launch(intent);
}
private void copyFileToSelectedDirectory() {
if (targetDirectoryUri != null && sourceFileUri != null) {
try {
// Determine the MIME type of the source file (important for creating the new document)
String mimeType = getContentResolver().getType(sourceFileUri);
if (mimeType == null) {
mimeType = "application/octet-stream"; // Default if type cannot be determined
}
// Create a new document (file) in the selected directory
Uri newDocumentUri = DocumentsContract.createDocument(
getContentResolver(),
targetDirectoryUri,
mimeType,
destinationFileName
);
if (newDocumentUri != null) {
try (InputStream inputStream = getContentResolver().openInputStream(sourceFileUri);
OutputStream outputStream = getContentResolver().openOutputStream(newDocumentUri)) {
if (inputStream != null && outputStream != null) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
Toast.makeText(this, "File copied successfully!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Error opening input/output streams.", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Error during file copy: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Failed to create new document.", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "An error occurred: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Target directory or source file not selected.", Toast.LENGTH_SHORT).show();
}
}
}
Explanation:
This Java snippet provides a solid foundation for copying files to a removable SD card while adhering to the security and privacy principles enforced by Scoped Storage in Android 14. Remember to adapt the source file URI and destination file name to your specific needs.
So it might be possible using SAF...
Taifun
Puh
Just tested SAF on a USB drive plugged in (no SD card slot available), was able to read and write no problem
So you have some blocks? Or did you, using Java?
I used the SAF extension as linked above.
This post took me 3 years back.
(might not be related?)
I also tried it with SAF, but to no avail.
Do It Result: "Permission Denial: writing com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/9C33-6BBD from pid=23240, uid=12610 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()"
.IsWriteGranted and .IsReadGranted = true
Tested on Android 9.