首页 > 解决方案 > Dart - HTTPClient 下载文件到字符串

问题描述

在我目前正在开发的 Flutter/Dart 应用程序中,需要从我的服务器下载大文件。但是,我需要做的不是将文件存储在本地存储中,而是解析其内容并一次性使用它。我认为实现这一点的最佳方法是实现我自己的StreamConsumer并覆盖相关方法。这是我到目前为止所做的

import 'dart:io';
import 'dart:async';

class Accumulator extends StreamConsumer<List<int>>
{
 String text = '';

 @override
  Future<void> addStream(Stream<List<int>> s) async
  {
   print('Adding'); 
   //print(s.length); 
   return; 
  }

 @override 
 Future<dynamic> close() async
 {
  print('closed'); 
  return Future.value(text);
 }
}

Future<String> fileFetch() async
{
 String url = 'https://file.io/bse4moAYc7gW'; 
 final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
 final HttpClientResponse response = await request.close();
 return await response.pipe(Accumulator());
}

Future<void> simpleFetch() async
{
 String url = 'https://file.io/bse4moAYc7gW'; 
 final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
 final HttpClientResponse response = await request.close();
 await response.pipe(File('sample.txt').openWrite());
 print('Simple done!!');  
}

void main() async 
{
 print('Starting'); 
 await simpleFetch(); 
 String text = await fileFetch();
 print('Finished! $text');
}

当我在 VSCode 中运行它时,这是我得到的输出

Starting
Simple done!! //the contents of the file at https://file.io/bse4moAYc7gW are duly saved in the file 
sample.txt
Adding //clearly addStream is being called
Instance of 'Future<int>' //I had expected to see the length of the available data here
closed //close is clearly being called BUT
Finished! //back in main()

我对这里潜在问题的理解仍然相当有限。我的期望

  1. 我原以为我会用addStream积累正在下载的内容,直到
  2. 没有什么要下载的,此时close将调用该程序并且程序将显示exited

为什么addStream显示instance of...而不是可用内容的长度?尽管 VSCode 调试控制台确实会显示,exited但这会在显示几秒钟后发生closed。我认为这可能是不得不打电话的问题,super.close()但不是这样。我在这里做错了什么?

标签: filedartasynchronousdownloadhttpclient

解决方案


我本来打算删除这个问题,但决定在这里留下一个答案,以帮助其他尝试做类似事情的人。

需要注意的关键点是对的调用就是Accumulator.addStream这样做的——它提供了一个流listened,没有要读取的实际数据。你接下来要做的是这个

void whenData(List<int> data)
{
 //you will typically get a sequence of one or more bytes here.
 for(int value in data)
 {
  //accumulate the incoming data here
 } 
 return;
} 

function void whenDone()
{
 //now that you have all the file data *accumulated* do what you like with it
} 

@override
Future<void> addStream(Stream<List<int>> s) async
{
 s.listen(whenData,onDone:whenDone);
 //you can optionally ahandler for `onError`
}

推荐阅读