COMPANY SERVICE STAFF BLOG NEWS CONTACT

STAFF BLOG

スタッフブログ

TECHNICAL

テクログ

2023.11.15

Flutterで 圧縮解凍アプリを作ってみた

テクログwindows

はじめに

お久しぶりです!
のりさんです。

今回もFlutterについて書こうと思います。

普段使っているファイルの圧縮・解凍(展開)機能
この機能をFlutterで実装できないか興味があったので
簡単な圧縮・解凍アプリをつくっていこうと思います。

今回は、しばらくさわっていなかった Windowsアプリ で実装していきます。

環境

  • Windows10 Pro
  • Android Studio Giraffe | 2022.3.1 Patch 2
  • Flutter 3.10.5

アプリの内容

今回のアプリは、以下の内容で実装していきます。

●解凍機能
 ・1ファイル(ZIP圧縮)をウィンドウにドロップしたら解凍が実行される
 ・ファイルの場所に解凍先ディレクトリを作成(ファイル名の拡張子を削除した名前)
 ・解凍が終わったら、エクスプローラーでディレクトリを開く

●圧縮機能
 ・ 1ファイル(ZIP圧縮以外)・フォルダがウィンドウにドロップされた場合、圧縮用保存ダイアログを表示
 ・2つ以上のファイル・フォルダがドロップされた場合、圧縮用保存ダイアログを表示
 ・圧縮用保存ダイアログで保存すると圧縮が実行される

利用パッケージ

今回は以下のパッケージを利用することにしました。

  • ・filepicker_windows:ファイル保存ダイアログ表示に利用
  • ・archive:ZIP圧縮・解凍処理に利用
  • ・desktop_drop:ウィンドウにドロップできるウィジェットを利用
  • ・url_launcher:解凍フォルダをエクスプローラーで開くときに利用

完成アプリ

完成したアプリは以下のようになりました!

エクスプローラからZIPファイルをウィンドウにドロップすると解凍され、フォルダが開きます
ZIP以外のファイルをウィンドウにドロップすると圧縮することができました!

準備

①プロジェクトの作成
 まずFlutter新規プロジェクト(Windows)を作成します

②アプリ起動時のウィンドウ設定
 以下の C++ファイルを修正します。

 ●windows/runner/main.cpp
  ・Win32Window::Size size(【横】, 【高さ】);
   ⇒300×300に設定しました
  ・window.Create(L”【タイトルバー文字列】”)
   ⇒圧縮解凍ツールと文字コードShift JISで修正しました

 ●windows/runner/win32_window.cpp
  CreateWindowにてウィンドウスタイルを変更
   WS_OVERLAPPEDWINDOW
        ↓
   WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX

③パッケージインストール
 以下のコマンドをターミナルで実行し、パッケージをインストールします。
 flutter pub add filepicker_windows archive desktop_drop url_launcher

ソースコード

lib/main.dartを修正します

import 'package:desktop_drop/desktop_drop.dart';
import 'package:flutter/material.dart';
import 'package:filepicker_windows/filepicker_windows.dart';
import 'package:archive/archive_io.dart';
import 'dart:io';
import 'package:url_launcher/url_launcher_string.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightBlue),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.white,
        height: double.infinity,
        width: double.infinity,
        child: DropTarget(
          onDragDone: (detail) async {

            if (detail.files.isEmpty) {
              return;
            }

            if (detail.files.length == 1 && await File(detail.files[0].path).exists() ) {
              // 1ファイルでかつ、ファイルの場合

              final fileName = detail.files[0].name;
              final filePath = detail.files[0].path;
              final dirPath = filePath.substring(0, filePath.length - fileName.length);

              if (fileName.toLowerCase().endsWith('.zip')) {
                // zip圧縮ファイルの場合
                // 解凍実行
                final newDirName = fileName.substring(0, fileName.length - 4);
                final dstDirPath = "${dirPath}${newDirName}\\";
                final inputStream = InputFileStream(filePath);
                final archive = ZipDecoder().decodeBuffer(inputStream);
                for (var file in archive.files) {
                  if (file.isFile) {
                    final outputStream = OutputFileStream('${dstDirPath}${file.name}');
                    file.writeContent(outputStream);
                    outputStream.close();
                  }
                }
                inputStream.close();
                // 解凍先のフォルダをエクスプローラで開く
                launchUrlString('file://${dstDirPath}');

                return;
              }

            }
            // 圧縮実行
            final file = SaveFilePicker()
              ..filterSpecification = {'ZIPファイル': '*.zip'}
              ..defaultFilterIndex = 0
              ..defaultExtension = '*'
              ..fileName = 'newfile.zip'
              ..title = '圧縮ファイル名を設定してください';
            final saveFilePath = file.getFile();

            if (saveFilePath != null) {
              var encoder = ZipFileEncoder();
              encoder.create(saveFilePath.path);
              for (var file in detail.files) {
                if(await File(file.path).exists()) {
                  encoder.addFile(File(file.path));
                } else if(await Directory(file.path).exists()) {
                  encoder.addDirectory(Directory(file.path));
                }
              }
              encoder.close();
            }
          },
          child: const Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Icon(Icons.file_open, size: 48, color: Colors.blueAccent,),
              SizedBox(height: 5,),
              Text("圧縮・解凍ツール"),
              SizedBox(height: 10,),
              Text("ここにドロップしてください", style: TextStyle(fontSize: 13),)
            ],
          ),
        ),
      ),
    );
  }
}

おわりに

Flutterでも圧縮解凍アプリが簡単に作れることがわかりました。
archiveパッケージはzip形式以外にも対応しているので、tarやgzipの圧縮・解凍ができるようです。

それではまた!

この記事を書いた人

のりさん

入社年2014年

出身地東京都

業務内容開発

特技・趣味水泳・筋トレ・旅行

テクログに関する記事一覧

TOP