Read/Write to external storage and persist after uninstallation

huangapple go评论109阅读模式
英文:

Read/Write to external storage and persist after uninstallation

问题

I need to create files and read/write to external storage and the files should persist after uninstallation of the application. It should work on Android 12.

import android.content.Context;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileUtil {

    public static void writeFileToExternalStorage(Context context, String fileName, String content) {
        File file = new File(context.getExternalFilesDir(null), fileName);

        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(content.getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

String fileName = "my_file.txt";
String content = "Hello";

FileUtil.writeFileToExternalStorage(getApplicationContext(), fileName, content);

File my_file.txt will be deleted after uninstallation of the app. I need it to persist.
I will be writing text files and images related to it (e.g. one subdirectory of the app directory would contain files f1.txt, img1.jpg, f2.txt, img2.jpg ... fn.txt, imgn.jpg).
I don't want to use a database or shared preferences for it.
How can I do it?

In this video there is said, that every time the app reads/writes to a file, the user has to go through a dialog, but this is what I don't want. It's very uncomfortable for the user.

英文:

I need to create files and read/write to external storage and the files should persist after uninstallation of the application. It should work on Android 12.

import android.content.Context;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileUtil {

    public static void writeFileToExternalStorage(Context context, String fileName, String content) {
        File file = new File(context.getExternalFilesDir(null), fileName);

        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(content.getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


String fileName = "my_file.txt";
String content = "Hello";

FileUtil.writeFileToExternalStorage(getApplicationContext(), fileName, content);

File my_file.txt will be deleted after uninstallation of the app. I need it to persist.
I will be writing text files and images related to it (e.g. one subdirectory of the app directory would contain files f1.txt, img1.jpg, f2.txt, img2.jpg ... fn.txt, imgn.jpg).
I don't want to use database or shared preferences for it.
How can I do it?

In this video there is said, that everytime the app reads/writes to a file, the user has to go through dialog, but this is what I don't want. It's very uncomfortable for the user.

答案1

得分: 2

你说得对,Context#getExternalFilesDir 返回的是在卸载您的应用时也会一并卸载的应用程序。

对于API 29及以上

文档 表示,对于Documents,我们应该使用Storage Access Framework

您可以使用 Intent#ACTION_CREATE_DOCUMENT 创建新文件。

类似于以下代码:

// 用于创建PDF文档的请求代码。
const val CREATE_FILE = 1

private fun createFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/text"
        putExtra(Intent.EXTRA_TITLE, "file.txt")
    }
    startActivityForResult(intent, CREATE_FILE)
}

执行该命令并接收结果后,您可以使用来自Intent#getDatauri访问文件。使用contentResolver.openOutputStream(destination)来更新文件内容。

更新1: 这是Java中类似的代码:

private void createFile() {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("application/text");
    intent.putExtra(Intent.EXTRA_TITLE, "file.txt");

    launcher.launch(intent);
}

并写入文件:

OutputStream stream = getContentResolver().openOutputStream(uri);
PrintWriter writer = new PrintWriter(stream);

writer.println("Hello World");
writer.close();

对于API低于29

我看到文档建议使用 Environment#getExternalStoragePublicDirectory,特别是如果文件需要共享。

您还可以使用 Environment#getExternalStorageDirectory 访问设备的根目录。然而,出于对getExternalStoragePublicDirectory的支持,建议不要使用根目录,因为保存在根目录中的文件可能会占用用户的空间。

应用程序不应直接使用此顶级目录,以避免污染用户的根命名空间。应将应用程序专用的任何文件放置在由Context.getExternalFilesDir返回的目录中,系统将在卸载应用程序时删除这些文件。其他共享文件应放置在getExternalStoragePublicDirectory(String)返回的目录之一中。

英文:

You're totally right that Context#getExternalFilesDir returns app that will be uninstalled with your app.

For API 29 and above:

Documentation says that for Documents we should use Storage Access Framework.

You can create a new file using Intent#ACTION_CREATE_DOCUMENT

Similar to this:

// Request code for creating a PDF document.
const val CREATE_FILE = 1

private fun createFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/text"
        putExtra(Intent.EXTRA_TITLE, "file.txt")
    }
    startActivityForResult(intent, CREATE_FILE)
}

You will see something similar to

Read/Write to external storage and persist after uninstallation

After executing the command and receiving the result you can access the file using uri from Intent#getData. With a uri you can use contentResolver.openOutputStream(destination) to update the file's content.

Update 1: this is a similar code in Java

    private void createFile() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("application/text");
        intent.putExtra(Intent.EXTRA_TITLE, "file.txt");

        launcher.launch(intent);
    }

And writing to the file:

OutputStream stream = getContentResolver().openOutputStream(uri);
PrintWriter writer = new PrintWriter(stream);

writer.println("Hello World");
writer.close();

For API below 29:

I see that documentation offers to use Environment#getExternalStoragePublicDirectory, especially, if files should be shared.

You can also access the root of the device using Environment#getExternalStorageDirectory. However, the usage is discouraged in favour of getExternalStoragePublicDirectory as files saved in root can pollute user's space.

> Applications should not directly use this top-level directory, in order to avoid polluting the user's root namespace. Any files that are private to the application should be placed in a directory returned by Context.getExternalFilesDir, which the system will take care of deleting if the application is uninstalled. Other shared files should be placed in one of the directories returned by getExternalStoragePublicDirectory(String).

答案2

得分: 1

唯一应该创建文件子目录的地方是公共的下载或文档目录。

您将使用getExternalPublicDirectory()来获取路径。使用它。不管是否被弃用,它在所有Android版本上都有效。

其他公共目录不可行,因为它们不会接受具有不同扩展名的文件。

这些文件将会保留。您没有说明谁以及如何在以后使用这些文件。

如果重新安装您的应用程序,请使用SAF来让用户选择您的子目录。

英文:

The only place where you should create the subdirectory for your files is in public Download or Documents directory.

You will use getExternalPublicDirectory() to get the path. Use it. Deprecated or not it works on all Android versions.

Other public directories are not possible as they will not take files with different extensions.

The files will persist. You did not tell who and how those files will be used later.

If you reinstall your app use SAF to let the user choose your subdir.

答案3

得分: 0

在Android 12上,管理存储建议使用SAF

但如果您不想使用,唯一的方法是请求权限MANAGE_EXTERNAL_STORAGE,该权限允许完全访问存储。有关更多详细信息,请查看此链接

注意:MANAGE_EXTERNAL_STORAGE是一个敏感权限,因此在使用之前请查看此Google Play通知

英文:

On Android 12, to manage storage SAF is the recommended way.

But if you don't want to use then the only way is requesting permission MANAGE_EXTERNAL_STORAGE which allows full storage access. For more details check out this link.

Note: MANAGE_EXTERNAL_STORAGE is a sensitive permission so check out this Google play notice before using it.

答案4

得分: 0

你可以将文件保存到路径 Environment.getExternalStorageDirectory() + "/your_folder",但用户可以手动删除文件。参考

英文:
  • You can save the file to path Environment.getExternalStorageDirectory() + "/your_folder", However user can manual delete file.
    Refer

答案5

得分: -1

在Android中,保存到由context.getExternalFilesDir()提供的外部存储目录的文件被视为应用程序的私有外部存储的一部分。默认情况下,这些文件在应用程序被卸载时会被删除。但是,如果您希望这些文件在卸载后仍然存在,可以将它们保存到外部存储的不同位置。

以下是您的代码的更新版本,将文件保存到外部存储的自定义目录:

import android.content.Context;
import android.os.Environment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileUtil {

    public static void writeFileToExternalStorage(Context context, String directoryName, String fileName, String content) {
        File directory = new File(Environment.getExternalStorageDirectory(), directoryName);
        if (!directory.exists()) {
            directory.mkdirs(); // 如果目录不存在,则创建目录
        }

        File file = new File(directory, fileName);

        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(content.getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

用法:

String directoryName = "my_files_directory";
String fileName = "my_file.txt";
String content = "Hello";

FileUtil.writeFileToExternalStorage(getApplicationContext(), directoryName, fileName, content);

在这段代码中,Environment.getExternalStorageDirectory()方法提供了外部存储的根目录。通过在此根目录内创建自定义目录,您可以将文件保存在那里。这个自定义目录将在应用程序被卸载后保留,允许文件保持完整。

请注意,从Android 10(API级别29)开始,存在访问外部存储的限制,您需要从用户那里请求必要的权限。此外,考虑在将来用户撤销存储访问权限时优雅地处理权限访问。

关于您提到的视频,它似乎涉及到Android 10中引入的Scoped Storage更改。Scoped Storage对访问应用程序私有目录之外的文件施加了一些限制。然而,上面描述的方法对于Android 12也适用,因为它将文件保存在应用程序的私有外部存储中,不受Scoped Storage的限制。

希望我对您有所帮助。

英文:

In Android, files saved to the external storage directory provided by context.getExternalFilesDir() are considered part of the application's private external storage. By default, these files are deleted when the application is uninstalled. However, if you want the files to persist even after uninstallation, you can save them to a different location on the external storage.

Here's an updated version of your code that saves files to a custom directory on the external storage

import android.content.Context;
import android.os.Environment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileUtil {

    public static void writeFileToExternalStorage(Context context, String directoryName, String fileName, String content) {
        File directory = new File(Environment.getExternalStorageDirectory(), directoryName);
        if (!directory.exists()) {
            directory.mkdirs(); // Create the directory if it doesn't exist
        }

        File file = new File(directory, fileName);

        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(content.getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Usage:

String directoryName = "my_files_directory";
String fileName = "my_file.txt";
String content = "Hello";

FileUtil.writeFileToExternalStorage(getApplicationContext(), directoryName, fileName, content);

In this code, the Environment.getExternalStorageDirectory() method provides the root directory of the external storage. By creating a custom directory within this root directory, you can save your files there. This custom directory will persist even after the application is uninstalled, allowing the files to remain intact.

Please note that starting from Android 10 (API level 29), there are restrictions on accessing external storage, and you'll need to request the necessary permissions from the user. Additionally, consider handling the storage access permission gracefully in case it is revoked by the user in the future.

Regarding the video you mentioned, it seems to be referring to the Scoped Storage changes introduced in Android 10. Scoped Storage imposes certain restrictions on accessing files outside the application's private directories. However, the approach described above should work for Android 12 as well, as it saves the files within the application's private external storage, which is not subject to Scoped Storage restrictions.

I hope I have been of assistance to you.

huangapple
  • 本文由 发表于 2023年6月5日 05:19:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76402457.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定