当前位置: 首页 > 知识库问答 >
问题:

无法在Android应用中的SD卡上写入文件

相野
2023-03-14

我无法在物理SD卡上写入文件。我想请求用户写入整个SD卡的权限。用户授予权限。现在我想在SD卡上的特定目录中创建文件(目录已经存在)。当我尝试打开输出流时,我得到异常:

Java。Lang.SecurityException:权限拒绝:正在写入com . Android . external stage . external stage provider uri content://com . Android . external stage . documents/tree/0 fff 170 e:MyDir/my file。MyExt from pid=3563,uid=10082需要Android . permission . manage _ DOCUMENTS或grantUriPermission()

以下是活动代码:

using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Net;
using Android.OS;
using Android.OS.Storage;

namespace MyApp
{
    [Activity(Label = "MyApp", MainLauncher = true)]
    public class MainActivity : Activity
    {
        private const int AccessRequest = 101;

        private TaskCompletionSource<string> AccessIntentTaskCompletionSource { get; set; }

        protected override async void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.Main);

            string uriWithPermission = await AccessIntentAsync();

            if (!string.IsNullOrEmpty(uriWithPermission))
            {
                string targetUri = uriWithPermission + "MyDir/MyFile.MyExt"; // MyDir exists on SD card

                // Example of targetUri:
                // content://com.android.externalstorage.documents/tree/0FFF-170E%3AMyDir/MyFile.MyExt

                WriteFileToUri(targetUri);
            }
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            if (requestCode == AccessRequest)
            {
                string path = null;

                if (resultCode == Result.Ok)
                {
                    path = data.DataString;
                    Android.Net.Uri uriPath = data.Data;
                    ContentResolver.TakePersistableUriPermission(uriPath, ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission);
                }

                this.AccessIntentTaskCompletionSource?.SetResult(path);
            }
        }

        private async Task<string> AccessIntentAsync()
        {
            this.AccessIntentTaskCompletionSource = new TaskCompletionSource<string>();

            StorageManager sm = GetSystemService(StorageService) as StorageManager;
            if (sm != null)
            {
                StorageVolume volume = sm.StorageVolumes.FirstOrDefault(sv => !sv.IsPrimary); // Assume only one non-primary storage volume.

                if (volume != null)
                {
                    Intent intent = volume.CreateAccessIntent(null); // request access to the entire volume
                    StartActivityForResult(intent, AccessRequest);

                    return await this.AccessIntentTaskCompletionSource.Task;
                }
            }

            return null;
        }

        private void WriteFileToUri(string targetUri)
        {
            Android.Net.Uri outputUri = Uri.Parse(targetUri);

            byte[] source = System.Text.Encoding.UTF8.GetBytes("MyFileContent");

            using (System.IO.Stream outputStream = this.ContentResolver.OpenOutputStream(outputUri)) // throws Exception
            {
                outputStream.Write(source, 0, source.Length);
                outputStream.Close();
            }
        }
    }
}

这是清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="MyApp.MyApp" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application android:allowBackup="true" android:label="@string/app_name"></application>
</manifest>

我已经在模拟器和真实设备上测试过了。都使用Android 7.1。

SD卡以“用于传输照片和媒体”模式安装。

编辑:请求权限android.permission.WRITE_EXTERNAL_STORAGE在运行时不起作用。它只在我想写入PRIMARY外部存储时才起作用。

共有3个答案

上官英哲
2023-03-14

