2014-09-19 72 views
1

我有一个URL的图像列表,并希望下载并保存每个图像。不幸的是,由于堆空间耗尽,我一直收到内存不足异常。最后一次尝试保存了两个图像,然后抛出“堆空间用尽,试图分配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

如果要连续下载它们,可以切换到Future.forEach。这个枚举器通过一个集合为每个集合执行一个函数,但等待函数在返回到下一个之前返回完成的Future。反过来,它会返回一旦最终迭代完成就完成的未来。

而不是

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)); 
} 
+0

这工作完全解决我的记忆问题。我可能想重新访问以支持同时下载多个文件。谢谢。我学到了一些新东西。 – 2014-09-20 02:03:14

1

如果@DannyTuppeny s不解决您的问题,您可以增加堆大小。 我想这应该是做它

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_sizedart --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')); 
} 
+0

谢谢。我正在调查Streams选项,但让我感到很困惑。我会尝试@DannyTuppeny解决方案,并根据您的建议增加堆大小。所有的下载都在同时完成,这很可能是问题所在。 – 2014-09-20 01:50:29

+1

我更新了我的答案。 – 2014-09-20 12:50:36

+0

太棒了。谢谢。我会尝试重构我的代码以尝试解决方案。 – 2014-09-20 13:39:31