Как правильно сохранить файл при использовании содержимого?
Я использую следующее намерение, чтобы позволить пользователю выбирать, где файл должен быть сохранен:
// 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 файла:
content://com.android.providers.downloads.documents/document/436
Но теперь я оставлен висеть, потому что этот раздел документации заканчивается
После создания нового документа вы можете получить его URI в onActivityResult(), чтобы продолжить запись в него.
И я не знаю, как это сделать. Так как мой результат использует content
Схема я не могу просто относиться к нему как к обычному Java.IO.File
и запишите это на диск. Итак, как мне сохранить файл с тем содержимым, которое у меня есть?
1 ответ
Когда вы получите содержимое Uri обратно в OnActivityResult
у вас есть временное разрешение (и, следовательно, доступ для записи) к этому Uri, поэтому вы можете открыть файловый дескриптор на основе участка в режиме записи, создать выходной поток из файлового дескриптора этого участка и записать все, что вам нужно.
Пример записи потока активов в файл, выбранный пользователем:
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).
Примечание. Это всегда будет быстрее из-за всех асинхронных / ожидающих накладных расходов и, как обычно, будет похоже на то, как я бы это делал (обычно быстрее в 2 раза (+) в зависимости от размера файла).
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);
}
}
});
}