Flutter Dio: как загрузить изображение?

Я пытаюсь проверить в Почтальон, это работа

Я хочу загрузить некоторое изображение в rest-api с помощью Package DIO Package, я новичок в этом пакете (я использую этот пакет только для операции CRUD), и у меня возникла проблема при загрузке изображения.
Я уже читаю документацию и ничего не вижу для загрузки изображений. Я пытаюсь этот код (ссылка на документацию) и получил ошибку:

error:FileSystemException
message :"Cannot retrieve length of file"
OSError (OS Error: No such file or directory, errno = 2)
"File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'"
Type (FileSystemException)
message:FileSystemException: Cannot retrieve length of file, path = 'File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'' (OS Error: No such file or directory, errno = 2)
DioErrorType (DioErrorType.DEFAULT)
name:"DioErrorType.DEFAULT"

Api.dart

Future uploadImage({dynamic data,Options options}) async{
      Response apiRespon =  await dio.post('$baseURL/mahasiswa/upload/',data: data,options: options);
      if(apiRespon.statusCode== 201){
        return apiRespon.statusCode==201;
      }else{
        print('errr');
        return null;
      }
}

View.dart

void uploadImage() async {
    FormData formData = FormData.from({
      "name_image": _txtNameImage.text,
      "image": UploadFileInfo(File("$_image"), "image.jpg")
    });
    bool upload =
        await api.uploadImage(data: formData, options: CrudComponent.options);
    upload ? print('success') : print('fail');
  }

_image типа ФАЙЛ

#

Я надеюсь, что эксперт с этим пакетом может помочь мне с этим кодом и предложить мне загрузить изображения.
Благодарю.

Полный код View.dart

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mosque/api/api_mosque.dart';

class UploadImage extends StatefulWidget {
  @override
  _UploadImageState createState() => _UploadImageState();
}

class _UploadImageState extends State<UploadImage> {
  ApiHelper api = ApiHelper();
  File _image;
  TextEditingController _txtNameImage = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.arrow_left),
          onPressed: () => Navigator.pop(context, false),
        ),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.file_upload),
            onPressed: () {
              uploadImage();
            },
          )
        ],
      ),
      body: _formUpload(),
    );
  }

  Widget _formUpload() {
    return SingleChildScrollView(
      scrollDirection: Axis.vertical,
      child: Column(
        children: <Widget>[
          TextField(
            controller: _txtNameImage,
            keyboardType: TextInputType.text,
            decoration: InputDecoration(hintText: "Nama Image"),
            maxLength: 9,
            textAlign: TextAlign.center,
          ),
          SizedBox(
            height: 50.0,
          ),
          Container(
            child: _image == null
                ? Text('No Images Selected')
                : Image.file(_image),
          ),
          SizedBox(
            height: 50.0,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                child: Icon(Icons.camera),
                onPressed: () => getImageCamera(),
              ),
              SizedBox(
                width: 50.0,
              ),
              RaisedButton(
                child: Icon(Icons.image),
                onPressed: () => getImageGallery(),
              )
            ],
          )
        ],
      ),
    );
  }

  void uploadImage() async {
    FormData formData = FormData.from({
      "name_image": _txtNameImage.text,
      "image": UploadFileInfo(File("$_image"), "image.jpg")
    });
    bool upload =
        await api.uploadImage(data: formData, options: CrudComponent.options);
    upload ? print('success') : print('fail');
  }

  getImageGallery() async {
    var imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      _image = imageFile;
    });
  }

  getImageCamera() async {
    var imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
    setState(() {
      _image = imageFile;
    });
  }
}

8 ответов

В Dio последней версии,UploadFileInfo метод был заменен на MultipartFileкласс. А вот как использовать для публикации изображения, видео или любого файла:

Future<String> uploadImage(File file) async {
    String fileName = file.path.split('/').last;
    FormData formData = FormData.fromMap({
        "file":
            await MultipartFile.fromFile(file.path, filename:fileName),
    });
    response = await dio.post("/info", data: formData);
    return response.data['id'];
}

Даже этот вопрос задают некоторое время назад, я считаю, что главная проблема заключается в size изображения, особенно с Laravel. Библиотека Flutter Image Picker предлагает некоторые функции для уменьшения размера изображения, я решил это с помощью следующих шагов:

  1. Создайте метод получения изображения, я использую Camera сделать фото

    Future getImage() async {
        var image = await ImagePicker.getImage(
        source: ImageSource.camera,
        imageQuality: 50, // <- Reduce Image quality
        maxHeight: 500,  // <- reduce the image size
        maxWidth: 500);
    
    
      _upload(image);
    
    }
    
  2. Создайте _upload способ загрузки фотографии, я использую Dioпакет Dio Package

    void _upload(File file) async {
       String fileName = file.path.split('/').last;
    
       FormData data = FormData.fromMap({
          "file": await MultipartFile.fromFile(
            file.path,
            filename: fileName,
          ),
       });
    
      Dio dio = new Dio();
    
      dio.post("http://192.168.43.225/api/media", data: data)
      .then((response) => print(response))
      .catchError((error) => print(error));
    }
    
  3. На стороне сервера я использую Laravel Laravel, я обрабатываю запрос следующим образом

    public function store(Request $request)
    {
        $file = $request->file('file');
    
        $extension = $file->getClientOriginalExtension();
    
        $fullFileName = time(). '.'. $extension;
        $file->storeAs('uploads', $fullFileName,  ['disk' => 'local']);
    
        return 'uploaded Successfully';
    }
    

