19

我需要将文件从资产复制到外部存储。这是我的代码:

    File f = new File(Environment.getExternalStorageDirectory() + File.separator
            + "MyApp" + File.separator + "tessdata" + File.separator + "eng.traineddata");
    if (!f.exists()) {
    AssetManager assetManager = getAssets();
    try {
        f.createNewFile();
        InputStream in = assetManager.open("eng.traineddata");
        OutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory() + File.separator
            + "MyApp" + File.separator  + "tessdata" + File.separator + "eng.traineddata");
        byte[] buffer = new byte[1024];
        int read;
            while ((read = in.read(buffer)) != -1)
                    out.write(buffer, 0, read);
            in.close();
            in = null;
            out.flush();
            out.close();
            out = null;
        } catch (IOException e) {
            Log.e("tag", "Failed to copy asset file: ", e);
        }
    }

我还在清单中添加了权限

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

执行时发生异常f.createNewFile(),说“权限被拒绝”。

请问我该如何解决?

4

6 回答 6

39

在我的情况下,这是由于 API 23+ 所需的权限弹出窗口,即使您在清单中添加了权限。

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

在应用启动或需要权限时调用此函数。

AndroidManifest.xml

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

可以在此处找到权限的详细示例代码。

于 2016-12-19T10:41:15.670 回答
30

最近在 API 级别 29 中,他们改变了访问外部存储的方式。如果您尝试访问公共文件夹(即下载),它将引发权限被拒绝错误。

您需要在清单文件的应用程序标签中指定以下代码。

android:requestLegacyExternalStorage="true"

或者您可以将文件保存在根目录中以避免此错误。

于 2020-08-26T11:11:22.930 回答
8

f.mkdirs()之前f.createNewFile()。您可能正在尝试在不存在的目录中创建一个新文件

于 2013-05-03T14:47:29.353 回答
2

尝试这个:

private void copy() {

File dirOri = new File(Environment.getExternalStorageDirectory() +"/somefolder/somefile");
File dirDest = new File(Environment.getExternalStorageDirectory() + "/yourfolder");

FileChannel src = null;
FileChannel dst = null;

try {
    src = new FileInputStream(dirOri).getChannel();
    dst = new FileOutputStream(dirDest).getChannel();
    dst.transferFrom(src, 0, src.size());               
    src.close();
    dst.close();
} catch (Exception e) {}
}

- 编辑 -

在清单中添加:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>  
于 2013-05-03T14:44:13.203 回答
1

如果您使用的是 SDK-23,您需要像这样在清单文件中写入权限

<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE" />

于 2019-05-13T06:50:25.253 回答
1

我已经很努力地搜索了答案。大多数解决方案不适用于 API 29。@ishann 的回答启发我搜索 android:requestLegacyExternalStorage 。原来,他们引入了范围存储的概念,这意味着应用程序默认只能访问其专用文件夹。例如,图片的文件夹模式现在应该是这样的:

/storage/emulated/0/Android/data/com.myapp.myapp/files/Pictures

即使授予了两个权限,在全局位置创建文件或文件夹也会失败:

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

以下代码对我有用:

File files[] = this.getApplicationContext().getExternalFilesDirs(Environment.DIRECTORY_PICTURES);

for(File f : files){
    Log.e("debug", f.getAbsolutePath());
    File newdir = new File(f.getAbsolutePath(), "/newtest/");
    boolean result = newdir.mkdirs();
    Log.e("debug", result + " ; " + newdir.exists());
    break;
}

相关文件

https://developer.android.com/training/data-storage#scoped-storage

https://developer.android.com/reference/android/content/Context#getExternalFilesDirs(java.lang.String)

于 2020-11-02T18:34:44.267 回答