
Clip Hold でファイルを含む完全な履歴をインポート・エクスポートできるようにした【Clip Hold 開発日記】
みなさんこんにちは、たいくんです。
昨日と今日の二日間をかけて、私のクリップボードマネージャーであるClip Holdの履歴インポート・エクスポート機能を改善したのでご紹介します(次回のアップデートで搭載予定)。
今までのインポート・エクスポート機能
Clip Holdの最初のバージョンである1.0.0の時から既に履歴のインポートとエクスポート機能がありましたが、この時はまだリリースしたばかりの最初期のバージョンであり、今ほど機能は多くありませんでした。
Clip Holdをリリースしたばかりの頃は、定型文の管理機能をメインに開発していたこともあり、クリップボードマネージャーとしてはかなり簡易的なものでした。
それからアップデートを重ね、バージョン1.2.0ではファイルと画像の保存に対応、1.4.0ではリッチテキストやPDFファイルに対応して、最初にインポート・エクスポート機能を実装した時から多種多様な形式に対応しました。
しかし、エクスポート機能で書き出されるファイルはテキスト情報のみを含む単一のJSONファイルを出力していたこともあり、保存されていたファイルやフォルダを書き出すことができませんでした(厳密にはファイルやフォルダの情報は含まれていたものの、実際のファイルやフォルダは含まれていないためインポート後に履歴から削除されていた)。
そのため、今までのバージョンではファイルやフォルダを移行したい場合は、アプリのサンドボックス環境に保存されているディレクトリにアクセスして、保存フォルダの中身を丸ごと手動でコピーしなければなりませんでした。
手動でのコピーは面倒ですし、ほとんどのユーザはサンドボックス環境に保存されているディレクトリの場所を知らなかったり、Macに詳しくない人であればそもそも手動でコピーする操作自体が難しかったりすることもあり、重い腰を上げてファイルの書き出しに対応することにしました。
つまずいたところ
ファイルやフォルダを含むすべての履歴をエクスポートする機能の実装には、いくつかつまずいたところがありました。
書き出したファイルをどのように保存するか
まず、ファイルをどのように保存するかという点です。最初はドキュメントパッケージ形式で保存するのが良いと考えましたが、この形式特有の問題点がありました。
そもそもドキュメントパッケージとは、Macのアプリケーションなどでも使用されている形式で、フォルダを1つのファイルのように見せて保存する形式です。Macのアプリケーションは拡張子が「.app」である1つのファイルのように見えますが、実はこれはファイルではなくフォルダで、コンテキストメニュー(右クリックメニュー)から「パッケージの内容を表示」をクリックすることでフォルダの中にアクセスできます。
この形式では簡単にフォルダをパッケージ化することができるのですが、macOSでは1つのファイルのように見えるものの、中身はただのフォルダに過ぎないため、他のプラットフォームではただのフォルダに見えてしまうことです。
Clip HoldはそもそもMac専用のアプリなので他のプラットフォームから書き出した履歴ファイルにアクセスしなければならない場面はほとんどありませんが、1つ懸念点がありました。
書き出した履歴をクラウドドライブやネットワークドライブなどの外部に保存した時、1つのファイルではなくフォルダとして見えてしまうことで、一部のサービスではフォルダのアップロードやダウンロードがしづらくなってしまう可能性です。
特に、一時的な保管場所としてウェブサービスを使う場合、一部のサイトではファイル単位のアップロードには対応していても、フォルダのアップロードに対応していないことがあります。また、ダウンロードするときにサービスによって自動で圧縮され、ファイルに付与されていた一部のメタデータなどが消えてしまう可能性があることです(これは後から気づいたことですが)。
これによって、ユーザが書き出した履歴をアップロードしづらくなったり、ダウンロードして復元した一部ファイルが変わってしまったりする可能性があるのではないかと思ったのです。

