如何让用户上传文件到内部存储?

11

我正在编写一个小应用程序,它可以读取需要定期写入设备存储的文件,这些文件来自于设备外部的源,例如 USB、蓝牙、Airdroid 等。从我所了解的情况来看,没有任何东西可以写入内部存储。我希望将文件管理在内部存储中以保护访问隐私。

我的第一个解决方案是创建一个活动,让用户将文件写入外部存储,然后点击按钮将它们转移到内部存储。如果在 n 分钟内没有完成这个操作,则外部存储中的文件将被销毁。但是,我发现 getExternalStorageDirectory 几乎没什么用处,因为设备会在内部存储中模拟外部存储,而 Android 无法确定是否以及如何完成此操作。

然而,我想知道是否有一种内置活动,允许用户直接上传或下载内部存储中的文件,但不允许完全访问内部存储的整个文件结构,就像他们访问内部存储一样。

作为最后的手段,也许我的应用程序可以通过 TCP 连接接收文件并将其写入内部存储。虽然有点麻烦,但寻找 SD 卡也是一样。请参见问题 查找外部 SD 卡位置

更新: 这个任务的目标是在 SD 卡上的一个目录中查找所有 .csv 文件,让用户选择其中一个文件,对其进行处理,并将输出文件写入 SD 卡。用户将输入一个“重量”值,该值将用于处理文件的计算中。

但是,由于 Android 在提供真正的外部存储位置(即 SD 卡)方面非常不可靠,我想尝试将文件存储在内部存储中,在这里 Android 似乎更加诚实和可靠。


您可以直接将文件存储在内部存储器中。 https://developer.android.com/training/basics/data-storage/files.html - Prerak Sola
@PrerakSola 但是怎么做呢?在我提问之前,我已经阅读了你提供的文档,并且它明确指出,关于内部存储,“在这里保存的文件只能被你的应用程序访问”。所以这个问题的核心就是,用户(不是我的应用程序)并且没有访问内部存储的权限,如何将文件保存到内部存储中。 - ProfK
1
你的问题是,“如何写入对用户可访问的内部存储,而不是data/data/package_name/,这样做将不允许其他应用程序访问它?” - Saravanabalagi Ramachandran
将文件上传到内部存储是含糊的。您是想说,从内部存储上传到网络或者从网络或外部来源写入到内部存储吗? - Saravanabalagi Ramachandran
@ZekeDran,“上传到”对我来说并不模糊。我认为它清楚地表明了,至少对于英语为母语的人来说,“内部存储”是目的地,即我想把文件放在那里,而不是从那里读取或取出它们。 - ProfK
显示剩余2条评论
2个回答

4
TLDR:`getExternalStorageDirectory()`和`getExternalFilesDirs()[0]`(API 19+) 应该返回“primary”存储位置,即内部存储。
EDIT: 如果您只想写入eMMC并且不关心它是否为私有,请使用`getFilesDir()`,这样可以确保您正在写入eMMC。

解释:

为了避免模糊和方便起见,我将使用以下术语:

  1. PrivateStorage: 应用程序在内部存储器中的私有存储 - /data/data/包名
  2. eMMC: 手机内部存储
  3. SD: 手机可扩展存储(可移动)

如果我正确理解您的问题,您不想写入PrivateStorage,这会使其他应用程序无法访问该数据。因此,目标是写入eMMC,更具体地说,是公共可访问的eMMC,而不是在eMMC应用程序的私有空间中。

根据Android文档(API 1),

Environment.getExternalStorageDirectory()返回主要外部存储目录。如果用户已将其安装在计算机上,已从设备中删除或发生其他问题,则可能无法访问此目录。您可以使用getExternalStorageState()确定其当前状态。

根据API 19docs,现在可以读写应用程序特定文件到辅助外部存储介质上,例如当设备提供模拟存储和SD卡时。新方法getExternalFilesDirs()与现有的getExternalFilesDir()方法相同,只是返回一个File对象数组。返回的File数组中的第一个条目被视为设备的"主"外部存储,与现有方法(如getExternalFilesDir())返回的File相同。总之,getExternalStorageDirectory()getExternalFilesDirs()[0]应该返回"主要"存储位置,即eMMC。但是,实际上你会发现它返回的可能不一定eMMC,对于某些手机(KarbonnTitiniumS2、XoloX3000和许多其他手机)。
这里有一些截图来证明这句话的正确性:这部TitaniumS2手机正在运行4.2版本,所以我无法使用getExternalFilesDirs()

enter image description here enter image description here

