Flutter笔记 关于Flutter中的大文件上传(上) 大文件上传布景与 Flutter 端完成文件分片传输
作者:李俊才 (jcLee95):blog.csdn.net/qq_28550263
邮箱 : 291148484@163.com
本文地址:blog.csdn.net/qq_28550263…
本系列上下两篇文章,包括 Flutter 端和 Django 端(后端)两个部分,讨论在 Flutter 端怎么处理大文件,以及在 Django 端怎么接纳。
目 录* * *
1. 概述
1.1 大文件上传的运用场景
在Flutter运用中,大文件上传的场景十分常见。例如,用户或许需求上传高清照片、视频或其他大型媒体文件。在企业运用中,用户或许需求上传很多的数据文件或陈述。本文的主题是在Flutter运用中完成大文件上传。咱们将探讨大文件上传的常见问题,介绍一些有用的上传战略,并供给完成这些战略的Flutter代码示例。咱们的方针是帮助读者理解怎么在Flutter运用中有用地上传大文件。
1.2 大文件上传的应战
大文件上传面对许多应战。首要,网络不稳定或许导致上传失利或速度慢。其次,因为文件巨细,上传或许需求很长时刻,而上传进展或许不明确,导致用户体验欠安。此外,假如运用在上传进程中溃散或被封闭,或许需求从头开始上传,这会糟蹋很多时刻和带宽。
1.3 全体上传局限性与优化战略
传统的文件上传办法通常是将整个文件作为一个恳求体发送到服务器。但是,这种办法对大文件来说并不抱负。因为网络不稳定,大文件有更大的或许性在上传进程中失利。此外,假如运用在上传进程中溃散或被封闭,或许需求从头开始上传。
为了处理这些问题,咱们能够采用一些战略来优化大文件的上传。
1.3.1 分块上传
例如,咱们能够运用分块上传,将文件分红多个小块,然后分别上传。这样,即使某个块上传失利,也只需求从头上传该块,而不是整个文件。
1.3.2 断点续传
另一种战略是断点续传,它答应咱们在上传被中断后从中断点持续上传,而不是从头开始。这两种战略各有优缺点。分块上传能够提高上传的成功率,但或许需求更杂乱的服务器支持。断点续传能够节约带宽,但需求服务器支持范围恳求,并且需求在客户端保存上传的进展。
2. 在Flutter中完成大文件上传前的准备
在这一章节中,咱们将详细介绍怎么在Flutter中完成大文件上传。咱们将经过以下进程来完成这个进程:获取权限、挑选文件、分块、上传和处理过错。
2.1 获取权限
在用户挑选文件之前,咱们需求确保运用有读取文件的权限。咱们能够运用permission_handler插件来恳求权限。首要,需求在pubspec.yaml文件中添加permission_handler依靠以获取权限。
dependencies:
permission_handler: 替换你装置的版别号
或许直接在项目中运转下面的指令装置最新版:
flutter pub add permission_handler
然后,咱们能够运用Permission类的request办法来恳求权限:
import 'package:permission_handler/permission_handler.dart';
void requestPermission() async {
var status = await Permission.storage.status;
if (!status.isGranted) {
status = await Permission.storage.request();
}
}
2.2 文件挑选
在获取了权限后,咱们能够运用file_picker插件来挑选文件。首要,需求在pubspec.yaml文件中添加依靠:
dependencies:
file_picker: 替换你装置的版别号
或许直接在项目中运转下面的指令装置最新版:
flutter pub add file_picker
然后,能够运用FilePicker的getFiles办法来挑选文件:
import 'package:file_picker/file_picker.dart';
void pickFile() async {
FilePickerResult? result = await FilePicker.platform.pickFiles();
if(result != null) {
PlatformFile file = result.files.first;
print(file.name);
print(file.bytes);
print(file.size);
print(file.extension);
print(file.path);
} else {
// User canceled the picker
}
}
3. 文件的切片
3.1 基本思路
在挑选了文件后,咱们需求将文件分块。分块的目的是将大文件切分红多个小块,这样咱们能够逐一上传这些小块,而不是一次性上传整个大文件。这种办法有两个长处:
- 假如某个块上传失利,咱们只需求从头上传该块,而不是整个文件;
- 咱们能够更精确地追寻上传进展,因为咱们能够知道已经上传了多少块和还剩余多少块。
3.2 完成进程
在Flutter中,咱们能够经过以下进程来完成文件分块:
- 首要,咱们需求获取文件的字节数据。
咱们能够运用PlatformFile目标的bytes特点来获取这些数据。这将回来一个Uint8List目标,它是一个包括文件一切字节的列表。 - 然后,咱们需求创立一个新的列表来存储分块的数据。
咱们能够创立一个空的List 目标来存储这些数据。 - 接下来,咱们需求遍历文件的字节数据,并将数据分块。
咱们能够运用一个循环来遍历字节数据。在每次迭代中,咱们都会取出一块数据,并将这块数据添加到分块数据的列表中。 - 最终,回来分块数据的列表。
3.3 示范事例
一个详细的完成代码如下:
List<int> splitFile(PlatformFile file, int chunkSize) {
List<int> chunks = [];
List<int> bytes = file.bytes!.toList();
for (int i = 0; i < bytes.length; i = chunkSize) {
int end = (i chunkSize < bytes.length) ? i chunkSize : bytes.length;
chunks.add(bytes.sublist(i, end));
}
return chunks;
}
其间,chunkSize参数表明每个块的巨细。
bytes.sublist(i, end) 办法用于获取从i到end的子列表,这就是咱们的一个块。
然后,将这个块添加到chunks列表中。这个进程会一直重复,直到一切的字节数据都被分块。
4. 切片的上传
在分块后,咱们能够逐一上传这些块。在这个进程中,咱们需求创立一个HTTP恳求,将每个块作为恳求的一部分,然后发送这个恳求到服务器。咱们能够运用http库来创立和发送HTTP恳求。
以下是完成这个功能的进程:
- 首要,咱们需求创立一个MultipartRequest目标。
这个目标表明一个multipart/form-data恳求,它能够包括多个文件和其他类型的数据。咱们需求指定恳求的办法(在这个例子中是POST)和URL。 - 然后,咱们需求将块添加到恳求中。
咱们能够运用MultipartFile类的fromBytes办法来创立一个文件目标,然后将这个目标添加到恳求的files列表中。 - 接下来,咱们需求发送恳求。
咱们能够运用send办法来发送恳求,这个办法会回来一个StreamedResponse目标。 - 最终,咱们需求查看响应的状况码,以确定上传是否成功。
假如状况码是200,那么上传成功;不然,上传失利。
例如:
import 'package:http/http.dart' as http;
void uploadChunk(List<int> chunk, String url) async {
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(http.MultipartFile.fromBytes('file', chunk));
var response = await request.send();
if (response.statusCode == 200) {
print('Uploaded!');
} else {
print('Failed to upload.');
}
}
其间:
chunk参数是咱们要上传的块,url参数是服务器的URL;
MultipartFile.fromBytes办法的第一个参数是文件的姓名,第二个参数是文件的字节数据;
send办法会异步发送恳求,所以咱们需求运用await关键字来等待它完成。
5. 完好完成
作为Flutter端完好完成我简单写了一下,上传到了Git Hub上,并发布在Pub.dev,地址为:pub.dev/packages/sl…。本文中各个交接解说的仅仅是思路,而在该完成的版别中,做了诸多必要的调整。我将文件挑选和上传分开。
一个Flutter端示例如下:
import 'package:flutter/material.dart';
import 'package:slivers_uploader/slivers_uploader.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'File Uploader Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final uploader = FileUploader(
chunkSize: 50 * 1024 * 1024, // 指定分块巨细,默认 1024*1024
);
MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('File Uploader Example'),
),
body: Center(
child: TextButton(
child: const Text('Upload File'),
onPressed: () async {
var file = await uploader.pickFile();
await file.upload(
url: 'http://192.168.31.239:8001/upload/',
onSuccess: (chunkNumber) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Chunk $chunkNumber upload successful!')),
);
},
onError: (chunkNumber) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Chunk $chunkNumber upload failed.')),
);
},
);
},
),
),
);
}
}
大约作用看起来是这样的:
在后端对应的能够看到经过POST发送过来的提交记载,就像我的后端这样:
下一篇文章,咱们首要介绍 Django 后端怎么完成对应的分块上传的文件。