2011-12-09 14 views
6

Pek çok benzer soru var, ancak bu, özellikle de etrafta dolaştıktan sonra özellikle yanıtlayan hiçbir şey yok. Buraya:Bir dosyanın başlangıcını C cinsinden kırpmanın en iyi yolu nedir?

"değişmediğini" en doğru C iyi yolu nedir

abcdefghijklmnopqrztuvwxyz:

(ikili olması ve çok fazla büyük olabilir) bir dosya var ki Örneğin dosyanın başlangıcını kısaltmaın solunda bu dosyanın kısmı .. yani, diskteki dosyayı değiştirecek 7 bayt "kısaltılıyor ön" olmak:

hijklmnopqrztuvwxyz

Ben geçici dosyaları kaçınmak gerekir ve belleğe tüm dosyayı okumak için büyük bir tampon kullanmamayı tercih ederim. Düşündüğüm olası bir yöntem fopen'i "rb +" bayrağıyla kullanmaktır ve sürekli olarak ileri ve geri okuma ve yazma işlemlerini, başlangıçtan başlayarak baytları kopyalamak için ileri ve geri hareket ettirmek, sonra da EEOFFile değerini en sonunda kırpmaktır. Bu çok arama (muhtemelen verimsiz) gibi görünüyor.

başka yolu da iki kez aynı dosyayı fopen ve ilgili dosya işaretçileri ile fgetc ve fputc kullanmak olacaktır. Bu mümkün mü? başka yolları varsa

, ben hepsini okumak isteriz.

+0

ben (iki DOSYA işaretçiler ile) iki kez dosyayı açmadan sona erdi. Bu çok hızlı oldu (bir göz açıp kapayıncaya kadar 2mb; benchmark). Fileno() ve ftell() ile ftruncate() kullandım. – snapfractalpop

cevap

3

Sen muazzam bir tampon boyutunu kullanmak zorunda değilsiniz ve çekirdek sizin için zor işi olacak, ama evet, dosyanın yukarı ve başından yakın yazmaktan tam bir tampon okuma yoludur Yeni bir dosya oluşturmanın daha basit bir işini yapamazsanız, o dosyaya ne istediğinizi kopyalayın ve yeni (geçici) dosyayı eski dosyaya kopyalayın. Yeni bir dosyaya ne istediğinizi kopyalamak ve sonra yeni dosyayı eski yerine taşımak ya da yeniyi eskiden kopyalamak, açıkladığınız karıştırma işleminden daha hızlı olabilir. Kaldırılacak bayt sayısı 7 bayt yerine bir disk blok boyutuysa, durum farklı olabilir, ancak büyük olasılıkla olmayabilir. Tek dezavantajı, kopyalama yaklaşımının daha fazla ara disk alanı gerektirmesidir.

Anahat yaklaşımınız, bir POSIX sisteminde olduğunuzu varsayarak, dosyanın doğru uzunlukta kısaltılması için truncate() veya ftruncate() kullanımını gerektirir. Eğer truncate() yoksa, kopyalamayı yapmanız gerekecektir. fopen() ile "r+b" modunu kullanarak veya open() ile O_TRUNC kaçınarak - Eğer yazma açarken dosyanın bilmeden dikkat eğer iki kere dosyayı açmadan Tamam çalışacağını

Not.

+0

Harika bir yanıt için teşekkürler! Taşınacak blokların boyutu önemli olabilir (megabaytların sırasına göre). Geçici dosyalardan kaçınmayla ilgili kaygım alanla değil, hassas verilerin kalıcılığıyla ilgilidir. Baytların disk üzerindeki bir yere fiziksel olarak depolanmasını sınırlamak istiyorum (kopya silinmiş olsa da, baytlar hala mevcut olabilir). BTW, Ben linux üzerindeyim.Eğer her bayt ileri geri ararsam çekirdek çeker mi, yoksa en uygun tampon ne olurdu? Son seçeneğin fiziksel olarak aynı şeyle sonuçlanıp sonuçlanmayacağını merak ediyorum. – snapfractalpop

+0

Tek bayt okuma ve yazma işlemleri yaparsanız, bir şey (standart G/Ç veya çekirdek - veya belki her ikisi de) bir çok iş yaparsınız. Kilobayt büyüklükteki parçalarda çalışmak (1, 2, 4, 8, 16, 32 KiB parçaları), her şeyden çok, ama en fakir ortamları vurgulamadan, daha verimli olacaktır. Çekirdek sizin için hizalamalar vb. Ile ilgilenecektir. –

+0

ok. Tekrar teşekkürler! – snapfractalpop

4

Sen belleğe dosyayı mmap ve sonra içindekileri memmove olabilir. Dosyayı ayrı olarak kesmeniz gerekir.

+0

Yani, adımlar: 1) mmap 2) memmove 3) un-mmap (mevcut mu var?) 4) truncate ? – snapfractalpop

+1

@snapfractalpop [related example here] (http://pastebin.com/s1vSCvxA). Bu çözüm gerçekten hızlı olma potansiyeline sahiptir, ancak dosya boyutu adres alanı büyüklüğüyle sınırlıdır. 32 bit sistemlerde büyük (> 4GB) dosyaları kesemezsiniz. –

+2

@Banthar: bundan daha kötü: sürecinizin adres alanının yeterince büyük olan bitişik bir bölümüne ihtiyacınız var. Parçalanma ve diğer bellek ayırmalarına bağlı olarak 4GB'tan daha az olabilir. – Joe

İlgili konular