2015-09-09 31 views
5

PHP kullanarak bir ikili dosyada belirli bir Bayt dizisini bulmak istiyorum. Çok fazla 0s ve 1s yazmayı önlemek için bu diziyi onaltılık olarak temsil ettim. Bulunacak sekans 0x4749524f.PHP'de bir ikili dosyada bir bayt dizisi mi arıyorsunuz?

$mysequence = "4749524f"; 
$f = fopen($filename, "r") or die("Unable to open file!"); 
while(!feof($f)){ 
    $seq = fread($f, 4); 
    if(bin2hex($seq) == $mysequence){ 
     echo "found!"; 
     break; 
    } 
    else if(!feof($f)) fseek($f, -3, SEEK_CUR); 
} 

Ne algoritması yapar basittir: Bu şimdi için geldi çalışma çözümdür

  1. Oku 4 Bayt
  2. Kontrol eğer olurlarsa ise dizinin
  3. eşittir onlar eşittir -> bulundu! Yürütmeyi durdur.
  4. tutuyorsa değildir ve ben dosyanın sonuna değilim Eğer Neden 3 Bayt geri gitmek adım 1.

geri 3 Bayt dosyasına gidip tekrar? Bu dosyanın içeriği ise Çünkü:

0000 4749 524f 0000 01b0 0013 

geri 3 Bytes gitmezseniz, ben üçüncü saniye birinci tekrar 0000 4749, 524f 0000, 01b0 0013 okuyacak gibi görebileceğiniz diziyi özledim.

Sorun: Cehennem gibi yavaş ... Uygulama, 50 MB büyüklüğe kadar dosyalar ile çalışmak zorunda kalacak, bu yüzden bu diziyi bulmak sonsuza dek sürecek.

PHP'de işi yapacak optimize edilmiş bir işlev var mı? Bunu yapmak için daha hızlı (benimki gibi değil) bir yolu var mı?

+1

1M (veya daha fazla) gibi uzun bir bayt kümesi okuyun. Sonra bunu hafızada arayın. Sonraki 1Mbyte'ları okurken, ilk setin son 3'ünün iğnenin başlangıcı olup olmadığını da kontrol edin. –

+0

Tamam, deneyeceğim! Teşekkürler. BTW, dosya okunurken belleğe önbelleklendiğini düşündüm ... Bu işlevi çalıştırdığım her zaman, dosya sabit diskten doğrudan okunabilir mi? –

+0

@AlbertoFontana Sadece aynı yaklaşımın bir modifikasyonu, sadece büyük parçalarda (4-8k iddia ediyorum) ve sonra bir "yığın içinde bul" (vs "chunk exact match") olarak okunur). Bölünmüş parçaları kolayca işlemek için basit bir yol da geri aramaktır, bu nedenle parçalar aslında birkaç bayt ile örtüşür (bu yakın çekim nispeten seyrek yapılırsa çok iyi olur). Sistem çağrı sayısının azaltılması, en büyük performans farkı ne olacak. Ayrıca, her zaman okunan verileri dönüştürmek yerine, $ mysequence'ı bayt dizisine dönüştürerek biraz daha fazla iş azaltılabilir. – user2864740

cevap

1

Diskten okuma yapmak her zaman uzun bir zaman alır. Disk önbelleklemeye güvenemezsiniz. Bu bir işletim sistemi işi. Bunun yerine, kendi "önbelleğe alma" yı kendiniz yapın. Uzun bir baytlık sette okuyabilirsiniz, belki 1M gibi bir şey (veya daha fazlası). Bu, disk okumalarını azaltır. Sonra bunu hafızada arayın. Sonraki 1Mbyte'ları okurken, önceki setin son 3 baytını eklediğinizden emin olun. Bulunana kadar her seti arayın. Okumanızın gerçek boyutu, RAM kullanımı ve disk okumaları arasında bir denge olmalıdır.

3

Tüm $mysequence kodunuzu değiştirirken, aramayı değiştiremezsiniz, bu nedenle hex2bin($mysequence) numaralı telefonu arayabilir ve $seq numaralı telefonu ile karşılaştırırsınız.

Bunu gerçekten daha hızlı yapmak için, büyük arabelleklerde dize için okuma ve arama yapmayı deneyebilirsiniz. Daha büyük tampon => daha hızlı arama, ancak daha fazla bellek gerekli. Hızlı kod taslağı, bunun nasıl olması gerektiği gibi:

$mysequence = "4749524f"; 
$searchBytes = hex2bin($mysequence); 
$crossing = 1 - length($searchBytes); // - (length - 1); see below 
$buf = ''; $buflen = 10000; 
$f = fopen($filename, "r") or die("Unable to open file!"); 
while(!feof($f)) 
{ 
    $seq .= fread($f, $buflen); 
    if(strpos($seq, $searchBytes) === false) // strict comparation here. zero can be returned! 
    { 
     // keep last n-1 bytes, because they can be beginning of required sequence 
     $seq = substr($seq, $crossing); 
    } 
    else 
    { 
     echo "found!"; 
     break; 
    } 
} 
unset($seq); // no need to keep this in memory any more 
+0

Ne zaman dediğinizi anlamadım: "$ sıq arama sırasında değişmiyor, bu yüzden bin2hex() 'i bir kez arayabilirsin." Tabii ki $ sq değişiyor, çünkü her döngüde yeni bir dizi okuyorum ... yanlış mıyım? –

+0

Arızam. Hex2bin ($ mysequence) '' 'diyebilir ve $ seq ile karşılaştırabilirsiniz. Her zaman '' 'bin2hex''' çağırmadan. –

İlgili konular