【问题标题】:Internal or External storage for editable app-specific file用于可编辑应用程序特定文件的内部或外部存储
【发布时间】:2018-11-11 08:23:49
【问题描述】:

我正在创建一个应用程序,它需要一个特定于应用程序的文件,例如,我称之为“conf.cfg”。我的应用程序需要读取此文件以创建一些对象等...文件的主体如下所示:

#activation, level, type, regex or array 0, "critic", 0,"\\d{4}\\w\\d{3}" 1, "critic", 1, [word1,word2] 1,"minor", 0,"\\d{2}-\\w{3}-\\d{4}\\s?\\/?\\s?\\d{2}:\\d{2}"

通过研究我发现android中有两种类型的存储:

  1. 内部存储:

当您想确保用户和其他应用都无法访问您的文件时,最好使用内部存储。

  1. 外部存储:

外部存储是存储不需要访问限制的文件以及您希望与其他应用共享或允许用户通过计算机访问的文件的最佳位置。

由于我希望用户能够编辑/下载/上传/使用这个文件,外部存储似乎是一个不错的选择。然而在Developper Android 他们说:

注意:如果用户取出 SD 卡或将设备连接到计算机,外部存储可能会变得不可用。并且这些文件对用户和其他具有 READ_EXTERNAL_STORAGE 权限的应用程序仍然可见。因此,如果您的应用的功能依赖于这些文件,或者您需要完全限制访问,则应改为将文件写入内部存储。

注意:外部存储上的文件并不总是可以访问,因为用户可以将外部存储安装到计算机上以用作存储设备。因此,如果您需要存储对应用功能至关重要的文件,则应将它们存储在内部存储中。

因为此文件需要始终可用并且对我的应用的功能至关重要 所以...内部存储似乎更好。但我需要用户查看并能够使用该文件。我在这里卡住了。

有人知道在哪里以及如何放置/创建此文件吗?

编辑:关注@greenapps 回答