检查以下代码,这将有助于您了解文件保存在内存中。

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE && resultCode == RESULT_OK) {
        // Show the thumbnail on ImageView
        previewMedia();
    } else if (requestCode == REQUEST_GALLERY_PHOTO && resultCode == RESULT_OK) {
        // Show the thumbnail on ImageView
        try {
            imageUri = data.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            Cursor cursor = getActivity().getContentResolver().query(imageUri,
                    filePathColumn, null, null, null);
            cursor.moveToFirst();

            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            mCurrentPhotoPath = cursor.getString(columnIndex);
            cursor.close();
            bitmap = BitmapFactory.decodeFile(compressImage(mCurrentPhotoPath));
            preview_imageview.setImageBitmap(bitmap);
        } catch (Exception e) {
            e.getMessage();
        }

        // ScanFile so it will be appeared on Gallery
        MediaScannerConnection.scanFile(getActivity(),
                new String[]{imageUri.getPath()}, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    public void onScanCompleted(String path, Uri uri) {
                    }
                });
    }
}
农永宁
2023-03-14

您必须授予运行时权限

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.v(TAG,"Permission is granted");
    //File write logic here
    return true;
} else {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE)
}
湛联
2023-03-14
string targetUri = uriWithPermission + "MyDir/MyFile.MyExt"; // MyDir exists

即使MyDir存在,您的代码也不会像您所看到的那样工作,因为它不是那里文件的正确uri。

同样,如果用户选择了MyDir目录,您的coude看起来会像

string targetUri = uriWithPermission + "/MyFile.MyExt";

使用outputstream创建文件的代码仍然无法工作。

相反,您应该使用 DocumentFile 来获取所选目录的实例。之后,您可以使用 DocumentFile.createFile() 创建子目录或文件。

为此,您不需要清单和运行时中的常规权限。

 类似资料:
  • 我的设备是Android6.0.1操作系统,但无法将文件写入外部SD卡,从日志中,没有权限,但我有权申请成功,并在AndroidManifest中获得权限。xml文件; 我使用“adb shell dumpsys package packagename”命令,将读写权限返回到true;然后我看了一下设置- 我必须使用外部SD卡 有人遇到过这个问题吗我觉得这很奇怪 错误日志: 带系统。错误:java

  • 问题内容: 我正在使用以下代码从服务器下载文件,然后将其写入sd卡的根目录,一切正常: 但是,;表示文件将始终写入root /mnt/sdcard。是否可以指定某个文件夹来写入文件? 例如: 问题答案:

  • 我有一个应用程序使用外部存储来存储照片。根据需要,在其清单中请求以下权限 并使用以下方法检索所需的目录 在我的一部测试手机(Android one)升级到6之后,它在尝试创建必需的目录“/sdcard/pictures/myapp-yy-mm”时返回了一个错误。 sd卡配置为“便携式存储”。我已经格式化了sd卡。我已经把它换掉了。我重新启动了。都是徒劳。 此外,内置的android截图功能(通过电

  • 在我的应用程序中,我需要在设备存储器中存储大量图像。这样的文件往往满足设备存储的需要,我希望用户能够选择外部SD卡作为目标文件夹。 我到处都看到Android不允许用户写入外部SD卡,我所说的SD卡是指外部和可安装的SD卡,而不是外部存储,但文件管理器应用程序可以在所有Android版本上写入外部SD。 授予不同API级别(Pre-KitKat、KitKat、Lollipop)的外部SD卡读/写访

  • 本文向大家介绍Android 数据库SQLite 写入SD卡的方法,包括了Android 数据库SQLite 写入SD卡的方法的使用技巧和注意事项,需要的朋友参考一下 如果手机没有root,数据库文件是无法查看到的,不方便调试。 最好的办法是把数据库写进SD卡。 修改的地方有两处: 1.在你的helper类中把数据库文件名称 DATABASE_NAME 由原来的一个文件名,修改成路径的形式。 修改

  • 问题内容: 我希望我的应用程序将应用程序数据库归档到SD卡。在我的代码中,我检查目录是否存在,如果不存在,则抛出。在此特定情况下,我尝试将db文件复制到SD卡上的根目录,但是会抛出。如何更改文件夹/文件的权限以能够写入? 问题答案: 没错,SD卡目录位于其中,但您不应该对其进行硬编码。而是调用以获取目录: 如果尚未执行此操作,则需要在清单中添加以下行,以授予您的应用正确的写入SD卡的权限: