You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web使用file_picker上传PDF:文件0字节问题求助

解决FilePicker获取PDF文件为空及上传0字节问题

问题根源

你的代码依赖withData: true直接获取文件字节,但该参数在处理较大PDF文件时可能失效(FilePicker对内存加载的文件大小有限制),导致bytes为空,最终base64字符串无效,服务器收到空内容。

可行代码示例

方案1:小文件直接获取字节(适配小PDF)

保留withData但增加空值判断,避免强制解包出错:

void pickFiles() async {
  try {
    final result = await FilePicker.platform.pickFiles(
      allowMultiple: false,
      type: FileType.custom,
      withData: true,
      allowedExtensions: ['pdf'],
    );

    if (result == null || result.files.isEmpty) return;
    
    final pickedFile = result.files.first;
    if (pickedFile.bytes == null) {
      debugPrint('无法获取文件字节,请尝试其他方案');
      return;
    }

    base64String = base64Encode(pickedFile.bytes!);
    nameDocumentController.text = pickedFile.name;
    // 执行上传逻辑
    await uploadFile(base64String, pickedFile.name);
  } on PlatformException catch (e) {
    debugPrint('不支持的操作:$e');
  } catch (e) {
    debugPrint('错误:${e.toString()}');
  }
}

// 上传示例(基于http包)
Future<void> uploadFile(String base64Str, String fileName) async {
  final url = Uri.parse('你的服务器上传接口');
  final response = await http.post(
    url,
    body: {
      'file': base64Str,
      'filename': fileName,
    },
  );

  if (response.statusCode == 200) {
    debugPrint('上传成功');
  } else {
    debugPrint('上传失败:${response.statusCode}');
  }
}

方案2:大文件通过文件路径读取(推荐,无大小限制)

放弃withData,改用获取文件路径后读取字节,适配所有大小的PDF:

void pickFiles() async {
  try {
    final result = await FilePicker.platform.pickFiles(
      allowMultiple: false,
      type: FileType.custom,
      withData: false, // 关闭内存加载
      allowedExtensions: ['pdf'],
    );

    if (result == null || result.files.isEmpty) return;
    
    final pickedFile = result.files.first;
    if (pickedFile.path == null) {
      debugPrint('无法获取文件路径');
      return;
    }

    // 从文件路径读取字节
    final file = File(pickedFile.path!);
    Uint8List fileBytes = await file.readAsBytes();
    base64String = base64Encode(fileBytes);
    nameDocumentController.text = pickedFile.name;
    
    // 执行上传
    await uploadFile(base64String, pickedFile.name);
  } on PlatformException catch (e) {
    debugPrint('不支持的操作:$e');
  } catch (e) {
    debugPrint('错误:${e.toString()}');
  }
}

方案3:直接上传文件流(无需转base64,更高效)

如果服务器支持multipart/form-data上传,直接传文件流比转base64更节省资源:

void pickAndUploadFile() async {
  try {
    final result = await FilePicker.platform.pickFiles(
      allowMultiple: false,
      type: FileType.custom,
      allowedExtensions: ['pdf'],
    );

    if (result == null || result.files.isEmpty) return;
    
    final pickedFile = result.files.first;
    if (pickedFile.path == null) return;

    final file = File(pickedFile.path!);
    final url = Uri.parse('你的服务器上传接口');
    
    var request = http.MultipartRequest('POST', url);
    request.files.add(
      await http.MultipartFile.fromPath(
        'file', // 对应服务器接收的字段名
        file.path,
        filename: pickedFile.name,
        contentType: MediaType('application', 'pdf'),
      ),
    );

    final response = await request.send();
    if (response.statusCode == 200) {
      debugPrint('上传成功');
    } else {
      debugPrint('上传失败:${response.statusCode}');
    }
  } on PlatformException catch (e) {
    debugPrint('不支持的操作:$e');
  } catch (e) {
    debugPrint('错误:${e.toString()}');
  }
}

必要配置

  • 确保在pubspec.yaml添加依赖:
    dependencies:
      file_picker: ^latest_version
      http: ^latest_version
    
  • 安卓端在AndroidManifest.xml添加权限:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
  • iOS端在Info.plist添加权限描述:
    <key>NSDocumentPickerUsageDescription</key>
    <string>需要访问您的文件以上传PDF</string>
    

内容的提问来源于stack exchange,提问作者Biagio63

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:25:57