2014-09-19 75 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