Tartışma

Python ile Dosya Karşılaştırma

Başlatan Nikolem · 09 Tem 2026 11:56 · 18 Görüntülenme · 0 Yanıtlar
Konuyu Açan #0
Dosya karşılaştırmak... İlk başta basit bir işlem gibi görünse de, aslında arkasında birçok farklı senaryo ve ihtiyaç yatıyor, değil mi? Yazılım geliştirirken versiyon kontrolü, yedekleme yaparken veri bütünlüğünü sağlamak, sistem yöneticisi olarak iki sunucu arasındaki konfigürasyon dosyalarının aynı olup olmadığını kontrol etmek veya sadece bilgisayarınızdaki gereksiz kopyaları temizlemek... Hepsi dosya karşılaştırma yeteneği gerektiriyor. Python bu konuda bize oldukça esnek ve güçlü araçlar sunuyor. Gelin, bu araçları detaylıca inceleyelim.

Neden Dosya Karşılaştırmalıyız? Temel Yaklaşımlar

Bir dosyayı bir başkasıyla karşılaştırmak dediğimizde, aslında neyi kastettiğimiz çok önemli. Sadece aynı boyutta olmaları yeterli mi, yoksa içeriklerinin de birebir aynı olması mı gerekiyor? Bu sorunun cevabına göre kullanacağımız yöntem ve harcayacağımız kaynak değişiyor.

1. Sadece Boyut Karşılaştırması:
Bu, en hızlı ve en yüzeysel yöntemdir. İki dosyanın boyutları farklıysa, içeriklerinin aynı olma ihtimali yoktur, bu kesin. Ama boyutları aynıysa, bu onların aynı olduğu anlamına gelmez. Birkaç byte bile olsa farklılıklar olabilir. Peki ne zaman işe yarar? Eğer milyonlarca dosya arasında hızlıca ilk elemeyi yapmak istiyorsanız, boyut kontrolü harika bir başlangıç noktasıdır. Mesela, "bu dosya kesinlikle değişti çünkü boyutu farklı" diyebilirsiniz, ama "bu dosya değişmedi çünkü boyutu aynı" diyemezsiniz.

2. Hash (Özet) Değerleri ile Karşılaştırma:
İşte burası işlerin biraz daha ilginçleştiği yer. Herhangi bir dosyanın içeriğini alıp, belirli bir algoritma (MD5, SHA-1, SHA-256 gibi) kullanarak sabit uzunlukta bir "parmak izi" oluştururuz. Bu parmak izine hash veya özet değeri denir. Dosyanın içeriğinde tek bir bit bile değişse, hash değeri tamamen farklı çıkacaktır. Bu da hash değerlerini dosya bütünlüğü kontrolü için inanılmaz güvenilir bir yöntem yapar. İki dosyanın hash değerleri aynıysa, içeriklerinin de %99.999 aynı olduğunu varsayabiliriz. Teorik olarak "hash çarpışması" denilen, farklı içeriklerin aynı hash değerini üretmesi durumu mümkün olsa da, modern algoritmalarla bu olasılık pratik uygulamalar için ihmal edilebilir düzeydedir. Özellikle büyük dosyalar için, byte-by-byte karşılaştırmaya göre çok daha hızlıdır, çünkü dosyanın tamamını belleğe almak yerine, sadece üzerinde işlem yapar ve bir hash değeri üretir.

3. Byte-by-Byte Karşılaştırma:
En kesin yöntem budur. İki dosyanın her bir byte'ını tek tek okuyup karşılaştırırız. Eğer tek bir byte bile farklıysa, dosyalar farklıdır. Bu yöntem %100 doğruluk sağlar ama aynı zamanda en yavaş olanıdır. Özellikle çok büyük dosyalarla çalışırken performans ciddi bir sorun haline gelebilir. Genellikle, önce boyut ve hash kontrolü yapıldıktan sonra, eğer bu kontroller aynı sonucu veriyorsa ama yine de tam bir emin olmak isteniyorsa başvurulan bir yöntemdir.

Python'ın Yerleşik Modülleri ile Çözümler

Python, bu farklı yaklaşımları uygulamak için zengin bir standart kütüphane sunuyor.

os Modülü: Boyut Kontrolü

Dosya boyutlarını almak için os modülündeki os.path.getsize() fonksiyonunu kullanabiliriz. Bu, hızlı bir ön kontrol için idealdir.

CODE
1234567891011121314151617181920212223242526272829303132333435
import os

