在 Android 中保存文件 - 适合初学者(内部/外部存储)

Posted

技术标签:

【中文标题】在 Android 中保存文件 - 适合初学者(内部/外部存储)【英文标题】:Saving Files in Android - For Beginners (Internal / External Storage) 【发布时间】:2019-01-05 01:08:03 【问题描述】:

我是 android 开发的新手,我需要初学者帮助...

我正在创建一个应用程序,它应该有 2 个目录,一个数据库目录和一个图像目录,就像 Whatsapp 一样。

我想在浏览手机时在文件管理器中查看这些目录,就像您查看其他应用程序文件夹一样。 我尝试了在这里找到的所有内容,在内部存储和外部存储中从代码中创建它。这些文件夹似乎已创建,但是当我浏览手机的文件管理器时,我找不到带有我的应用程序名称的文件夹以及其中的数据库和图像文件夹... 我究竟做错了什么?我需要在 android studio 中创建这些文件夹作为添加文件夹吗?还是我需要从代码中创建它?

您能告诉我完成这项任务所需的操作吗? 我正在使用安卓工作室 3.1.3。 感谢帮助者! :)

【问题讨论】:

【参考方案1】:

主要答案确实帮助了我,如果没有那个很好的答案,我就无法做到这一点。

但是我在获取存储目录时遇到了一些困难(因为 API 会随着时间的推移而发生变化),而且我正在使用 Kotlin,所以我想我只是分享我使用的最终代码。

我的也返回一个字符串消息(文件的绝对路径为成功,否则为错误消息)。

我还添加了一些日志语句,以便您查看正在发生的事情。

fun writeFileExternalStorage() :String 

        var fileData : String = "test this"
        
        Log.i("FirstFrag", "in writeFileExternalStorage")
        //Checking the availability state of the External Storage.
        val state = Environment.getExternalStorageState()
        if (Environment.MEDIA_MOUNTED != state) 

            Log.i("FirstFrag", "Couldn't get file system.")
            return "Couldn't write file."
        

        var file =File(requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "test.txt")

        Log.i("FirstFrag", file.absolutePath)
        //This point and below is responsible for the write operation
        var outputStream: FileOutputStream? = null
        try 
            Log.i("FirstFrag", "creating new file")
            file.createNewFile()
            Log.i("FirstFrag", "file created")
            //second argument of FileOutputStream constructor indicates whether
            //to append or create new file if one exists
            outputStream = FileOutputStream(file, true)
            outputStream?.write(fileData.toByteArray())
            outputStream?.flush()
            outputStream?.close()
            Log.i("FirstFrag", "wrote file!")
            return file.absolutePath
         catch (e: Exception) 
            Log.i("FirstFrag",e.message.toString())
            return e.message.toString() + "\nPlease check that you have a valid filename."
        
        finally 
            isRetrievingFile = false;
        
    

【讨论】:

【参考方案2】:

内部存储”和“外部存储”这两个术语一开始可能会让人感到困惑,因为 Google 的意图与我们今天所期望和知道的不同 -当今使用的语言:“外部”并不一定意味着“SD 卡”。 This guy made a great article about the terminology confusion

根据您的意图,您可能希望使用 外部存储 概念。 Documentation 中对这些差异进行了很好的解释,但我将在此处简要介绍一下。

最后我会给你一个例子,但首先让我们了解一下基础知识:

内部存储

只有您的应用程序可以访问文件 卸载您的应用时会删除文件 文件始终可用(这意味着文件永远不会保存在可移动内存中)

外部存储

其他应用程序(包括文件管理器应用程序的任何变体,在您的情况下)完全可以读取文件 卸载应用时不一定会删除文件 - 稍后解释 不保证文件的可用性(可以被其他应用程序/可移动内存删除)

既然我们知道您需要外部存储,那么在开始之前需要做几件事:

需要权限(读/写)在您的 Manifest.xml 文件中,具体取决于您的需要:
    <manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
    </manifest>

每个权限都是独立的,这意味着您不需要同时拥有这两个权限,例如,如果您只想读取文件而不是写入文件

