How to solve Unhandled Exception: FormatException: Could not find End of Central Directory Record while downloading file in Flutter?

557

This was likely caused by the fact that the file was not yet flushed to the filesystem after downloading before attempting to extract same. To fix this update the _downloadFile method to the following

Future<File> _downloadFile(String url, String fileName) async {
    var req = await http.Client().get(Uri.parse(url));
    var file = File('$_dir/$fileName');
    return file.writeAsBytes(req.bodyBytes, flush: true); // Added flush: true
  }

From dart:io docs

Future<File> writeAsBytes(List<int> bytes, {FileMode mode = FileMode.write, bool flush = false})

Writes a list of bytes to a file.

Opens the file, writes the list of bytes to it, and closes the file. Returns a Future<File> that completes with this [File] object once the entire operation has completed.

By default [writeAsBytes] creates the file for writing and truncates the file if it already exists. In order to append the bytes to an existing file, pass [FileMode.append] as the optional mode parameter.

Note: --> If the argument [flush] is set to true, the data written will be flushed to the file system before the returned future completes.
Share:
557
S. M. Asif
Author by

S. M. Asif

Updated on December 29, 2022

Comments

  • S. M. Asif
    S. M. Asif over 1 year

    In my Flutter project, I want to download some files as zip and then unzip it programmatically and save it in device locally. So, for that reason I followed some examples, here's the code for that-

    import 'package:flutter/material.dart';
    import 'dart:io';
    import 'package:archive/archive.dart';
    import 'package:http/http.dart' as http;
    import 'package:path_provider/path_provider.dart';
    
    class DownloadAssetsDemo extends StatefulWidget {
      DownloadAssetsDemo() : super();
    
      final String title = "Download & Extract ZIP Demo";
    
      @override
      DownloadAssetsDemoState createState() => DownloadAssetsDemoState();
    }
    
    class DownloadAssetsDemoState extends State<DownloadAssetsDemo> {
      //
      bool _downloading;
      String _dir;
      List<String> _images, _tempImages;
      String _zipPath = 'https://coderzheaven.com/youtube_flutter/images.zip';
      String _localZipFileName = 'images.zip';
    
      @override
      void initState() {
        super.initState();
        _images = List();
        _tempImages = List();
        _downloading = false;
        _initDir();
      }
    
      _initDir() async {
        if (null == _dir) {
          _dir = (await getApplicationDocumentsDirectory()).path;
        }
      }
    
      Future<File> _downloadFile(String url, String fileName) async {
        var req = await http.Client().get(Uri.parse(url));
        var file = File('$_dir/$fileName');
        return file.writeAsBytes(req.bodyBytes);
      }
    
      Future<void> _downloadZip() async {
        setState(() {
          _downloading = true;
        });
    
        _images.clear();
        _tempImages.clear();
    
        var zippedFile = await _downloadFile(_zipPath, _localZipFileName);
        await unarchiveAndSave(zippedFile);
    
        setState(() {
          _images.addAll(_tempImages);
          _downloading = false;
        });
      }
    
      unarchiveAndSave(var zippedFile) async {
        var bytes = zippedFile.readAsBytesSync();
        var archive = ZipDecoder().decodeBytes(bytes);
        for (var file in archive) {
          var fileName = '$_dir/${file.name}';
          if (file.isFile) {
            var outFile = File(fileName);
            //print('File:: ' + outFile.path);
            _tempImages.add(outFile.path);
            outFile = await outFile.create(recursive: true);
            await outFile.writeAsBytes(file.content);
          }
        }
      }
    
      buildList() {
        return Expanded(
          child: ListView.builder(
            itemCount: _images.length,
            itemBuilder: (BuildContext context, int index) {
              return Image.file(
                File(_images[index]),
                fit: BoxFit.fitWidth,
              );
            },
          ),
        );
      }
    
      progress() {
        return Container(
          width: 25,
          height: 25,
          padding: EdgeInsets.fromLTRB(0.0, 20.0, 10.0, 20.0),
          child: CircularProgressIndicator(
            strokeWidth: 3.0,
            valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
            actions: <Widget>[
              _downloading ? progress() : Container(),
              IconButton(
                icon: Icon(Icons.file_download),
                onPressed: () {
                  _downloadZip();
                },
              ),
            ],
          ),
          body: Container(
            child: Column(
              children: <Widget>[
                buildList(),
              ],
            ),
          ),
        );
      }
    } 
    

    This example, works fine with all the functionalities- zip file download, extract the file and load the images.

    But the problem is

    When I want to download the file from my desired location where I have saved a sqlite database(Size:19 mb) as a zip file, it doesn't work like the way it happened for the given code.

    It shows the following error exception-

    [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: FormatException: Could not find End of Central Directory Record

    And I am not exactly getting whether the problem is in my download path or I need to make some changes in my coding example?

    So, I need some suggestion to fix this exception and download and unzip my desired file from desired url.