def dosya_boyutu_karsilastir(dosya1_yolu, dosya2_yolu):
    """
    İki dosyanın boyutlarını karşılaştırır.
    """
    if not os.path.exists(dosya1_yolu):
        print(f"Hata: {dosya1_yolu} bulunamadı.")
        return False
    if not os.path.exists(dosya2_yolu):
        print(f"Hata: {dosya2_yolu} bulunamadı.")
        return False

    boyut1 = os.path.getsize(dosya1_yolu)
    boyut2 = os.path.getsize(dosya2_yolu)

    if boyut1 == boyut2:
        print(f"'{dosya1_yolu}' ve '{dosya2_yolu}' aynı boyutta ({boyut1} byte).")
        return True
    else:
        print(f"'{dosya1_yolu}' ({boyut1} byte) ve '{dosya2_yolu}' ({boyut2} byte) farklı boyutta.")
        return False

[b]Kullanım örneği:[/b]
[b]Önce test dosyaları oluşturalım[/b]
with open("test1.txt", "w") as f:
    f.write("Bu ilk dosya.")
with open("test2.txt", "w") as f:
    f.write("Bu ikinci dosya.")
with open("test3.txt", "w") as f:
    f.write("Bu ilk dosya.") # test1 ile aynı içerik, aynı boyut

dosya_boyutu_karsilastir("test1.txt", "test2.txt")
dosya_boyutu_karsilastir("test1.txt", "test3.txt")


Gördüğünüz gibi, test1.txt ve test3.txt aynı boyutta olsa da, bu onların içeriklerinin aynı olduğunu garanti etmez. İşte bu noktada hashlib devreye giriyor.

hashlib Modülü: Güvenilir Hash Kontrolü

Python'ın hashlib modülü, MD5, SHA1, SHA256 gibi birçok popüler şifreleme hash algoritmasını uygulamak için harika bir araçtır. Özellikle büyük dosyalarla çalışırken, dosyanın tamamını bir kerede belleğe yüklemek yerine, parçalar halinde okuyup hash'ini güncellemek çok önemlidir.

CODE
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
import hashlib
import os

def dosya_hash_karsilastir(dosya1_yolu, dosya2_yolu, algoritma="sha256", chunk_size=4096):
    """
    İki dosyanın belirtilen algoritma ile hash değerlerini karşılaştırır.
    Büyük dosyalar için parçalar halinde okuma yapar.
    """
    if not os.path.exists(dosya1_yolu) or not os.path.exists(dosya2_yolu):
        print("Hata: Dosyalardan biri veya ikisi bulunamadı.")
        return False

    def get_file_hash(filepath):
        hasher = hashlib.new(algoritma)
        try:
            with open(filepath, 'rb') as f:
                for chunk in iter(lambda: f.read(chunk_size), b''):
                    hasher.update(chunk)
            return hasher.hexdigest()
        except IOError as e:
            print(f"Dosya okuma hatası '{filepath}': {e}")
            return None

    hash1 = get_file_hash(dosya1_yolu)
    hash2 = get_file_hash(dosya2_yolu)

    if hash1 is None or hash2 is None:
        return False

    if hash1 == hash2:
        print(f"'{dosya1_yolu}' ve '{dosya2_yolu}' aynı hash değerine sahip ({algoritma}: {hash1}). Dosyalar aynı.")
        return True
    else:
        print(f"'{dosya1_yolu}' ({hash1}) ve '{dosya2_yolu}' ({hash2}) farklı hash değerlerine sahip. Dosyalar farklı.")
        return False

[b]Kullanım örneği:[/b]
[b]test1.txt ve test3.txt'nin içerikleri aynıydı[/b]
dosya_hash_karsilastir("test1.txt", "test3.txt", algoritma="md5")
dosya_hash_karsilastir("test1.txt", "test2.txt", algoritma="sha256")

[b]test2.txt'nin içeriğini değiştirelim ve tekrar karşılaştıralım[/b]
with open("test2.txt", "w") as f:
    f.write("Bu ikinci dosya, şimdi içeriği farklı.")
dosya_hash_karsilastir("test1.txt", "test2.txt", algoritma="md5") # İçerik değiştiği için hash de değişecek


Bu örnekte, chunk_size parametresi, dosyanın kaçar byte'lık parçalar halinde okunacağını belirliyor. Bu yaklaşım, gigabaytlarca büyüklükteki dosyalar için bile bellek dostu bir çözüm sunar.

filecmp Modülü: Yüksek Seviyeli Karşılaştırma

