Forum: D Programlama Dili RSS
Tüm Dosyaları MD5'lemek! (hızlı çözüm)
Avatar
Salih Dinçer #1
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Tüm Dosyaları MD5'lemek! (hızlı çözüm)
Merhaba,

Dün akşam şurada paylaştığım işe yarar uygulamayı, burada da paylaşmamak olmaz diye düşündüm. Bunu yapmadan önce biraz daha geliştirip (artık dirEntries() sayesinde alt dizinleri özyinelemi olarak tarıyor!) ve önemli bir kaç hatasını giderdim...
/*
 *   genMD5files.d (v1.2)
 */
import std.stdio, std.conv, std.file, std.md5;
 
struct container {
    char[1024] buffer;
 
    string toString() {
        int[] primes = [ 3, 5, 11, 17, 29, 41, 59, 71, 101,
                         107, 137, 149, 179, 191, 197, 227,
                         239, 269, 281, 311, 347, 419, 431,
                         461, 521, 569, 599, 617, 641, 659,
                         809, 821, 827, 857, 881, 1019 ];
        char[][] md5;
 
        foreach(x; primes) {
            if(x < buffer.length) {
                md5 ~= [ buffer[x..x+1], buffer[x+2..x+3] ];
            }
        }
        return getDigestString(to!string(md5));
    }
}
 
void main(string[] args) {
    string path = args.length > 1 ? args[1] : ".";
    SpanMode mode = args.length > 2 ? args[2] == "-R" ?
                                    SpanMode.breadth :
                                    SpanMode.depth :
                                    SpanMode.shallow;
        
    foreach(string name; dirEntries(path, mode)){
        container t;
        if( ! isDir(name) ) {
            auto data = File(name, "r");
            data.rawRead(t.buffer);
            t.writeln(" (", name, ")");
        }
    }
}
Kullanmak için genMD5files . -R veya sadece bulunduğunuz yerdeki başka bir dizin için genMD5files obj ve ./obj/ dizini altındakiler için ise -R de ekleyebilirsiniz. Aslında -Mö de deseniz farketmiyor çünkü recursive olan diğer mode'a geçiyor. Şimdilik bu kadar geliştirme yeter...:)

Başarılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj 3 defa değişti; son değiştiren: Salih Dinçer; zaman: 2012-10-09, 12:17.
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Güzel ve kısa. :)

container.buffer'ın static olmasını riskli görüyorum. İki container nesnesi aynı anda kullanılsa buffer'ı paylaştıkları belli olmuyor:
    dosya0.rawRead(t0.buffer);
    dosya1.rawRead(t1.buffer);    // t0.buffer'ın üstüne yazdı 

Bir de, container'ı kullananların onun bir üyesinin içine okumaları sarmayı deliyor. :) Herkes kendisine ait bir yere okusa ve ondan sonra "şunu md5'le" dese daha kullanışlı olur.

Hatta, işlemin toString içinde yapılıyor olması olaya gizem katmış. ;) Tabii toString'i yavaşlatıyor da.

Bir soru: rawRead, kısa bir dosya geldiğinde 1024'ten az bayt okuyordur. O zaman buffer'ın son tarafında hâlâ önceki dosyanın baytları duruyordur, değil mi? Bir hata mı?

Ali
Avatar
Salih Dinçer #3
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Güzel ve akıllıca...:)

Öncelikle bu akıllıca sorulardan şu şekilde yırtayım:

Kodun şu hale gelmesine dirEntries() işlevi sebep oldu, suçlu o!

Şaka bir yana gerçekten de eski sürümlerde (<1) olmayan bu sorunlar, sırf özyinelemeli özellikleri için zorunda kaldığım hususlar oldu. Örneğin with()'i kaldırıp struct'a çevirmem ve buffer'a static özelliğini koymam hep dirEntries() işlevinin nanemollalığı...)

Çünkü hep parçalama hatası alıyordum. Ali hocam bilir, with()'i kullanmayı çok severim. Onu kaldıracak derecede zart zurt etmesi bana bu kadar köklü değişikliğe gitmeme sebep oldu. Hoş özyinelemeli olması dışında şu özellikleri gerçekten tercih edilesi bırakıyor:
  • Önceki işlev listDir() emekliye ayrılması
  • Dosyanın tam yolunu döndürmesi
  • İşletim sistemine göre slash ve ters slash ayrımını hissetmesi
  • Çalıştırırken parametre serbestliği (obj, ./obj, obj/ ve ./obj/ hep aynı)

