質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

6423閲覧

Python 2 filecmp.cmpによるファイルの比較結果が、差異が無いのにFalseになる

khaii21

総合スコア65

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/06/23 15:35

#前提・実現したいこと
Python 2です。
requestsモジュールを使って、あるサイトをスクレイピングした結果をファイルに書き出しています。
前に取得した古い結果ファイルがあり、スクリプト内でfilecmp.cmp関数を使って比較をすると、
内容に差分が無いのに比較結果がFalseになります。
作成した結果ファイルはdiffコマンドで比較しても差分は無く、手動で対話形式にてilecmp.cmp関数を
使って比較をするとTrueとなります。
どなたか原因がお分かりになる方がいらっしゃいましたらご教授頂けないでしょうか。

#該当のコード

import requests import json import filecmp file_new = "/tmp/new.log" file_old = "/tmp/old.log" with open(file_new, "w") as f: # 以下にrequestsモジュールにてスクレイピングする処理を記載しています # 上記で取得した結果をJSON形式でファイルに書き出しています json.dump(result, f, ensure_ascii=False, indent=4, sort_keys=True, separators=(",", ": ")) # ファイルの比較結果がFlaseになります print(filecmp.cmp(file_old, file_new))

試してみたこと

スクリプトでは比較結果がFalseになりますが、スクリプトで作成した結果ファイルを
手動で対話形式にてilecmp.cmp関数を使って比較をすると正常にTrueとなります。

>>> import filecmp >>> file_new = "/tmp/new.log" >>> file_old = "/tmp/old.log" >>> if (filecmp.cmp(file_old, file_new)): ・・・ print("True") ・・・else: ・・・ print("False") True

diffコマンドによる比較でも差分はありません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

推測での回答になりますが
10.5. filecmp — ファイルおよびディレクトリの比較

filecmp.cmp(f1, f2[, shallow])(原文)

名前が f1 および f2 のファイルを比較し、二つのファイルが同じらしければ True を返し、そうでなければ False を返します。
shallow が真の場合、同一の os.stat() シグニチャを持つファイルは等しいとみなされます。
os.stat() シグニチャが変わらない限り、この関数を用いて比較されたファイルが再び比較されることはありません。

とあるので、処理直後のnewファイルのシグネチャが変わらないうちに古い(異なる)内容と比較している、あるいは以前のキャッシュされた比較結果が返されている可能性があります。
ここでのos.stat()はファイルサイズ、作成、更新日時などから算出されるようです。

よってfilecmp.cmp(f1, f2, False)のように、常に内容を比較するように修正すると解消する可能性があります。

別の原因についての補足

ファイルバッファの強制フラッシュ(Python)によると、比較処理時点では実ファイルの書き込みが完了していない可能性が考えられます。
よって json.dump(result, f~の後にf.flush()を追加する必要がありそうです。

投稿2018/06/23 15:59

編集2018/06/23 16:08
can110

総合スコア38266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

khaii21

2018/06/23 16:19 編集

ご回答ありがとうございます。 ご指摘の通り、スクリプト内では書き込み処理内で比較をしておりました。 書き込み処理の中ではFalseになるようです。 書き込み処理を抜けて、その後で比較するようにしたところきちんと判定できることができました。 助かりました。色々とお調べ頂きましてありがとうございます。
hayataka2049

2018/06/23 16:19

f.flush()で解決したのならこちらですね。 with抜けてもバッファに留まってるってわかりづらいけど、そうか考えてみたらそういう挙動になる訳か・・・
khaii21

2018/06/23 16:20

can110さん hayataka2049さん とても勉強になります。 ありがとうございます。
can110

2018/06/23 16:25 編集

そうですね。バッファに溜まって書き込み完了してなかったのが原因だと思います。
guest

0

filecmp.clear_cache()(原文)
filecmp のキャッシュをクリアします。背後のファイルシステムの mtime 分解能未満でのファイル変更後にすぐに比較するような場合に有用です。

11.5. filecmp — ファイルおよびディレクトリの比較 — Python 3.6.5 ドキュメント #filecmp.clear_cache

というものがあるので、逆に考えると「ファイル変更後にすぐに比較する」場合は問題が起きるということなのかしら。

python2では、

python

1filecmp._cache.clear()

filecmp.clear_cache()と同様の動作が実現できるはずです。見てわかる通り、褒められたコーディングではありません。もしこれが有効だったとしても、他の回避方法があれば、その方が良いです。

参考:
filecmp.cmp() cache - Python

投稿2018/06/23 15:54

編集2018/06/23 16:12
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

khaii21

2018/06/23 16:19 編集

ご回答ありがとうございます。 色々とお調べいただきましてありがとうございます。 ご教授頂きましたサイトを見ております。 英語が苦手でしてすぐに理解ができそうにありませんが今後の理解を深めるために調べます。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問