この問題を解決するため、最初は単一ファイルにするために、書き出したフォルダをZIP形式で圧縮してカスタム拡張子を使用するように変更して実装しましたが、何度か復元のテストを行っていたところ、ZIP圧縮に長い時間がかかることと、一部のファイル(例えば不可視ファイルなど)からメタデータ(属性)が消えてしまっていることに気がつきました。
そこでいろいろ調べていたところ、これらの問題を解決する方法として「Apple Archive」と呼ばれる圧縮フレームワークがあるようで、これを使うことでマルチスレッドを活用した効率的な圧縮とファイルの属性を含めた転送、エラー訂正などの様々なメリットがあることがわかりました。
最終的に、Apple ArchiveのLZFSE圧縮アルゴリズムを使った圧縮を行い、拡張子を.clipholdとして保存する形式に落ち着きました。
このファイルをClip Holdでインポートすることで自動で展開が行われ、ファイルのコピーや履歴の復元が行われ、すべてのファイルと履歴が移行できるようになりました。
なお、書き出されたファイルは拡張子を「.aar」に変更して、macOS標準の「アーカイブユーティリティ」を使うことで展開することができるため、万が一Clip Holdで復元できなかった場合や書き出したファイルから特定のファイルだけを取り出したい時などにアクセスすることができます。
圧縮後の推定容量を表示したい

履歴をエクスポートする時、書き出されるファイルの容量を簡単に確認できるように、推定容量を表示したいと思っていました。
しかし、Apple Archiveフレームワークには圧縮後の推定容量を計算するような機能がないようなので、自前で計算する必要があります。ここが地味に苦戦しました。
私のコピー履歴にはテキストを除いて合計で8.7GBほどの容量を使用しているのですが、圧縮するとテキストを含めてわずか2GB程度に減っていました。
そもそもテキスト自体は150MBほどしかないのでほとんどがファイルの容量なのですが、自分が思っていたよりも結構圧縮率が高いようです。
単純に圧縮前の容量に対して大体何%ほど、といった割合をかけるだけでは環境によって大きく変わってしまう可能性があるため、実際に保存されているファイル(フォルダを除く)の先頭1MBまでを読み込んで、裏で実際に圧縮してみる実測テストを行って大体の圧縮率を出すことにしました。
ただしテストしてみたところ、ファイルの先頭は圧縮率が高めに出ることが多いようで、出てきた推定サイズが実際の圧縮後よりも小さい値だったので、これを最小値として考え、最大値として+15%のマージンを加えた容量を表示して目安を表示することにしました。
これにより、私のコピー履歴では推定サイズが1.61GB〜2.91GBと表示されました。これでもまだ結構な幅がありますが、今のところは目安としては十分機能すると考えたため、一旦これで計算はよしとしました。
今後の開発中に何か良いアイデアや方法を思いついた場合は考え直すつもりですが…
展開中の進捗を見たい

Apple Archiveフレームワークの標準機能では展開中の進捗を確認することができないようで、大きな履歴ファイルをインポートするときに展開に長い時間がかかり、その間処理がきちんと進んでいるのかどうかがわかりづらい問題がありました。
Apple Archiveフレームワークでの利点としてストリーミングアクセスがあるため、いろいろ考えたところこれを活用して、エクスポート時に総容量をメタデータとしてファイルに書き込んでおき、インポートするときに書き込んだメタデータにアクセスできるようになった瞬間に展開後の容量を確認し、展開された容量と比較することで進捗を確認することができるようになりました。
ただし、最初はメタデータを「metadata.json」として保存していましたが、展開が完了するまで進捗が更新されませんでした。
どうやら、展開はアルファベット順のファイルから行われていく特性があるようで、容量が記載されているそのファイルはアルファベット順の末尾にあったため、展開の直前まで容量を確定できなかったのです。
そこで、メタデータのファイルを「.metadata.json」として先頭にドットをつけて(不可視ファイルにしつつ)リストの先頭に配置することで、展開開始時に即座にメタデータファイルにアクセスできるようになり、進捗を確認することができるようになりました。
バージョン1.7.0は開発中です
今回紹介した内容は、Clip Holdの次期バージョンである1.7.0に搭載される予定です。なお、1.7.0は開発中であり、この記事で紹介した内容は1.7.0の正式リリースまでに変更される可能性があります。
Clip Holdのアップデート情報のお知らせは私のXアカウント(@i_am_taikun)で行いますので、ぜひフォローしていただけると幸いです。
最後まで読んでくださりありがとうございました。それでは、また!
コメントはこちらから!
記事について気になるところや質問、ご指摘など、以下のコメント欄から気軽にコメントしていただけるとうれしいです!
※コメントの投稿には、無料で作成できるGitHubアカウントが必要です。コメント欄が表示されない場合はページを再読み込みしてみてください。
コメント欄ではMarkdown記法が使用でき、画像を挿入することもできます。ここで使用できるMarkdown記法の詳しい使い方は、入力欄の右下にあるアイコンをクリックすることで確認することができます。