В последней версии Dio:

Должно получиться вот так.

String fileName = imageFile.path.split('/').last;
FormData formData = FormData.fromMap({
  "image-param-name": await MultipartFile.fromFile(
    imageFile.path,
    filename: fileName,
    contentType: new MediaType("image", "jpeg"), //important
  ),
});

Если без этой строчки.

contentType: new MediaType("image", "jpeg")

Может это вызовет ошибку: DioError [DioErrorType.RESPONSE]: Http status error [400] Exception

И получить MediaTypeв этом пакете: http_parser

Следующий код загружает несколько файлов изображений с клиента dio на сервер golang.

  1. dioclient.dart
 FormData formData = FormData.fromMap({
   "name": "wendux",
   "age": 25,
   "other" : "params",
 });
 for (File item in yourFileList)
   formData.files.addAll([
     MapEntry("image_files", await MultipartFile.fromFile(item.path)),
   ]);
 Dio dio = new Dio()..options.baseUrl = "http://serverURL:port";
 dio.post("/uploadFile", data: formData).then((response) {
   print(response);
 }).catchError((error) => print(error));
  1. golangServer.go
package main
import (
    "fmt"
    "io"
    "net/http"
    "os"
)
func uploadFile(w http.ResponseWriter, r *http.Request) {
    err := r.ParseMultipartForm(200000)
    if err != nil {
        fmt.Fprintln(w, err)
        return
    }
    formdata := r.MultipartForm
    files := formdata.File["image_files"]
    for i, _ := range files {
        file, err := files[i].Open()
        defer file.Close()
        if err != nil {
            fmt.Fprintln(w, err)
            return
        }
        out, err := os.Create("/path/to/dir/" + files[i].Filename)
        defer out.Close()
        if err != nil {
            fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
            return
        }
        _, err = io.Copy(out, file)
        if err != nil {
            fmt.Fprintln(w, err)
            return
        }
        fmt.Fprintf(w, "Files uploaded successfully : ")
        fmt.Fprintf(w, files[i].Filename+"\n")
    }
}
func startServer() {
    http.HandleFunc("/uploadFile", uploadFile)
    http.ListenAndServe(":9983", nil)
}
func main() {
    fmt.Println("Server starts!")
    startServer()
}

Я нашел решение, в котором я загружаю файл в определенный каталог, который генерирует другой пакет камеры, для которого требуется путь к файлу для сохранения файла jpg по указанному пути.

и я получал имя файла с путем и переходил к

        DIO package

который вызывал проблему с длиной файла, поэтому я выполнил следующие шаги для решения этой проблемы.

получить имя файла с полным путем из каталога создать файл из пути

      File(directoryFilePathWithExtension);

и передайте File.path в пакет dio

      MultipartFile.fromFile(
    File(directoryFilePathWithExtension).path,
    filename: DateTime.now().toIso8601String(),
)

Использование UploadFileInfo.fromBytes если вы работаете с изображениями из памяти (вышеприведенное сообщение об ошибке показывает, что ваш файл недействителен и не существует).

Привет, есть много проблем с загрузкой файла

  1. попробуйте в android Api 21, потому что у него не было разрешений для Android, если api работает в android api 21, тогда он также будет работать с вышеуказанными версиями.

  2. Возможно, вы не сможете получить файл в указанной выше версии Android

  3. тебе просто нужно

FormData formData = FormData.fromMap({ "av_document": ждать MultipartFile.fromFile(_filePath,filename: _fileName), });

загрузить любой файл или изображение на сервер и еще кое-что на заметку

        _filePaths = await FilePicker.getMultiFilePath(type: _pickingType, 
        fileExtension: _extension);


        _fileName = _filePath.split('/').last

с помощью этого процесса вы можете загрузить файл или изображение на сервер

Я использую
dio: ^4.0.6 (для загрузки)
flutter_native_image: ^0.0.6+1 (для уменьшения размера изображения)

чтобы уменьшить размер файла

        File? compressedFile = profileImage.value == null
      ? null
      : await FlutterNativeImage.compressImage(
          profileImage.value?.path ?? '',
          quality: 20,
          percentage: 60);

dio formКарта данных

      var formData = dio.FormData.fromMap({
    "name": input['name']!.text,
    "profile_pic": await dio.MultipartFile.fromFile(compressedFile.path),
    "birth_date": input['dob']!.text,})

запрос ->

      response = await _dio.post(url, data: formData);
Другие вопросы по тегам