你还可以注意到,出于同样的原因,ES Explorer在旧版本和新版本中都错误地将/sdcard0识别为内部存储(eMMC),将/sdcard1识别为外部存储(SD),并且确实继续告诉用户sdcard0是内部存储。
此外,一个问题被提出来,用于查找非主要(SD)存储。

似乎没有API函数可用于查找非主要外部存储设备,而谷歌也没有意愿修复这种情况,让应用程序使用hacky解决方法,如解析所有当前挂载的文件系统。对于一个当代操作系统来说,不正确地支持像访问插入的USB存储设备上的文件这样基本的功能是相当糟糕的。


@ProfK,如果您能够明确说明您的应用程序需要做什么,人们就可以提出解决方法和可能的技巧;虽然您已经提到了它,但是没有足够的细节(比如您想要最终实现什么)来找到一个技巧,我猜 :) - Saravanabalagi Ramachandran
我写这封信的目的并不是为了阻止其他应用程序访问数据,而是因为Android知道数据的位置,而找到真正的外部存储空间相当困难。 - ProfK
这个应用程序是做什么的?它有什么作用?为什么你想要访问 eMMC?这只是出于性能方面的原因吗? - Saravanabalagi Ramachandran

0
希望这可以帮到你...
你能够获取用户想要上传的文件,并且可以读取数据...然后你想将它们写入你的应用程序路径...
如果我错了,请纠正我...
以下是如何尝试将文件写入您的应用程序路径...我的路径是/data/data/com.test.internalstorage/files
try {
    File filesDir = getApplicationContext().getFilesDir();
    Log.d(TAG, "  Files -> 1 context.getFilesDir()-=> " + filesDir);
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getName-=> " + filesDir.get-name());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getAbsolutePath-=> " + filesDir.getAbsolutePath());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getCanonicalPath-=> " + filesDir.getCanonicalPath());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getPath-=> " + filesDir.getPath());
    String[] lst = getApplicationContext().getFilesDir().list();
    for (int i=0; i< lst.length; i++){
        Log.d(TAG, "  Files -> 1 context.getFilesDir()list("+i+")-=> " + lst[i]);
    }
    String FILENAME = "hello_file5";
    String string = "hello world!";

    FileOutputStream fos = null;

    fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
    fos.write(string.getBytes());
    fos.close();


    Log.d(TAG, "  Files ");"
    File nw_filesDir = getApplicationContext().getFilesDir();
    Log.d(TAG, "  Files -> 2 context.getFilesDir()-=> " + nw_filesDir);
    String[] nw_lst = getApplicationContext().getFilesDir().list();
    for (int i=0; i< nw_lst.length; i++){
        Log.d(TAG, "  Files -> 2 context.getFilesDir()list("+i+")-=>  " + nw_lst[i] +
                " -> " + new File(nw_filesDir,nw_lst[i]).getParentFile());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

输出为

D/_TAG_:   Files -> 1 context.getFilesDir()-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getName-=> files
D/_TAG_:   Files -> 1 context.getFilesDir().getAbsolutePath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getCanonicalPath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getPath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir()list(0)-=> hello_file
D/_TAG_:   Files -> 1 context.getFilesDir()list(1)-=> hello_file2
D/_TAG_:   Files -> 1 context.getFilesDir()list(2)-=> hello_file3
D/_TAG_:   Files -> 1 context.getFilesDir()list(3)-=> hello_file4
D/_TAG_:   Files 
D/_TAG_:   Files -> 2 context.getFilesDir()-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(0)-=>  hello_file -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(1)-=>  hello_file2 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(2)-=>  hello_file3 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(3)-=>  hello_file4 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(4)-=>  hello_file5 -> /data/data/com.test.internalstorage/files

欢迎纠正和建议!!!


谢谢,但不是那样。我想从用户通过USB保存在设备SD卡上的文件中获取并处理它们,但我无法可靠地找到它们所在的路径,因此我希望让用户直接将它们保存到内部存储器中。USB连接将无法访问该位置,因此我正在寻求一种设备/应用程序可以将文件从设备外部保存到内部存储器的方法。 - ProfK
在这种情况下,我猜文件的权限将不允许您(我的意思是USB接口),因为根据Linux文件权限,它将属于“其他组”...而应用程序作为系统的一部分运行,从实用角度来看,您可以访问! - Bhuro
如果我们能在应用程序文件夹内的内部存储中以755或777权限创建目录,可能会有所帮助。比如,在我的情况下是/data/data/com.test.internalstorage/files。然后可以使用adb或abd shell命令将文件传输到该位置... - Bhuro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接