Flutter Web端:如何将上传File的函数改为上传Uint8List?
问题描述
我原本使用以下函数将应用中的文件上传至服务器:
void _upload(File file) { if (file == null) return; setState(() { _textoInfo = "subiendofotoalservidor".tr(); }); String base64Image = base64Encode(file.readAsBytesSync()); String fileName = file.path.split("/").last; http.post(Uri.parse(phpEndPoint), body: { "image": base64Image, "name": fileName, }).then((res) async { print("respuesta servidor ${res.body}"); setState(() { _textoInfo = "fotoperfilactualizada".tr(); miImagen = fileName; }); print("foto subida ${miImagen}"); _cambiarFotoAdmin(miImagen, widget.administrador.email, context); // cambiarImagenUsuario(fileName); }).catchError((err) { }); http.post(Uri.parse(phpEndPointFoto), body: { "foto":fileName, "id": miId, }).then((res) async { // cambiarImagenUsuario(fileName); Provider.of<UsuarioProvider>(context, listen: false).cambiarImagenAdministrador(fileName); }).catchError((err) { }); }
现在在浏览器中运行Flutter项目时,image_picker从电脑文件系统选择图片返回的类型为Uint8List,请问应如何将_upload(File file)修改为支持Uint8List的版本?
附选择图片的函数代码:
Future<void> _openImagePickerGallery() async { if(!kIsWeb){ final XFile? pickedImage = await _picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { setState(() { _image = File(pickedImage.path); }); } } else if(kIsWeb){ final XFile? pickedImage = await _picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { var f = await pickedImage.readAsBytes(); setState(() { hayFoto = true; webImage = f; }); // _image = File(pickedImage.path); } } }
修改方案
由于Web端无法直接获取文件路径,需要先在选择图片时保存文件名,再调整上传函数的参数和逻辑,同时兼容移动端:
- 添加状态变量存储Web端文件名
在你的State类中新增一个变量:
String? _webFileName;
- 修改选择图片函数,保存Web端文件名并调用上传
在Web分支中读取字节后保存XFile的name属性,并调用新的上传函数;移动端也同步调整调用逻辑:
Future<void> _openImagePickerGallery() async { if(!kIsWeb){ final XFile? pickedImage = await _picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { setState(() { _image = File(pickedImage.path); }); // 移动端调用上传函数 _uploadFromFile(_image!); } } else if(kIsWeb){ final XFile? pickedImage = await _picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { var f = await pickedImage.readAsBytes(); // 保存文件名 _webFileName = pickedImage.name; setState(() { hayFoto = true; webImage = f; }); // Web端调用新的上传函数 _uploadFromBytes(webImage!, _webFileName!); } } }
- 重构上传函数,支持Uint8List类型
编写通用的字节上传函数,同时可以保留File上传的兼容逻辑:
核心Uint8List上传函数
void _uploadFromBytes(Uint8List imageBytes, String fileName) { if (imageBytes.isEmpty || fileName.isEmpty) return; setState(() { _textoInfo = "subiendofotoalservidor".tr(); }); // 直接用传入的字节做base64编码 String base64Image = base64Encode(imageBytes); http.post(Uri.parse(phpEndPoint), body: { "image": base64Image, "name": fileName, }).then((res) async { print("respuesta servidor ${res.body}"); setState(() { _textoInfo = "fotoperfilactualizada".tr(); miImagen = fileName; }); print("foto subida ${miImagen}"); _cambiarFotoAdmin(miImagen, widget.administrador.email, context); }).catchError((err) { print("上传图片失败: $err"); setState(() { _textoInfo = "subidafallida".tr(); // 可添加错误提示文案 }); }); http.post(Uri.parse(phpEndPointFoto), body: { "foto": fileName, "id": miId, }).then((res) async { Provider.of<UsuarioProvider>(context, listen: false).cambiarImagenAdministrador(fileName); }).catchError((err) { print("更新用户图片记录失败: $err"); }); }
移动端File上传兼容函数(可选)
如果需要保留原File类型的上传入口,可以复用字节上传逻辑:
void _uploadFromFile(File file) { if (file == null) return; // 读取文件字节,调用通用上传函数 _uploadFromBytes(file.readAsBytesSync(), file.path.split("/").last); }
调整后,Web端和移动端都能正常完成图片上传,同时复用了核心的上传逻辑。
内容的提问来源于stack exchange,提问作者mvasco
相关产品推荐
相关产品推荐

