使用内容sheme时,保存文件的正确方法是什么? [英] Whats the correct way to save a file when using the Content sheme?

查看:152
本文介绍了使用内容sheme时,保存文件的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下意图允许用户选择文件的保存位置:

I use the following intent to allow the user to choose where a file should be saved:

// https://developer.android.com/guide/topics/providers/document-provider
var intent = new Intent(Intent.ActionCreateDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("image/png");
intent.PutExtra(Intent.ExtraTitle, "myfile");
StartActivityForResult(Intent.CreateChooser(intent, "Select Save Location"), 43);

它将创建文件并返回文件的uri:

It creates the file and returns the file's uri:

content://com.android.providers.downloads.documents/document/436

但是现在我被绞死了,因为文档的该部分以

But now I am left hanging because that section of the documentation ends with

创建新文档后,可以在onActivityResult()中获取其URI,以便您可以继续对其进行写操作.

After you create a new document you can get its URI in onActivityResult() so that you can continue to write to it.

我不知道该怎么做.由于我的结果是使用content方案,因此我不能只将其像普通的Java.IO.File一样对待并将其写入磁盘.那么如何将文件保存到我拥有的内容uri中?

And I don't know how to do that. Since my result is using the content scheme I can't just treat it like a regular Java.IO.File and write it to the disk. So how do I save a file to the content uri that I have?

推荐答案

当您在OnActivityResult中重新获得内容Uri时,您对该Uri具有临时权限(因此具有写访问权),因此您可以打开一个包裹-处于写入模式的基于文件的描述符,请从该包裹的文件描述符创建输出流,然后将其写入所需的任何内容.

When you get the content Uri back in the OnActivityResult you have temporary permission (and thus write access) to that Uri, so you can open a parcel-based file descriptor in write-mode, create a output stream from that parcel's file descriptor and write whatever you need to it.

protected async override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
    if (resultCode == Result.Ok && requestCode == 43)
    {
        var buffer = new byte[1024];
        using (var pFD = ContentResolver.OpenFileDescriptor(data.Data, "w"))
        using (var outputSteam = new FileOutputStream(pFD.FileDescriptor))
        using (var inputStream = Assets.Open("somePicture.png"))
        {
            while (inputStream.CanRead && inputStream.IsDataAvailable())
            {
                var readCount = await inputStream.ReadAsync(buffer, 0, buffer.Length);
                await outputSteam.WriteAsync(buffer, 0, readCount);
            }
        }

    }
    base.OnActivityResult(requestCode, resultCode, data);
}

更新(性能):

仅供参考,如果要保存/流式传输大文件,请避免在流上读取和写入异步版本,而只需旋转一个线程(或通过Task.Run从线程池使用一个线程).

Update (performance):

Just an FYI, if you are saving/streaming large files avoid the async versions of the Read and Write on the streams and just spin up a single thread (or use one from the threadpool via Task.Run).

注意:由于所有异步/等待开销,这将总是 更快,并且有点像我通常会做的那样(通常快2倍(+ ),具体取决于文件大小.

Note: This will always be faster due all the async/await overhead and is kind-of like normally how I would do it (typically faster by 2x(+) based upon file size).

if (resultCode == Result.Ok && requestCode == 43)
{
    await Task.Run(() =>
    {
        // Buffer size can be "tuned" to enhance read/write performance
        var buffer = new byte[1024]; 
        using (var pFD = ContentResolver.OpenFileDescriptor(data.Data, "w"))
        using (var outputSteam = new FileOutputStream(pFD.FileDescriptor))
        using (var inputStream = Assets.Open("her.png"))
        {
            while (inputStream.CanRead && inputStream.IsDataAvailable())
            {
                var readCount = inputStream.Read(buffer, 0, buffer.Length);
                outputSteam.Write(buffer, 0, readCount);
            }
        }
    });
}

这篇关于使用内容sheme时,保存文件的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