Python'ın filecmp modülü, dosya ve dizin karşılaştırma işlemleri için özel olarak tasarlanmış, daha yüksek seviyeli fonksiyonlar sunar. Kendi başımıza bir şeyler yazmak yerine, bu modülü kullanmak çoğu zaman daha pratik ve hatasız bir çözüm olabilir.

filecmp.cmp(): İki Dosyanın Karşılaştırılması

filecmp.cmp(f1, f2, shallow=True) fonksiyonu, iki dosyayı karşılaştırır. shallow parametresi, karşılaştırmanın ne kadar derin olacağını belirler:
  • shallow=True (varsayılan): Dosya boyutunu ve son değiştirilme zamanını (timestamp) karşılaştırır. Eğer bunlar aynıysa, dosyaların aynı olduğunu varsayar. Bu, hızlı bir kontrol sağlar.
  • shallow=False: Dosya boyutunu, son değiştirilme zamanını ve eğer bunlar aynıysa, dosya içeriklerini byte-by-byte karşılaştırır. Bu, daha kesin bir sonuç verir.

CODE
12345678910111213141516171819202122232425262728293031
import filecmp
import os

[b]Test dosyalarını temizleyelim ve yeniden oluşturalım[/b]
if os.path.exists("test1.txt"): os.remove("test1.txt")
if os.path.exists("test2.txt"): os.remove("test2.txt")
if os.path.exists("test3.txt"): os.remove("test3.txt")

with open("test1.txt", "w") as f:
    f.write("Merhaba dünya!")
with open("test2.txt", "w") as f:
    f.write("Merhaba Python!")
with open("test3.txt", "w") as f:
    f.write("Merhaba dünya!") # test1 ile aynı içerik

print(f"test1.txt ve test2.txt karşılaştırması (shallow=True): {filecmp.cmp('test1.txt', 'test2.txt', shallow=True)}")
print(f"test1.txt ve test3.txt karşılaştırması (shallow=True): {filecmp.cmp('test1.txt', 'test3.txt', shallow=True)}")
print(f"test1.txt ve test3.txt karşılaştırması (shallow=False): {filecmp.cmp('test1.txt', 'test3.txt', shallow=False)}")

[b]shallow=True için bir durum:[/b]
[b]Aynı içerikli ama farklı zaman damgalı dosyalar oluşturmak[/b]
import time
with open("test4.txt", "w") as f:
    f.write("Farklı zaman damgası.")
time.sleep(1) # Bir saniye bekle
with open("test5.txt", "w") as f:
    f.write("Farklı zaman damgası.")

print(f"test4.txt ve test5.txt karşılaştırması (shallow=True): {filecmp.cmp('test4.txt', 'test5.txt', shallow=True)}") # False dönebilir
print(f"test4.txt ve test5.txt karşılaştırması (shallow=False): {filecmp.cmp('test4.txt', 'test5.txt', shallow=False)}") # True dönecek


shallow=True durumunda, dosyanın içeriği aynı olsa bile, son değiştirilme zamanları farklı olduğu için False dönebilir. Bu, bazen yanıltıcı olabilir, bu yüzden genellikle shallow=False kullanmak daha güvenli bir yaklaşımdır.

filecmp.dircmp(): Dizinlerin Karşılaştırılması

Asıl gücü filecmp modülünün dizin karşılaştırma yeteneğinde yatıyor. filecmp.dircmp(a, b) fonksiyonu, iki dizini (a ve b) karşılaştırır ve karşılaştırma sonuçlarını içeren bir dircmp nesnesi döndürür. Bu nesne, dizinler arasındaki farklılıkları detaylı bir şekilde raporlamanızı sağlar.

CODE
1234567891011121314151617181920212223242526272829303132333435363738394041424344
import filecmp
import os

[b]Test dizinleri oluşturalım[/b]
if not os.path.exists("dir1"): os.makedirs("dir1")
if not os.path.exists("dir2"): os.makedirs("dir2")
if not os.path.exists("dir3"): os.makedirs("dir3")

with open("dir1/fileA.txt", "w") as f: f.write("Bu A dosyası.")
with open("dir1/fileB.txt", "w") as f: f.write("Bu B dosyası.")
with open("dir1/fileC.txt", "w") as f: f.write("Bu C dosyası.")

with open("dir2/fileA.txt", "w") as f: f.write("Bu A dosyası.") # dir1/fileA ile aynı
with open("dir2/fileB.txt", "w") as f: f.write("Bu B dosyası, ama farklı.") # dir1/fileB'den farklı
with open("dir2/fileD.txt", "w") as f: f.write("Bu D dosyası.") # dir1'de yok