Yine de var olan sorunları farklı şekillerde halledebileceğimizi düşünüyorum...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #4
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Az önce yukarıdaki kodu değiştirdim. Çünkü tek çözüm olarak taşıyıcının kurulduğu satırı döngü içine almak geldi. Ancak ne hikmetse buna gerek yok. Eğer bir şeyleri karıştırmadıysam (gerçi basit bir denemeydi) 1 KB'dan küçük dosyalarda MD5 kodu her iki çözümde de aynı:
F0144C70A8CA250061EB456D9DFFEFD8 (.\opengl.d)
F0144C70A8CA250061EB456D9DFFEFD8<- emin olmak için sadece MD5'i kopyaladım...

İyice emin olmak için MD5'den önceki değerleri ekrana yansıttım. Son düzenleme de çözüm değilmiş! Oysa her döngü yenilendiğinde container nesnesi tekrar kurulmaz mı?

["G", "\n", "\n", "\n", "\r", "H", "\x00", x"A5"c, x"B1"c, "o", "\x00", x"CE"c, x"FC"c, "\
x05", "\x00", x"C2"c, "f", x"E9"c, x"C6"c, "\r", x"DD"c, "P", x"AA"c, "j", "0", x"CC"c, "#
", x"F7"c, "\f", "y", "\"", x"B9"c, x"97"c, x"F7"c, "(", x"97"c, "v", "4", x"DF"c, "1", x"
F0"c, x"9D"c, x"95"c, "*", "\x1B", x"D6"c, "\a", x"E6"c, x"8B"c, x"C0"c, x"D9"c, "z", x"F2
"c, "2", "|", x"B4"c, x"D5"c, "\x1C", x"F7"c, x"8D"c, "\x02", "\b", "\x02", "\b", x"80"c,
"\x01", "\x00", "\x02", "\x01", "\x04", x"D1"c, x"BB"c
] (veriler\primes.img)
["h", " ", " ", "f", "e", "h", ".", "x", "d", "l", "\n", "e", "o", "j", "\x00", x"C2"c, "f
", x"E9"c, x"C6"c, "\r", x"DD"c, "P", x"AA"c, "j", "0", x"CC"c, "#", x"F7"c, "\f", "y", "\
"", x"B9"c, x"97"c, x"F7"c, "(", x"97"c, "v", "4", x"DF"c, "1", x"F0"c, x"9D"c, x"95"c, "*
", "\x1B", x"D6"c, "\a", x"E6"c, x"8B"c, x"C0"c, x"D9"c, "z", x"F2"c, "2", "|", x"B4"c, x"
D5"c, "\x1C", x"F7"c, x"8D"c, "\x02", "\b", "\x02", "\b", x"80"c, "\x01", "\x00", "\x02",
"\x01", "\x04", x"D1"c, x"BB"c
] (veriler\clear.bat)

Maviler aynı yani önceki döngüden buffer[]'dan kalanlar...:(
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2012-10-09, 11:49.
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
dirEntries'in daha önce gösterdiği bir dosya uzun olsun (1024 veya daha büyük). Onun baytları buffer'da kalacaklar.

Daha sonra okunan bir dosya daha kısa olsun. toString'in içinde foreach primes'ı gezerken önceki dosyanın baytlarını da kullanır.

Eğer bu hatayı denediğin halde görmediysen belki de iki dosya da kısa oldukları için olmuştur.

Ali
Avatar
Salih Dinçer #6
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Tamam şimdi oldu...:)

