はじめに
弊社のETLシステムを差し替えることになった際に、旧システムでETL処理した old.tsv.gz
ファイルと新システムでETL処理したnew.tsv.gz
ファイルが同じ内容になっているか確認する必要が生じました。(もちろんETL前は同じファイルです。)
しかし、md5sumを取ってみると、二つのファイルのハッシュ値が異なり、原因を調査したのでまとめます。
現象
$ ls -la old.tsv.gz new.tsv.gz
-rw-rw-r-- 1 user 425983 4月 20 14:36 old.tsv.gz
-rw-rw-r-- 1 user 425983 4月 20 14:36 new.tsv.gz
ファイルサイズが同じなので、内容も同じだという気分になってきます。
しかし、md5sumを計算してみると下記のように結果が異なります。
$ md5sum old.tsv.gz new.tsv.gz
0a4d0421dbaafc3e1c2f535ff8dfa7da old.tsv.gz
6453d46698d5e237b7ae7d8686819171 new.tsv.gz
中身はきっと同じはず、、、、、
伸長(解答)したファイルの中身が一致していることを確認してみましょう。
$ gzip -d -c old.tsv.gz|md5sum
89257d0ba2167c69a7bc054ff68b4f48
$ gzip -d -c new.tsv.gz|md5sum
89257d0ba2167c69a7bc054ff68b4f48
原因
gzipコマンドのマニュアルを読んでみると下記のオプションの存在に気づきます。
-n --no-name
デフォルトでは、圧縮時に元ファイルの名前とタイムスタンプを保存させない。 (元の名前を切り詰める必要がある場合は、元の名前は必ず保存される。) 伸長時に、元のファイル名が存在しても復元せず (圧縮ファイル名から gzip 拡張子を取り除くだけとし)、 元ファイルのタイムスタンプが存在しても復元しない (圧縮ファイルからコピーする)。 このオプションは伸長時のデフォルトである。
-N --name
圧縮時に元ファイルの名前とタイムスタンプを保存する。 これがデフォルトである。 伸長時に元ファイルの名前とタイムスタンプが存在するなら復元する。 このオプションは、ファイル名の長さに制限があるシステムや、 ファイル転送の後にタイムスタンプが失われた場合に役立つ。
デフォルトのgzipコマンドで圧縮する際には、元ファイルの名前とタイムスタンプを保存します。
開発していた旧システムと新システムでは、保存されるタイミングが異なるため、タイムスタンプが異なっていたようです。
対策
用途によっては、元のファイルの名前、タイムスタンプを保存するのは不便だと感じます。
その際には、
gzip -n [file name]
としましょう。
また、pythonでgzipを作るときには、
with open('out.gz', 'wb') as f, gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0.) as gz:
gz.write(str.encode('sample content'))
とすると良いでしょう。
参考