验证storage is available - 这是在运行时完成的,并且在文档中得到了很好的解释。我们需要确保存储已安装到设备中/其状态不会以某种方式导致读/写请求失败。

示例时间!

在给定的方法中,我们将在根目录中保存一个文本文件。

感谢this article

public void writeFileExternalStorage() 

    //Text of the Document
    String textToWrite = "bla bla bla";

    //Checking the availability state of the External Storage.
    String state = Environment.getExternalStorageState();
    if (!Environment.MEDIA_MOUNTED.equals(state)) 

        //If it isn't mounted - we can't write into it.
        return;
    

    //Create a new file that points to the root directory, with the given name:
    File file = new File(getExternalFilesDir(null), filenameExternal);

    //This point and below is responsible for the write operation
    FileOutputStream outputStream = null;
    try 
        file.createNewFile();
        //second argument of FileOutputStream constructor indicates whether
        //to append or create new file if one exists
        outputStream = new FileOutputStream(file, true);

        outputStream.write(textToWrite.getBytes());
        outputStream.flush();
        outputStream.close();
     catch (Exception e) 
        e.printStackTrace();
    


我想具体回答您的一些问题:

我需要在 android studio 中创建这些文件夹作为添加文件夹吗?还是我需要从代码中创建它?

绝对不是通过 Android Studio。这些是您的项目文件夹,包含您的代码。方法上面已经提到了。

我找不到包含我的应用名称的文件夹以及其中的数据库和图像文件夹...我做错了什么?

如您之前提到的,可能将您的文件保存为内部存储文件/将它们保存为项目文件夹 - 而那些不会(也不应该)显示出来。


有用的知识

有两种类型的目录:公共和私有。

私人

媒体商店无法访问 卸载应用时删除文件 由getExternalFilesDir(...) 方法检索

示例:WhatsApp 目录(在我的手机中)位于根级别。调用它是:getExternalFilesDir("WhatsApp/...")

公共(下载/电影/图片库)

文件由MediaStore 扫描 由Environment.getExternalStoragePublicDirectory(...) 方法检索

示例: 获取 Documents 文件夹如下所示:Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)

【讨论】:

非常感谢您提供详细而快速的答复!还有一个问题。我创建的文件在手机上的路径是:/storage/emulated/0/Android/data/com.example.../files/FileName,当我使用 getExternalFilesDir 时。我想在 /storage/emulated/0/AppName 上创建目录,所以我使用了 Environment.getExternalStorageDirectory()。调试时,路径正确,文件夹似乎已创建,但我在手机和电脑浏览器上都找不到。我在这里哪里做错了?以 WhatsApp 为例,路径为 /storage/emulated/0/WhatsApp/ 我用来创建文件夹的代码是:String DirName = "MyAppName";文件 dir = new File(Environment.getExternalStorageDirectory(), DirName); if (!dir.exists()) dir.mkdirs(); 我认为您想使用new File(getExternalFilesDir(), DirName) 而不是getExternalStoragePublicDirectory()。另一件事:文件应该指向一个文件,而不是一个目录。尝试将 DirName 更改为“MyAppName/TestFile.txt”,看看它是否适合您 使用getExternalFilesDir(),路径是/storage/emulated/0/Android/data/com.example.../DirName/files/,我希望路径是/storage/emulated /0/目录名/。正在使用 new File(Environment.getExternalStorageDirectory(), DirName ) 因为这不正确?对于将 DirName 更改为“MyAppName/TestFile.txt”,我想创建一个空目录并用代码中的应用程序命令填充它,还有其他方法吗?为什么我看不到创建的目录?再次感谢所有帮助! :)(תודהרבה!) 是的,成功了!这就是问题所在!谢谢,你帮了我很多! :) מאד מעריכה,תודה רבה! :)

以上是关于在 Android 中保存文件 - 适合初学者(内部/外部存储)的主要内容,如果未能解决你的问题,请参考以下文章

xml Android适合初学者

适合Java初学者的知识

适合Java初学者的知识

适合Java初学者的知识

有没有适合 Android 开发初学者的 App 源码推荐

是否有 Android 支付 API 可以让我的用户在我的应用程序内的其他服务上购买商品?