Android M 写入 SD 卡 - 权限被拒绝
Android M write to SD Card - Permission Denied
我正在尝试将文件从我的应用程序复制到 SD 卡,但出现错误 eacces(权限被拒绝)。 OS 是 Android M 并且我允许运行时存储权限(在应用程序信息中签入)。我还在 AndroidManifest.xml
中设置了使用权限
<application>...</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制到 SD 卡时无效
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/1032-2568/SomeFolder/
Error: java.io.FileNotFoundException: /storage/1032-2568/SomeFolder/SomeFile.txt: open failed: EACCES (Permission denied)
如果我复制到内部存储就可以工作
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/emulated/0/SomeFolder/
将文件从源复制到目标的代码
/*
* Below are the parameters I have tried
*
* inputPath - data/user/0/com.example.myapp/cache or data/user/0/com.example.myapp/cache/
* inputFile - /SomeFile.txt or SomeFile.txt
* outputPath - /storage/1032-2568/SomeFolder/ or /storage/1032-2568/SomeFolder
*/
public static void copyFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
out = new FileOutputStream(outputPath + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
}
catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
ES 文件资源管理器
我看到ES File Explorer也无法在Redmi设备的SD卡上写入任何内容。 Here's a video with solution。按照适用于我设备上的 ES Explorer 的步骤进行操作。这可以通过编程方式完成吗?
您需要在 Android 6.0(API 级别 23)及更高版本中添加权限请求 运行 时间,这里是 official 文档
这是 WRITE_EXTERNAL_STORAGE
的代码
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"Permission is granted");
return true;
}
像这样请求其他许可
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
我看到您正在复制一个文件的全部内容并试图将其写入另一个文件。我可以建议一个更好的方法来做到这一点:
假设您已经检查了文件是否存在
StringWriter temp=new StringWriter();
try{
FileInputStream fis=new FileInputStream(inputFile+inputPath);
int i;
while((i=fis.read())!=-1)
{
temp.write((char)i);
}
fis.close();
FileOutputStream fos = new FileOutputStream(outputPath, false); // true or false based on opening mode as appending or writing
fos.write(temp.toString(rs1).getBytes());
fos.close();
}
catch (Exception e){}
此代码适用于我的应用程序...让我知道它是否适用于您...
根据@CommonsWare 的建议,我们必须使用 android 提供的新存储访问框架,并且必须获得用户的许可才能写入 SD 卡文件,正如您所说,这已经写入文件中管理器应用程序 ES 文件资源管理器。
这是让用户选择 "SD card" 的代码:
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);
看起来有点像这样:
并在 pickedDir
中获取文档路径并在您的 copyFile 块中进一步传递
并使用此路径写入文件:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}
public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);
DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
我也遇到了这个问题,但我通过在 运行 时间内使用请求权限并在 Android 设备的 App 信息中强制授予 permission.After 权限后解决了这个问题。在清单中声明权限后 => 转到设备设置 => 转到应用程序信息 => 转到权限 =>
最后允许权限。请记住我刚才说的是 api 22 级之后来自棉花糖。
运行时权限似乎已正确实现,但问题似乎出在设备上
如果您使用的是 Redmi,则必须在 Redmi 安全设置中手动允许特定应用程序的权限
这个link展示了如何在redmi security
中开启权限
在某些设备上 Android 4.3 之后,您无法直接写入 SD 卡上的文件系统。
你应该使用 storage access framework。
您无法使用第三方应用程序复制或删除外部存储上的文件和文件夹。像 [文件资源管理器].
数据政策在KITKAT版本之后更新。
如果只允许系统应用。所以你可以使用原始文件浏览器(来自ROM)。
如果您需要使用第 3 方应用,请 ROOT 您的设备。 (需要根权限)
我正在尝试将文件从我的应用程序复制到 SD 卡,但出现错误 eacces(权限被拒绝)。 OS 是 Android M 并且我允许运行时存储权限(在应用程序信息中签入)。我还在 AndroidManifest.xml
中设置了使用权限<application>...</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制到 SD 卡时无效
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/1032-2568/SomeFolder/
Error: java.io.FileNotFoundException: /storage/1032-2568/SomeFolder/SomeFile.txt: open failed: EACCES (Permission denied)
如果我复制到内部存储就可以工作
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/emulated/0/SomeFolder/
将文件从源复制到目标的代码
/*
* Below are the parameters I have tried
*
* inputPath - data/user/0/com.example.myapp/cache or data/user/0/com.example.myapp/cache/
* inputFile - /SomeFile.txt or SomeFile.txt
* outputPath - /storage/1032-2568/SomeFolder/ or /storage/1032-2568/SomeFolder
*/
public static void copyFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
out = new FileOutputStream(outputPath + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
}
catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
ES 文件资源管理器
我看到ES File Explorer也无法在Redmi设备的SD卡上写入任何内容。 Here's a video with solution。按照适用于我设备上的 ES Explorer 的步骤进行操作。这可以通过编程方式完成吗?
您需要在 Android 6.0(API 级别 23)及更高版本中添加权限请求 运行 时间,这里是 official 文档
这是 WRITE_EXTERNAL_STORAGE
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"Permission is granted");
return true;
}
像这样请求其他许可
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
我看到您正在复制一个文件的全部内容并试图将其写入另一个文件。我可以建议一个更好的方法来做到这一点:
假设您已经检查了文件是否存在
StringWriter temp=new StringWriter();
try{
FileInputStream fis=new FileInputStream(inputFile+inputPath);
int i;
while((i=fis.read())!=-1)
{
temp.write((char)i);
}
fis.close();
FileOutputStream fos = new FileOutputStream(outputPath, false); // true or false based on opening mode as appending or writing
fos.write(temp.toString(rs1).getBytes());
fos.close();
}
catch (Exception e){}
此代码适用于我的应用程序...让我知道它是否适用于您...
根据@CommonsWare 的建议,我们必须使用 android 提供的新存储访问框架,并且必须获得用户的许可才能写入 SD 卡文件,正如您所说,这已经写入文件中管理器应用程序 ES 文件资源管理器。
这是让用户选择 "SD card" 的代码:
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);
看起来有点像这样:
并在 pickedDir
中获取文档路径并在您的 copyFile 块中进一步传递
并使用此路径写入文件:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}
public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);
DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
我也遇到了这个问题,但我通过在 运行 时间内使用请求权限并在 Android 设备的 App 信息中强制授予 permission.After 权限后解决了这个问题。在清单中声明权限后 => 转到设备设置 => 转到应用程序信息 => 转到权限 => 最后允许权限。请记住我刚才说的是 api 22 级之后来自棉花糖。
运行时权限似乎已正确实现,但问题似乎出在设备上 如果您使用的是 Redmi,则必须在 Redmi 安全设置中手动允许特定应用程序的权限 这个link展示了如何在redmi security
中开启权限在某些设备上 Android 4.3 之后,您无法直接写入 SD 卡上的文件系统。
你应该使用 storage access framework。
您无法使用第三方应用程序复制或删除外部存储上的文件和文件夹。像 [文件资源管理器].
数据政策在KITKAT版本之后更新。
如果只允许系统应用。所以你可以使用原始文件浏览器(来自ROM)。
如果您需要使用第 3 方应用,请 ROOT 您的设备。 (需要根权限)