flutterdioflutter-http

How to adjust download buffer size on flutter http, dio or flutter_downloader?


enter image description here

I want to download a large file that is amount of about 300MB. It was a lot slower than I thought, and when I looked at the log, I saw that it was fetching bytes with a size of about 8KB. I haven't found a way to resize the download buffer even if I look for other flutter libraries. How can I adjust that?


Solution

  • You can use the ChunkedStreamReader to handle the response stream using a custom chunkSize (e.g. 64KB) and write it to a file. See also this GitHub issue.

    In the below example it will listen to the response as a stream then read the bytes from the ChunkedStreamReader with the wanted chunk size (64*1024 = 64KB) and write the gotten chunks to a file.

    // Download file
    try {
      int offset = 0;
      var httpClient = http.Client();
      var request = http.Request('GET', Uri.parse(url));
      var response = httpClient.send(request);
    
      // Open file
      File file = File('$downloadPath.tmp');
    
      response.asStream().listen((http.StreamedResponse r) async {
        final reader = ChunkedStreamReader(r.stream);
        try {
          // Set buffer size to 64KB
          int chunkSize = 64 * 1024;
          Uint8List buffer;
          do {
            buffer = await reader.readBytes(chunkSize);
            // Add buffer to chunks list
            offset += buffer.length;
            print('Downloading $filename ${downloaded ~/ 1024 ~/ 1024}MB');
            // Write buffer to disk
            await file.writeAsBytes(buffer, mode: FileMode.append);
          } while (buffer.length == chunkSize);
    
          // Rename file from .tmp to non-tmp extension
          await file.rename(downloadPath);
          print('Downloaded $filename');
        } catch (e) {
          print(e);
        } finally {
          reader.cancel();
        }
      }).onDone(() async {
        // do something when finished
      });
    } catch (error) {
      print('Error downloading: $error');
    }
    

    EDIT: 12/03/2022

    I just published a package for that on pub.dev (Chunked_Downloader) where you can define the chunk size in the constructor:

    var chunkedDownloader = await ChunkedDownloader(
        url: 'https://example.com/video.mjpeg',
        savedDir: '/temp',
        fileName: 'sometestfile.mjpeg',
        chunkSize: 1024 * 1024,
        onError: (error) {},
        onProgress: (received, total, speed) {},
        onDone: (file) {})
    .start();