heer 是我编写的一段代码。我使用getExternalFilesDir(null) 命令来写入和存储我的文件

    String folderName = "Innovation";
    String confFileName = "conf.txt";
    String commentSymbol = "#";
    String commentLine = commentSymbol + " activation, level, type , regex or array";

    File storage = getExternalFilesDir(null);
    File folder = new File(storage, folderName);
    File conf = new File(folder, confFileName);

    Log.d(TAG, "Folder action!");
    if (!folder.exists()) {
        if (folder.mkdirs()) {
            Log.d(TAG, "Created : " + folder.getAbsolutePath());
        } else {
            Log.e(TAG, "folder not created!");
        }
    }

    Log.d(TAG, "File action!");
    if (!conf.exists()) {
        try {
            Log.d(TAG, "opening...");
            FileOutputStream fos = new FileOutputStream(conf);
            fos.write(commentLine.getBytes());
            fos.close();
            Log.d(TAG, "Created : " + conf.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    if (conf.exists()) {
        Log.d(TAG, "File exist at : " + conf.getAbsolutePath());
    }

文件创建完成,如上一条日志所示

创建:/storage/emulated/0/Android/data/com.aralex.innovation/files/Innovation/conf.txt

但是当我使用手机的原生文件资源管理器应用程序搜索文件时,我找不到它。我可以转到文件夹,但文件夹“Innovation/”是隐藏的。

这是一个问题,因为我希望文件可见。

手机:三星 s7、s7edge、s9+

Default File Explorer Icon

Default File Explorer Oppened

【问题讨论】:

  • 内部或外部存储都可以。所有设备都有它。它们与可移动的微型 SD 卡无关。你读过一篇旧文档。
  • 但它说:如果用户取出 SD 卡或将设备连接到计算机,外部存储可能会变得不可用
  • 你的故事中不清楚的是,如果我在上面安装了你的应用程序,这个文件将如何登陆我的设备。
  • 是的,您阅读了旧文档。外部存储始终可用。请重新阅读我的评论。
  • 如果是第一次安装,则创建的文件仅包含第一行(以“#”开头的行)。然后用户必须能够编辑这个文件(在他的手机上使用其他应用程序,比如一个简单的记事本)或者能够用他的手机文件浏览器去文件,替换它等等......就像一个文件简单的文件一台电脑

标签: android file storage


【解决方案1】:

好吧,我终于自己找到了答案。

在这个帖子Android create folders in Internal Memory@prodev 上指定Environment.getExternalStorageDirectory() 是一个好地方,因为该文件将可以访问并且:

注意,Environment.getExternalStorageDirectory()中的ExternalStorage不一定指sdcard,它返回手机主存储内存

它需要权限(仅适用于构建版本 >= M):

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />

所以这里有一个代码来回答我的问题(它在运行时要求许可):

private ArrayList<Rule> ruleList; 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    [...]

    // Check for the storage permission before accessing the camera.  If the
    // permission is not granted yet, request permission.
    if (hasPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
            || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        ruleList = createRules();
    } else {
        requestStoragePermission();
    }
}

private boolean hasPermissions(Context context, String... permissions) {
    if (context != null && permissions != null) {
        for (String permission : permissions) {
            Log.d(TAG, "Checking permission : " + permission);
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "not granted : " + permission);
                return false;
            } else {
                Log.d(TAG, "granted : " + permission);
            }
        }
    }
    return true;
}

/**
 * Handles the requesting of the storage permission.  This includes
 * showing a "Snackbar" errorMessage of why the permission is needed then
 * sending the request.
 */
private void requestStoragePermission() {
    Log.w(TAG, "Storage permission is not granted. Requesting permission");

    final String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};

    if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_EXTERNAL_PERM);
        return;
    }

    final Activity thisActivity = this;

    View.OnClickListener listener = view -> ActivityCompat.requestPermissions(thisActivity, permissions,
            RC_HANDLE_EXTERNAL_PERM);

    Snackbar.make(findViewById(android.R.id.content), R.string.permission_storage_rationale,
            Snackbar.LENGTH_INDEFINITE)
            .setAction(R.string.ok, listener)
            .show();
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    if (requestCode != RC_HANDLE_EXTERNAL_PERM) {
        Log.d(TAG, "Got unexpected permission result: " + requestCode);
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }

    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
            && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
        Log.d(TAG, "Storage permission granted");
        // We have permission
        ruleList = createRules();
        return;
    }

    Log.e(TAG, "Permission not granted: results len = " + grantResults.length +
            " Result code = " + (grantResults.length > 1 ? grantResults[0] + " " + grantResults[1] : grantResults.length > 0 ? grantResults[0] : "(empty)"));

    DialogInterface.OnClickListener listener = (dialog, id) -> finish();

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Assisting Tool")
            .setMessage(R.string.no_storage_permission)
            .setPositiveButton(R.string.ok, listener)
            .show();
}

private ArrayList<Rule> createRules() {
    Log.d(TAG, "=========================READING FILE======================");

    ArrayList<Rule> ruleList = new ArrayList<>();

    String folderName = "Innovation";
    String confFileName = "conf.txt";
    String commentSymbol = "#";
    String commentLine = commentSymbol + " activation, level, type , regex or array";

    File storage = Environment.getExternalStorageDirectory();
    File folder = new File(storage, folderName);
    File conf = new File(folder, confFileName);

    Log.d(TAG, "Folder action!");
    if (!folder.exists()) {
        if (folder.mkdirs()) {
            Log.d(TAG, "Created : " + folder.getAbsolutePath());
        } else {
            Log.e(TAG, "folder not created!");
        }
    }

    Log.d(TAG, "File action!");
    if (!conf.exists()) {
        try {
            Log.d(TAG, "opening...");
            FileOutputStream fos = new FileOutputStream(conf);
            fos.write(commentLine.getBytes());
            fos.close();
            Log.d(TAG, "Created : " + conf.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    if (conf.exists()) {
        Log.d(TAG, "File exist at : " + conf.getAbsolutePath());
    } else {
        Log.e(TAG, "The file doesn't exist...");
    }
}

现在它创建了一个特定于应用程序的文件

/storage/emulated/0/Innovation/conf.txt

用户可以访问!

【讨论】:

  • 你说的都没有道理。 getExternalFilesDir() 也应该工作。而且不需要权限。
【解决方案2】:

所以外部存储。

没有内部,因为文件浏览器无法访问您的应用私有内部存储器。

你可以使用 getExternalFilesDir(null) 那样你就不需要读写权限

【讨论】:

  • 但如前所述,如果文件不在“那里”,我必须创建它。所以我需要一个写权限
  • 见主帖中的编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
  • 2014-06-12
  • 1970-01-01
  • 2021-12-10
相关资源
最近更新 更多