Ne hikmetse (belki Linux'a geçince yine hata verecek!) sorun şöyle düzeldi:
- static'i kaldırdım (nasıl olduysa!) ve
- container'ı döngü içinde bıraktım...

Anlamadığım şey ise static olan bir üye yeniden oluşturulduğunda (malum küme sonlanınca GC'ye emanet etmiyor mu?) neden önceki bilgilerini muhafaza edebiliyor? Sankli global variable gibi bir olay söz konusu!
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #7
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Sankli global variable gibi bir olay söz konusu!

Aynen öyle. static üyeden bir adet bulunur. O üye o türün bütün nesneleri tarafından paylaşılır.

O üye program başında bir kere ilklenir. Her nesne oluşturulduğunda tekrardan ilklenmesi başka nesnelerin işini bozacaktır. Öyle olsaydı şurada "static üyeler" başlığındaki örnek çalışamazdı:

  http://ddili.org/ders/d/yapilar.html

Ali
Avatar
Salih Dinçer #8
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Teşekkürler hocam, bu vesileyle yeni bir şey daha öğrendik. Tabii ki static'in anlamını çok iyi biliyordum ama destruct olduğunda bunun paylaşılan bir nesne olmayacağını düşünüyordum. Belki destroy() yapmak da bir değişikliğe yol açmayacak...:)

Bu arada Nokta() yapısını ve örneğini incelerken bir şey dikkatimi çekti; şu satır:
auto üstteki = NoktaOluştur(7, 0);
Sanki NoktaOluştur() bir işlev değil de biz burada aynı isimde bir yapıyı kuruyormuş gibi görünmüş. Hoş döndürdüğü değer de bir yapı nesnesi ya...:D

Elbette tüm kodu inceleyince birinin yapı birinin işlev olduğu anlaşılıyor. Belki new operatörünü kullanmak iyi bir alışkanlık olacak. Sanırım D'de bir çok kurma ve eşitleme olanakları C'ye uyumluluğu arttırmak için. Güzel parantezler ( {, } ) ile yapılan işlemleri de geçen hafta dersinizde öğrendim. Eski C'cilerin D'ye geçmek için çok sebebi var gibi geliyor bana...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #9
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Sanki NoktaOluştur() bir işlev değil de biz burada aynı isimde bir yapıyı kuruyormuş gibi görünmüş

Kodlama standardı ne olursa olsun böyle karışıklıklar oluyor. :( Belki noktaOluştur() daha doğru olurmuş ama o zaman da türün adı 'nokta' gibi görünüyor. O zaman yeniNokta() daha iyi bir isim olabilirmiş. (?)

Benzer bir durum D'nin toString işlevinde de var. Dönüştürülen tür 'String' mi 'string' mi? Kodlama standardı birleşik sözcükleri büyük harfle yazdırınca toString oluyor. :(

O kadar önemli değil tabii. :)

Belki new operatörünü kullanmak iyi bir alışkanlık olacak.

O örnekte olamıyor çünkü kullanıcılar 'new Nokta' deseler numara değişkenini de kendileri yönetmek zorunda kalırlar. Olmaz.

Ayrıca new ile oluşturulan nesne çöp toplayıcıya bırakılacağından sonlanması hemen olmaz.

Aslında burada daha iyisi 'static opCall'dur. Yukarıdaki bölümde bilerek göstermemiştim. Sonunda şurada "Varsayılan kurucu yerine static opCall" başlığında ortaya çıkıyor:

  http://ddili.org/ders/d/ozel_islevler.html

İşin güzeli, ben tam da bu örneği Arayüzler bölümünde "static üye işlevler" başlığı altında 'static opCall' kullanacak biçimde değiştirdim bile! :) (Ama daha siteye koymadım.) O zaman kodda şaşıracak bir şey kalmıyor:

import std.stdio;
 
struct Nokta
{
    // Her nesnenin kendi tanıtıcı numarası
    size_t numara;
 
    int satır;
    int sütun;
 
    // Bundan sonra oluşturulacak olan nesnenin numarası
    static size_t sonrakiNumara;
 
    this (int satır, int sütun)
    {
        this.satır = satır;
        this.sütun = sütun;
        this.numara = yeniNumaraBelirle();
    }
 
    static size_t yeniNumaraBelirle()
    {
        immutable yeniNumara = sonrakiNumara;
        ++sonrakiNumara;
        return yeniNumara;
    }
}
 
void main()
{
    auto üstteki = Nokta(7, 0);
    auto ortadaki = Nokta(8, 0);
    auto alttaki =  Nokta(9, 0);
 
    writeln(üstteki.numara);
    writeln(ortadaki.numara);
    writeln(alttaki.numara);
}

Ama static opCall'un tanımlanmış olması ortalığı biraz karıştırıyor. Bu soru şurada da daha bugün geçti:

  http://forum.dlang.org/thread/mryghcsskaxqhzmrvlof@forum.d…

Benim oradaki yanıtım benzer başka konulara bağlantı da içeriyor.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-19, 19:51:12 (UTC -08:00)