with open("dir3/fileA.txt", "w") as f: f.write("Bu A dosyası.")
with open("dir3/fileB.txt", "w") as f: f.write("Bu B dosyası.")
with open("dir3/fileC.txt", "w") as f: f.write("Bu C dosyası.")

[b]dir1 ve dir2'yi karşılaştıralım[/b]
print("\n--- 'dir1' ve 'dir2' Karşılaştırması ---")
dc = filecmp.dircmp("dir1", "dir2")

print("Sadece dir1'de olan dosyalar:", dc.left_only)
print("Sadece dir2'de olan dosyalar:", dc.right_only)
print("Her iki dizinde de olan dosyalar:", dc.common)
print("İçeriği aynı olan dosyalar (shallow=True):", dc.same_files) # shallow=True'ye göre
print("İçeriği farklı olan dosyalar (shallow=True):", dc.diff_files) # shallow=True'ye göre
print("Karşılaştırılamayan dosyalar (örn: farklı tipler):", dc.funny_files)

[b]Daha derin bir karşılaştırma için report() veya report_full_closure() kullanabiliriz[/b]
[b]dc.report()[/b]
[b]dc.report_full_closure() # Alt dizinleri de karşılaştırır[/b]

[b]dir1 ve dir3'ü karşılaştıralım (aynı olmalılar)[/b]
print("\n--- 'dir1' ve 'dir3' Karşılaştırması ---")
dc2 = filecmp.dircmp("dir1", "dir3")
print("Sadece dir1'de olan dosyalar:", dc2.left_only)
print("Sadece dir3'te olan dosyalar:", dc2.right_only)
print("İçeriği farklı olan dosyalar:", dc2.diff_files)
print("Ortak dosyalar:", dc2.common)
print("Ortak ve aynı içerikli dosyalar:", dc2.same_files)


dircmp nesnesi, left_only, right_only, common, same_files, diff_files gibi birçok kullanışlı özelliğe sahiptir. Bu özellikler sayesinde, dizinler arasındaki farklılıkları kolayca tespit edebilir ve raporlayabilirsiniz. Bu, özellikle büyük kod tabanları, yedekleme senaryoları veya iki sunucu üzerindeki konfigürasyonları senkronize etmek gibi durumlarda çok işe yarar.

Manuel Byte-by-Byte Karşılaştırma: En Detaylı Yöntem

