在加载文件之前检查其是否存在

76

我想做的是在 Material Widget 中加载一张图片,用于 ListTile 中,但这个资源可能不存在。

class MyImage extends StatelessWidget {
  final imagePath;

  MyIcon(String iconName) {
    try { // check if imagePath exists. Here is the problem
      imagePath = check('assets/$iconName.png/');
    } catch (e, s) { // if not
      imagePath = 'assets/$iconName.png/';
    }
  }

 @override
  Widget build(BuildContext context) {
    return Material(...here I will load the imagePath...);
 }
}

所以,由于我正在使用无状态小部件,我必须事先知道图像是否存在,否则我会加载空值,对吗?

4个回答

107

要检查应用程序的内部本地存储中是否存在一个文件,请使用:

import 'dart:io' as io;
var syncPath = await path;

// for a file
await io.File(syncPath).exists();
io.File(syncPath).existsSync();

// for a directory
await io.Directory(syncPath).exists();
io.Directory(syncPath).existsSync();

2
如何检查给定的路径是设备中的文件路径还是来自服务器的网络路径? - Jay Mungara
2
@JayMungara,你可以使用Validators插件中的**isURL('path')**方法来区分本地链接和网络链接。 - CodeGeek
3
File(path).exists() 返回一个 future bool 类型。如果要在无状态的 widget 中实现这一功能,或者只需使用 if 语句进行检查,请使用 File(path).existsSync(),它返回一个 bool 类型的数据。 - jayesh saha
@JayMungara - 你找到答案了吗? - Ayush Mandowara
@CodeGeek,你的解决方案对于这个问题不适用。 - Ayush Mandowara
2
@Nae 请不要推荐慢的异步 API。Dart 本身也不鼓励这样做,可以参考 Linter 规则 "avoid_slow_async_io" -> https://dart-lang.github.io/linter/lints/avoid_slow_async_io.html。 - Georg Muehlenberg

40

对我来说,简单的方法是这样的:

import 'dart:io';
File("path/to/file").exists() 

或者,为了同步检查它

import 'dart:io';
File("path/to/file").existsSync()

2
await File("path/to/file").exists()File("path/to/file").existsSync() 是一样的吗?为什么它们都存在? - Joran
3
我认为它们的存在是因为你可能处于一个没有标记为异步关键字的闭包中,但你想等待结果。我认为这是有意为之的。 - Giuse Petroso

17

看起来你想尝试从一个可能存在也可能不存在图片的文件夹中加载ImageProvider,如果它不存在,就加载一个备用的资产图像(你可以确定它会存在,因为你会把它放在根捆绑包中)。

试试这个:

ImageProvider getImageProvider(File f) {
  return f.existsSync()
      ? FileImage(f)
      : const AssetImage('images/fallback.png');
}

1
谢谢!这就是我要找的,但不知何故 f.existsSync() 总是返回 false - Isaac
3
好的,我认为这样不起作用。f.existsSync始终会返回false,因为assets不是文件,它们是可执行文件中的捆绑包,根据我提出的这个新问题的评论所说:https://dev59.com/Oq7la4cB1Zd3GeqPkd8E - Isaac
正如之前所说,您无需测试资源是否存在-您在构建时就知道了。但是,在评论中,您说“我将先前下载(半自动)”,因此这些内容将被写入可读/写目录中,因此可以测试它们是否存在。 - Richard Heap
我不明白。这些文件被写入到资产文件夹中,资产文件夹在pubspec中提到,然后应用程序被编译。然后我需要测试每当用户想要查看此团队的某些信息时,如果其图标存在,因为并不确定每个团队都有其图标。 - Isaac
1
所以,你真正想知道的是某个资产是否存在。最好的方法是包含一个额外的(文本?JSON?)资产,它是所有其他资产的列表。实际上,Flutter 为您创建了一个。它被称为 AssetManifest.json。这是一些实现细节,可能会改变,但目前似乎可以使用。 - Richard Heap
太好了!我会看一下的。 - Isaac

-3

为了检查本地存储中是否存在文件(例如image.network),现在可以使用以下代码:

Image.file(File("path/to/file"),
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {return Text('file access error');

1
这并没有回答问题提出者的问题。 - Mahesh Jamdade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接