我的应用将文件存储在其内部存储目录(/Android/data/com.mycompany.myapp/files,由getFilesDir()返回),我希望允许用户直接从文件管理中访问这些文件移动设备上的应用程序或Android文件传输桌面应用程序。
Storage Options developer guide说:
默认情况下,保存到内部存储的文件对您的应用程序是私有的,而其他应用程序无法访问它们(用户也不能)。
“默认情况下”意味着我可以更改默认权限以允许用户访问这些文件,但我找不到任何有关如何执行此操作的文档。当我使用文件管理应用程序浏览/ Android / data目录时,目前隐藏了com.mycompany.myapp目录。
我目前正在保存这样的文件数据:
String fileName = "myfile.jpg";
String filePath = getFilesDir() + File.separator + fileName;
FileOutputStream fileStream = new FileOutputStream(filePath);
fileData.writeTo(fileStream); // fileData is a ByteArrayOutputStream
fileStream.close();
我尝试将各个文件的权限设置为世界可读,但这并未使目录可见:
FileOutputStream fileStream = this.app.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
我还检查了AndroidManifest文件的文档,但没有看到任何内容。有谁知道我怎么能这样做?
答案 0 :(得分:40)
我仔细查看了getFilesDir()
vs getExternalFilesDir()
的结果,发现getFilesDir()
返回/data/data/[packagename]/files
,getExternalFilesDir()
返回/Android/data/[packagename]/files
。我认为我在/Android/data
中浏览的应用程序文件是内部存储目录,但现在我看到它们实际上是外部存储目录。
如果内部存储目录确实永远不会被普通用户使用,我希望文档说明,而不是说它们不可用"默认情况下。"至少对我说,默认情况下""意味着可以更改默认行为。
无论如何,我测试并确认如果删除我的应用程序,保存到getExternalFilesDir()
的文件会自动删除。这样就满足了我对与应用程序明确连接的存储位置的需求(使用特定于应用程序的目录名称并随应用程序删除),但用户可以随时访问这些存储位置以进行手动文件管理。
这里的比较可能有助于其他人阅读此内容:
答案 1 :(得分:10)
我认为你对开发者文档感到困惑,我不能怪你,这不是我读过的最好的文档。无论如何,Android提供了两种将文件保存到文件系统的方法:
内部存储空间始终可用且只能供您的应用访问,系统中的任何其他应用都无法访问您的应用保存到此分区的文件。
现在,我认为您需要的是外部存储,因为它“世界可读”,任何人和任何应用都可以访问。缺点是它可能无法使用,因为用户可以将其安装在USB设备上 - 用户可以随时将其删除。
根据文档说明,您不应同时使用MODE_WORLD_WRITEABLE
或MODE_WORLD_READABLE
,因为它非常危险。此外,自API级别17以来,这些常量已被弃用
如果您需要公开您的文件,请将其保存到外部存储空间。您需要在清单文件中声明权限,以避免您的应用在每次访问外部存储时崩溃...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
因为外部存储可能无法使用,您需要在执行任何操作之前确定其状态,否则您的应用会崩溃......
public enum StorageState{
NOT_AVAILABLE, WRITEABLE, READ_ONLY
}
public StorageState getExternalStorageState() {
StorageState result = StorageState.NOT_AVAILABLE;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return StorageState.WRITEABLE;
}
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return StorageState.READ_ONLY;
}
return result;
}
有关文档的更多信息以及您应该注意的事项。例如,您可以为应用程序提供这些文件的所有权,以便在卸载应用程序时系统可以自动删除这些文件。有关详细信息,请参阅documentation on the Android Developers Site
答案 2 :(得分:0)
将此添加到清单
然后将其添加到您的活动中:
private static final String RequieredPermission = Manifest.permission.READ_EXTERNAL_STORAGE;
然后调用HandlePermission()
,您需要在其中检查权限,通常是在活动的Oncreate方法中。然后需要这些功能:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Log.d("amir", "onRequestPermissionsResult: called");
switch (requestCode) {
case REQUEST_PERMISSION_READING_STATE:
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "Permission Granted!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
}
}
}
private void HandlePermission() {
int permissionCheck = ContextCompat.checkSelfPermission(
this, RequieredPermission);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
RequieredPermission)) {
showExplanationaboutPermission("Permission Needed", "Rationale", RequieredPermission, REQUEST_PERMISSION_READING_STATE);
} else {
requestPermission(RequieredPermission, REQUEST_PERMISSION_READING_STATE);
}
} else {
Toast.makeText(MainActivity.this, "Permission (already) Granted!", Toast.LENGTH_SHORT).show();
}
}
private void showExplanationaboutPermission(String title,
String message,
final String permission,
final int permissionRequestCode) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
requestPermission(permission, permissionRequestCode);
}
});
builder.create().show();
}
private void requestPermission(String permissionName, int permissionRequestCode) {
ActivityCompat.requestPermissions(this,
new String[]{permissionName}, permissionRequestCode);
}