Eğer filecmp.cmp(shallow=False) sizin için yeterli değilse (ki çoğu zaman yeterlidir) veya kendi özel mantığınızı uygulamak istiyorsanız, dosyaları manuel olarak byte-by-byte karşılaştırabilirsiniz. Bu, özellikle performans kritik uygulamalarda veya karşılaştırma sırasında belirli bir mantık (örneğin, dosyanın sadece bir kısmını karşılaştırmak, belirli byte'ları atlamak) uygulamak istediğinizde faydalı olabilir.

CODE
12345678910111213141516171819202122232425262728293031323334
import os

def manuel_byte_by_byte_karsilastir(dosya1_yolu, dosya2_yolu, chunk_size=4096):
    """
    İki dosyayı manuel olarak byte-by-byte karşılaştırır.
    """
    if not os.path.exists(dosya1_yolu) or not os.path.exists(dosya2_yolu):
        print("Hata: Dosyalardan biri veya ikisi bulunamadı.")
        return False

    # Önce boyut kontrolü, gereksiz okumadan kaçınmak için
    if os.path.getsize(dosya1_yolu) != os.path.getsize(dosya2_yolu):
        print("Dosya boyutları farklı, içerik kesinlikle farklı.")
        return False

    with open(dosya1_yolu, 'rb') as f1, open(dosya2_yolu, 'rb') as f2:
        while True:
            bytes1 = f1.read(chunk_size)
            bytes2 = f2.read(chunk_size)

            if bytes1 != bytes2:
                print("Dosyalar içerik olarak farklı.")
                return False

            if not bytes1: # Dosya sonuna gelindi
                break
    
    print("Dosyalar içerik olarak aynı.")
    return True

[b]Kullanım örneği:[/b]
manuel_byte_by_byte_karsilastir("test1.txt", "test3.txt")
manuel_byte_by_byte_karsilastir("test1.txt", "test2.txt") # test2 farklı içerikliydi


Bu fonksiyon, önce boyutları kontrol ederek gereksiz okumaları engeller. Ardından, dosyaları belirlediğimiz chunk_size kadar parçalar halinde okur ve her bir parçayı karşılaştırır. Eğer herhangi bir noktada parçalar farklı çıkarsa, fonksiyon hemen False döndürür. Bu yöntem, büyük dosyalar için bile bellek dostu bir yaklaşımdır.

Performans ve Büyük Dosyalar İçin İpuçları

Büyük dosyalarla çalışırken performans kritik bir konu haline geliyor. İşte birkaç önemli ipucu:

  • Aşamalı Karşılaştırma: Her zaman en hızlı ve en yüzeysel kontrolle başlayın. Önce boyutları kontrol edin. Farklıysa, devam etmenize gerek yok. Aynıysa, hash kontrolüne geçin. Hash'ler farklıysa yine devam etmeye gerek kalmaz. Sadece boyut ve hash aynıysa ve %100 kesinlik istiyorsanız byte-by-byte karşılaştırmaya geçin. Bu "erken çıkış" stratejisi, gereksiz işlem yükünü büyük ölçüde azaltır.
  • Chunking (Parçalara Ayırma): hashlib ve manuel byte-by-byte karşılaştırma örneklerinde gördüğünüz gibi, dosyaları küçük parçalar halinde okumak, bellekte büyük dosyaların tamamını tutma ihtiyacını ortadan kaldırır. Bu, özellikle RAM'i kısıtlı sistemlerde çok önemlidir. Genellikle 4KB (4096 byte) veya 8KB gibi değerler makul bir başlangıç noktasıdır.
  • Doğru Hash Algoritmasını Seçmek: MD5, SHA-1 gibi algoritmalar daha hızlıdır ancak güvenlik açıkları nedeniyle kritik güvenlik uygulamalarında tercih edilmezler. SHA-256 veya SHA-512 gibi daha modern algoritmalar daha güvenlidir ancak biraz daha yavaş olabilirler. Sadece dosya bütünlüğü kontrolü için kullanıyorsanız, hız ve güvenlik arasında bir denge kurmalısınız.
  • G/Ç İşlemlerini Minimize Etmek: Dosya okuma/yazma (G/Ç) işlemleri genellikle CPU işlemlerinden çok daha yavaştır. Mümkün olduğunca az G/Ç işlemi yapmaya çalışın. Örneğin, bir dosyanın hash'ini hesaplarken, tüm dosyayı tek bir geçişte okuyup hash'i güncellemek en verimli yoldur.

Hata Yönetimi ve Özel Durumlar

Gerçek dünya senaryolarında her zaman her şey yolunda gitmez, değil mi? Dosyalar bulunamayabilir, erişim izinleri olmayabilir veya okuma sırasında başka hatalar oluşabilir. Kodlarınızda bu tür durumları ele almak, uygulamanızın daha sağlam olmasını sağlar.

  • Dosya Bulunamadı: os.path.exists() ile dosyanın varlığını kontrol etmek veya try-except FileNotFoundError blokları kullanmak önemlidir.
  • Erişim İzinleri: Bir dosyayı okumak için yeterli izniniz yoksa PermissionError alırsınız. Yine try-except blokları ile bu durumu yakalayıp kullanıcıya bilgi verebilirsiniz.
  • Boş Dosyalar: Boş dosyaların boyutları 0'dır ve hash değerleri de belirli bir sabite eşit olacaktır. Bu durumu özel olarak ele almanız gerekebilir mi, yoksa genel mantığınız içinde mi çözülüyor, bunu düşünmelisiniz.
  • Sembolik Bağlantılar (Symlinks): os.path.getsize() gibi bazı fonksiyonlar, sembolik bağlantının hedefinin boyutunu döndürür. Ancak filecmp modülü sembolik bağlantıları farklı şekilde ele alabilir. Sembolik bağlantıları takip edip etmeyeceğinize karar vermeniz gerekebilir.

Kapanış: Sizin Deneyimleriniz Neler?

Python ile dosya karşılaştırma üzerine detaylı bir bakış atmış olduk. Gördüğünüz gibi, ihtiyaca göre boyut kontrolünden, hash değerlerine, hatta dizin karşılaştırmasına kadar birçok farklı araç ve yöntem mevcut. Önemli olan, kendi senaryonuz için en uygun ve verimli yöntemi seçebilmek.

Peki siz bu konuda neler yapıyorsunuz? Büyük veri setleriyle çalışırken hangi yöntemleri tercih ediyorsunuz? Ya da bu konuda karşılaştığınız ilginç sorunlar veya geliştirdiğiniz özel çözümler var mı? Yorumlarda paylaşabilirseniz, hepimiz için çok değerli bir bilgi kaynağı olur!

Yanıt vermek için giriş yapmış olmalısınız.

0 alıntı seçildi