如何正确下载和保存图像列表?

时间:2014-09-19 20:14:17

标签: asynchronous dart

我有一个网址图片列表,想下载并保存每张图片。不幸的是,由于堆空间不足,我一直收到Out of Memory异常。最后一次尝试保存了两个图像然后抛出“耗尽堆空间,试图分配33554464字节”。

我的代码如下所示。逻辑似乎是正确的,但我相信异步调用可能有问题。是否有一些调整我应该使下载顺序?或者我应该使用另一种方法吗?

import 'package:http/http.dart' as http;
import 'dart:io';

main() {
  // loc is a Set of valid URLs
  // ...

  loc.forEach(retrieveImage)
}

void retrieveImage(String location) {
  Uri uri = Uri.parse(location);
  String name = uri.pathSegments.last;

  print("Reading $location");
  http.readBytes(location).then((image) => saveImage(name, image));

} 

void saveImage(String name, var data) {
  new File("${name}")
    ..writeAsBytesSync(data);
  print(name);
}

2 个答案:

答案 0 :(得分:2)

如果您想按顺序下载它们,可以切换到Future.forEach。这个枚举器通过一个集合为每个执行一个函数,但等待函数返回完成后继续完成,然后继续下一个。反过来,它会返回一个在最后一次迭代完成后完成的未来。

而不是

loc.forEach(retrieveImage);

使用

Future.forEach(loc, retrieveImage);

然后确保retrieveImage返回未来:

Future retrieveImage(String location) {
  Uri uri = Uri.parse(location);
  String name = uri.pathSegments.last;

  print("Reading $location");
  return http.readBytes(location).then((image) => saveImage(name, image));
}

答案 1 :(得分:1)

如果@DannyTuppeny无法解决您的问题,您可以增加堆大小。 我认为这应该是它的旗帜

old_gen_heap_size: 1024 (Max size of old gen heap size in MB,e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap)
dart --old_gen_heap_size=1024 somefile.dart 

export DART_VM_OPTIONS="--old_gen_heap_size=1024"

http://dartbug.com/13744也提及--new_gen_heap_size,但dart --print-flags未列出。 我不知道这是否得到支持及其作用。

我在你的代码中看到的问题是,所有图像几乎立即开始下载,当它们被接收时,它们使用堆内存。另外@DannyTupeny的代码不会改变它。

您可以通过仅在先前的请求完成时调用新请求来限制同时下载的文件数,或者在接收文件时使用流将数据写入文件,因此不需要在内存中完全缓冲。 我自己还没有这样做,至少在星期天之前没有时间去研究它,但也许其他人可以为这些尝试提供更多细节。

要将传入数据直接重定向到文件而不在内存中缓冲整个文件,这应该可以工作,但我无法重现内存不足的问题,所以我不能肯定地说。

import 'dart:io' as io;
import 'dart:async' as async;
import 'package:path/path.dart' as path;
import 'package:http/http.dart' as http;

var images = [
    "https://c4.staticflickr.com/4/3880/15283361621_bc72a1fb29_z.jpg",
    "https://c2.staticflickr.com/4/3923/15101476099_6e1087b76c_h.jpg",
    "https://c2.staticflickr.com/4/3899/15288834802_073d2af478_z.jpg",
    "https://c4.staticflickr.com/4/3880/15283361621_bc72a1fb29_z.jpg",
    "https://c2.staticflickr.com/6/5575/15101869429_fa44a80e87_z.jpg",
    "https://c1.staticflickr.com/3/2941/15100232360_03f3631c44_z.jpg",
    "https://c1.staticflickr.com/3/2941/15269480156_a28e1c0dbb_b.jpg",
    "https://c2.staticflickr.com/4/3907/15103503127_195ffcd5c0_z.jpg",
    "https://c2.staticflickr.com/6/5595/15265903986_a3210505f4_c.jpg",
    "https://c2.staticflickr.com/6/5567/15100857617_9926f2a189_z.jpg",
    "https://c1.staticflickr.com/3/2941/15100542247_6e9c3f13ae_z.jpg",
    "https://c2.staticflickr.com/4/3852/15099895539_cf43a904a5_z.jpg"
];

main() {
  var futures = <async.Future>[];

  images.forEach((url) {
    futures.add(new http.Request('GET', Uri.parse(url))
    .send().then((response) {
      var f = new io.File(path.basename(url));
      var sink = f.openWrite();
      sink.addStream(response.stream)
      .then((_) => sink.close());
    }));
  });
  async.Future.wait(futures) // wait for all image downloads to be finished
  .then((_) => print('done'));
}