




Чем
DirectoryвFutureотличается от того, что у меня уже есть...?
Согласно документации ничем не отличается; это тот же объект:
Возвращает
Future<Directory>, который завершается этим каталогом после его создания. Если каталог не может быть создан, будущее завершается исключением.
(мой акцент)
Не то чтобы мы не доверяли документации, но многие вещи легко неправильно истолковать, поэтому давайте быстро докажем это экспериментами. Загрузите проект cli и измените main на:
import 'package:cli/cli.dart' as cli;
import 'dart:io';
Future<void> main(List<String> arguments) async {
var d = Directory('./testing');
if (await d.exists()) {
print('Directory already exists. Remove the directory before running.');
} else {
var d2 = await d.create();
print(identical(d, d2)); // true
}
}
Когда вы его запускаете, он выводит true; d и d2 относятся к одному и тому же объекту.
Помните, что операции ввода-вывода занимают много времени (с точки зрения процессора), и create не ждет завершения операции (это createSync), он возвращает Future, когда операция завершится. Поскольку это Future может иметь значение, они просто решили сделать это значение тем же Directory объектом, который вы вызвали create.
Ответ на ваш вопрос в комментариях.
final List<int> bytes = [8, 16, 16, 32]; //immagine having something here by a web-stream
Directory theNewDirectory = Directory("/ciao/fenomeno_di_turno");
final File file = File("${theNewDirectory.path}/test.txt");
file.createSync(); // get in error
// OK . I'm going to create the directory.
// But I'm blocking the application UI flow/thread
// And what is the purpose of using await if there exists createSync();
await theNewDirectory.create();
file.createSync(); //Here can be DONE is created
await file.writeAsBytes(bytes!, flush: true);
// NOTE THAT: ANYTHING BY THIS CODE ABOVE CAN BE GUARANTEE IN A STATEFUL WIDGET WHEN IT CHANGES ITS STATE
// (ESPECIALLY IF YOU USE await's)
// OTHERWISE (WHICH IS THE ANSWER OF YOUR QUESTION)
// the purpose of use create() allows you to work on passed directory parameter
// read comments below
if (!theNewDirectory.existsSync()) {
theNewDirectory.create(recursive: true).then((Directory createdDir) {
// HERE theNewDirectory, the first one, the original varible may NOT exists if your Stateful widget have changed its STATE.
// this part always runs, once registered the listener .then((Directory createdDir) {..});
final List<int> bytes = [8, 16, 16, 32];
final File file = File("${createdDir.path}/test.txt");
file.createSync(); // Here you can do it as synchronously as you are in async mode by calling create()
file.writeAsBytes(bytes!, flush: true);
});
}
Потому что, если вы работаете в основном потоке (например, используете его при создании виджета или обновлении состояния), вы можете заблокировать его с помощью операций ввода-вывода.
Для этой цели вы можете использовать асинхронный метод Future<Directory> create({bool recursive = false}) класса Directory, который дает будущее, в котором вы можете извлечь/ожидать создания каталога, который вам нужно создать, а затем использовать его для создания файла или поиска файла/каталога и т. д. и т. п.
В противном случае, если вы уверены в том, что контекст, который вы используете
create ничего не блокирует (связанное с пользовательским интерфейсом), вместо этого вы можете использовать его напрямую void createSync({bool recursive = false}).
Даже у кого-то есть проблемы с этим ответом (насколько я вижу), который остается здесь в надежде, что вы и новые пользователи SO поймете цель .create() и почему он возвращает Directory !!
Вы правы в том, что Directory.create возвращать Future<Directory> вместо Future<void> излишне. Могло бы вернуться Future<void>. Сравните с Directory.createSync, который возвращает void.
Я предполагаю, что Directory.create, вероятно, возвращает Future<Directory> вместо Future<void>, чтобы упростить цепочку:
var directory = Directory('/some/path');
var events = (await directory.create()).watch();
Тогда как синхронная версия может использовать оператор каскада:
var directory = Directory('/some/path');
var events = (directory..createSync()).watch();
Насчет вашего предположения «Оно могло вернуться Future<void>» вы ошибаетесь. Это тоже неправильно .createSync() — это пустой метод. Будучи Future<Directory>, .create() позволяет вам после создания делать с вашим каталогом все, что вы хотите (особенно в неасинхронных методах, избегающих использования ожидания). То же самое могло быть и с createSync, он должен был возвращать каталог.
@G3nt_M3caj Какие у тебя есть доказательства того, что я не прав? Объект Directory — это просто объект, хранящий путь к каталогу. В этом нет ничего особенного. Directory('/some/path') будет одним и тем же объектом Dart до и после создания объекта файловой системы. Нет необходимости использовать create или createSync для возврата другого объекта Dart.
В контексте поддержки null лучшим вариантом является возврат электронного каталога или информации о каталоге (но dart - это не .NET). Разве это то, что нужно. Вы рассматриваете каталог как просто путь, но это не максимум жизни. Есть много вещей, которые нужно знать о каталоге i (теги, разрешения, список подкаталогов и т. д. и т. п.). Если каталог не существует, вы ничего о нем не знаете.
@G3nt_M3caj Ничто из этого не имеет отношения к объекту Dart Directory. Как я уже сказал, объект Dart — это просто оболочка пути к файловой системе. Вы можете создать Directory('/some/path') независимо от того, существует ли /some/path или продолжает ли он оставаться допустимым путем в файловой системе.
И никто из вас, написавших, не делает этот ответ неправильным. createSync возвращается void. create может вернуть Future<void> без каких-либо существенных различий (кроме некоторого незначительного синтаксического удобства, как в случае с цепочкой). Возможно, этот API не идеален для вас, но это не делает этот ответ неверным. Если вы считаете, что это неправильно, предоставьте код, который демонстрирует Directory.create() возврат (Future в a) Directory, отличного от того, к которому он был вызван.
У нас разные подходы. На мой взгляд, объект Directory как результат обоих случаев .create() (переход через Future) и .createSync() всегда лучше, чем ничего не иметь при его вызове, когда вы вынуждены выполнять тесты, если метод не возник в каком-то Исключение из-за разрешений или других. Представьте себе сценарий в виджете с состоянием, в котором он меняет свое состояние, пока вы пытаетесь создать свой каталог. Зарегистрировав анонимного прослушивателя к then((dir) => ...) без использования await, который блокирует пользовательский интерфейс, вы можете продолжить создание своего каталога, если не завершите работу без ошибок.
В противном случае переменные, как в вашем примере, не гарантируют, что задача должна быть завершена (в сложных сценариях, как я уже говорил ранее - в надежде, что кто-нибудь попытается создать каталог внутри виджета с состоянием, но используя другие подходы).
Давайте продолжим обсуждение в чате.
@Clive Потому что
create— это метод экземпляра объектаDirectory; вы уже должны начать с объектаDirectory, который представляет пока еще не созданный каталог файловой системы. В принципе, он может вернутьFuture<void>, поскольку у вас уже есть объект Dart, соответствующий нужному объекту файловой системы.