巨大なログを開いて探せるようになると、次に来るのは「前回と今回で、何が変わったか」です。
先月の CSV と今月の CSV。昨日のログと今日のログ。前回の納品フォルダと今回の納品フォルダ。仕様書の v1 と v2。どれも「2つを比べる」仕事ですが、ファイルが Shift-JIS だったり、行の順番がそろっていなかったり、1本が 10GB あったりします。そこで、UwView の姉妹ツールとして UwDiff を作りました。UwView で探して、UwDiff で比べる、という分け方です。
先に結論: CSV 10GB × 2本のキー照合が 21.8秒(行順ばらばらでも 23.3秒)、テキスト 10GB × 2本が 20.7秒。ただし、ほぼ全行が違う最悪の組は 110秒、メモリを 476MB に絞ると 58〜60秒
- CSV 10GB × 2本をキー列で照合: 行順そろい 21.8秒(CP932 では 20.5秒)、行順ばらばらでも 23.3秒(CP932 では 22.3秒)
- テキスト 10GB × 2本(行の並びを保つ比較・unified diff): 20.7秒・メモリ 0.4GiB
- 画面: テキスト 10GB × 2本で、「比べる」から画面に出るまで 20.5秒。最後の変更へ飛ぶのは 27ms
- フォルダ 1万本(片側 2.2GB): 3.1秒(キャッシュに載った状態)
負けを先に書きます。ほぼ全行が違う最悪の組(新を 4,096 行ごとに並べ替えた 10GB × 2本)は、テキストの比較で 110秒かかりました。行の並びがそろった組(20.7秒)の約5倍です。また、行の順番がばらばらの巨大な表は相手を待つ行をメモリに持つので、10GB × 2本で 11.1〜11.5GiB 使います。メモリの上限を 476MB にすると一時ファイルへ逃がして最後まで済みますが、58〜60秒かかります。
uvdは私が作っている UwDiff の CLI です(画面は UwDiff)。UwDiff は UwView の一部ではなく、別の製品です。この記事の数字は uvd 1.0.0 を Mac mini(Apple M4・10コア・メモリ32GB・外付け SSD)で測ったもので、キャッシュを消していない値です(データを作った直後に続けて実行。10GB × 2本はメモリに収まらないので cold に近い)。どれも結果が正解と完全に一致することを確かめたうえでの時間です。
6つの軸
UwDiff で決めたのは、「どんなファイルでも同じように比べられる」ことです。それを6つの軸に分けました。
| 軸 | できること |
|---|---|
| 形式 | テキスト(ログ・CSV・TSV・ソース)/圧縮 7 形式(gz・bz2・xz・lzma・zst・lz4・br)の中身/Word(.docx)・Excel(.xlsx)・PDF の文字 |
| 文字コード | UTF-8・Shift-JIS(CP932)・EUC-JP・UTF-16(BOM あり・なし)を自動で見分ける。旧と新で違ってもよい |
| CLI と画面 | CLI uvd で比べ、-open を付けると結果がそのまま画面に出る(画面はもう一度比べない) |
| 3OS | macOS(Apple Silicon・Intel)・Linux(x86_64・aarch64)・Windows(x64・ARM64) |
| 多数・巨大 | 1本 10GB 級のファイル、数千〜数万本のフォルダ。メモリを超えても一時ファイルへ逃がして止まらない |
| 速さ | 上の「先に結論」と、下の「速さ」の表 |
比べ方は4つ
1. テキスト — diff -u と同じ形で出す
行の並びを保って比べ、diff -u と同じ形(unified diff)で出します。出した差分を patch で旧に当てると新になります。10GB でも、旧に当てると新とバイト単位で一致することを確かめました。
diff -u 旧.log 新.log > 差分.diff
uvd ならこう書きます。
uvd 旧.log 新.log -o 差分.diff
終了コードも diff と同じです(0 = 同じ・1 = 違いあり・2 = エラー)。圧縮したログは展開せずにそのまま渡せます(uvd 旧.log.gz 新.log.zst -o -。片方だけ圧縮でもよい)。
改行コード(\r\n と \n)の違いは既定で無視します。違いとみなすなら -strict-eol を付けます。
2. 表 — キー列で照合する(行の順番が違ってもよい)
CSV・TSV・Excel を、点名や ID などのキー列で照合します。行の順番が違ってもキーで対応付け、列は見出しの名前で対応付けます(列の並びが違ってもよい)。
uvd 旧.csv 新.csv -key 点名 -o 差分.csv
uvd 台帳_9月.xlsx 台帳_10月.xlsx -key 点名 -o 差分.csv
出力は「区分・キー・列・旧値・新値」で、変わったセルごとに 1 行です。値は文字列のまま比べるので、先頭の 0・長い数字・日付らしい値が勝手に変わることはありません。
3. 採る変更だけを反映する
表の差分から、採らない行を消して(Excel で開いて消してもよい)、残った変更だけを旧に当てられます。
uvd apply 旧.csv 新.csv 採る差分.csv -o 結果.csv
旧のファイルの文字コード・BOM・区切り・改行・引用符・行の順番を保ち、変えない行はバイト単位でそのまま書きます。旧の今の値が差分の旧値と違うセルや、旧の文字コードで書けない値は、当てずに知らせます(終了コード 1)。画面でも、チェックを外して「採った変更を反映…」で同じことができます。
4. フォルダ — 下の階層まで一度に
diff -rq 納品_前回/ 納品_今回/
uvd ならこう書きます。
uvd 納品_前回/ 納品_今回/ -o 一覧.csv
旧だけ・新だけ・違う・同じの一覧を CSV で出します。-detail 差分たち/ を付けると、中身が違うファイルの差分を 1 本ずつ書きます。含める・除くの指定(-include・-exclude)は、UwView の uvf と同じ書き方です。
文字コード — 同じなら変換しない
文字コードは自動で見分けます(BOM → BOM の無い UTF-16 → UTF-8 → CP932 と EUC-JP)。旧と新が同じ文字コードなら、変換せずにそのまま比べます。 違えば両方を UTF-8 にそろえて比べます(差分の出力も UTF-8)。UTF-16 は同じどうしでも UTF-8 に直します。NEC 特殊文字・IBM 拡張文字・半角カナも化けません。
速さ(実測・条件つき)
| 比べるもの(2本とも同じ大きさ) | 時間(秒) | メモリ |
|---|---|---|
| CSV 10GB × 2本・キー照合・行順そろい(UTF-8/CP932) | 21.8/20.5 | 4.0〜4.3GiB |
| CSV 10GB × 2本・キー照合・行順ばらばら(UTF-8/CP932) | 23.3/22.3 | 11.1〜11.5GiB |
| CSV 10GB × 2本・行順ばらばら・メモリ上限 476MB(UTF-8/CP932) | 58/60 | 2.8GiB |
| テキスト 10GB × 2本・行の並びを保つ比較 | 20.7 | 0.4GiB |
| テキスト 10GB × 2本・ほぼ全行が違う最悪の組 | 110 | 1.3GiB |
| 画面: テキスト 10GB × 2本、「比べる」から画面に出るまで | 20.5 | — |
| フォルダ 1万本(片側 2.2GB・約 1% が違う) | 3.1(キャッシュに載った状態) | — |
試験データは UwDiff のリポジトリの tools/run_tests.sh と同じもの(種を固定して作る CSV。10GB は 1億534万行・正解の差分 255.9万行)です。秒は /usr/bin/time の real です。
できないこと
- Word・Excel・PDF は取り出した文字の比較です。書式・図・数式は比べません。古い .doc・.xls、パスワード付き、文字の無い PDF は読めません。
- Excel のシートの照合と「順番を問わない」比較は、差分の一覧まで(反映はしない)です。
- 1 か所で数百万行が入れ替わるような所は、その範囲を「置き換え」として出すことがあります(正しい差分ですが、最小とは限りません)。
- 画面は日本語と英語を切り替えられますが、CLI の出力は日本語のままです。
入手とライセンス
いまの版は v1.0.0「First Light」です。配布物(mac は .dmg、Linux は .tar.gz、Windows は .zip)は GitHub Releases と、このサイトのダウンロードのページ(SHA256 も載せています)から取れます。ソースから作る手順(.NET 10 SDK)は GitHub の UwDiff リポジトリにあります。
ライセンスは UwDiff License(PolyForm Internal Use 1.0.0 + 公式バイナリのパッケージ再配布の許可)です。個人利用、および企業の社内業務利用は無料です。公式バイナリを無改変のまま、無償でパッケージとして再配布することもできます(Homebrew・Scoop・Flathub・Snap・AUR など)。オープンソースソフトウェアではありません。
リンク
- UwDiff のソースと説明(GitHub): https://github.com/amru195704/UwDiff
- 操作マニュアル(GitHub): https://github.com/amru195704/UwDiff/blob/main/docs/manual.ja.md
- 実測の全データ(GitHub): https://github.com/amru195704/UwDiff/blob/main/docs/benchmarks.md
- UwDiff のページ(このサイト): https://uvp.y42u.net/uwdiff/
- 姉妹ツール UwView(探す・開く): https://uvp.y42u.net/about/
- UwView のソースコード(GitHub): https://github.com/amru195704/UwView
- 不具合・要望: https://github.com/amru195704/UwDiff/issues
開発者より: アプリ・Kindle 本・公開プロジェクトの一覧は GitHub: amru195704 にまとめています。
