Bir dosyaya ham bayt yazma tehlikesi var mı? [kapalı]


12

Programlama İncileri - özellikle, en fazla 10.000.000 tamsayı (Sütun 1, Sorun 3) içeren bir dosyayı sıralayan bir programın uygulanması bir sorun üzerinde çalışıyorum. Kitap, verilerin dosyada nasıl saklanması gerektiğini belirtmediğinden, tam sayıları ham bayt olarak depolamayı düşünüyorum (ham baytları iyi bir seçenek haline getiren bazı kısıtlamalar var). Daha önce hiç bu kadar düşük seviyede çalışmadım, bu yüzden dikkat etmem gereken tehlikeli bir şey olup olmadığını bilmek istiyorum. Örneğin, bir dosyaya ham bayt yazarken yanlışlıkla bir tür dosya sonu dizisi kullanma konusunda endişelenmem gerekiyor mu?

Düzenle:

Şimdi sorumun ne kadar geniş olduğunu anlıyorum. Diskteki diğer dosyaların üzerine yanlışlıkla yazmak gibi daha feci türden problemler demek istedim. Üzgünüm başlangıçta daha net değildim.


6
İncili Programlamanın çok eski bir kitap olduğunu unutmayın; 10 ^ 7 tam sayılarının tamamını modern bir masaüstü bilgisayardaki belleğe kolayca okuyabilir, sıralayabilir ve tekrar yazabilirsiniz. Bu bölümün orijinal noktasını elde etmek için, okuduğunuz miktarı toplam sayının bir kısmıyla sınırlayın. Veya dosya boyutunu 10 ^ 10 tamsayıya yükseltin.
Caleb

3
Aslında, "tehlikeli" kelimesini duyduğumda, bilgisayarımı patlatan, banka hesaplarımı silen şeyler ya da bunun gibi şeyler düşünüyorum. Ve sanırım - programınız bir Airbus veya elektrik santralini kontrol etmek için kullanılmadığı sürece - aklınızdakileri denediğinizde gerçekten "tehlikeli" bir şey olmayacağını varsaymak muhtemelen güvenlidir.
Doc Brown


2
@delnan Yıllar önce, EOF karakterinin efsanesi modadayken, zamanın birçok kopya programının yaptığı 'EOF karakterine kopyala' yı temel alan kopya koruma sistemlerini hatırlıyorum. Bazı programlar, ilişkili bir metin dosyasının EOF işaretleyicisinden sonra ancak dosyanın ayrılan bitiminden önce denetleyecekleri ek veriler koyabilir . Kopyalama programı temiz bir yüklemeyi doğrulayan fazladan verileri kopyalamaz ... ahh ... nostalji.

Tehlike? "Bunu yaparsam bilgisayarım patlayacak" gibi? Hayır!
jwenting

Yanıtlar:


11

Karşılaşacağınız tek tehlike, az ya da büyük endianess (en büyük ya da en az önemli baytın önce yazılması). Ancak aynı ortamda kalırsanız herhangi bir sorun olmayacaktır. ayrıca gidiş-dönüş yazma / ayrıştırma genel sağlaması.

Dosya sistemi, herhangi bir bayt dizisini işlemek için tasarlanmıştır.


2
Son satır için +1. Büyük / küçük sorunun tek sorun olduğundan emin değilim - OP örneğin tamsayılar arasındaki sınırların nerede olduğu konusunda kafanız karışabilir. Ama yine de iyi cevap.
Caleb

27

Hayır, aslında bu kaç dosya formatının çalıştığıdır. Bunun gibi yaygın ikili dosya örnekleri arasında görüntüler ve müzik / ses dosyaları bulunur.

Dosyanın bütünlüğünü ve dosyadan okunan verileri korumak için şu yönergeleri izlediğinizden emin olun:

  • Dosyayı her zaman aynı modu kullanarak açın (okuma veya yazma): metin veya ikili. Birincil fark, metin modunun yeni satırlarla ilgilenmesidir ve bir dosyayı okurken yeni satır karakterlerini "kesebilir" (kullanılan belirli kitaplığa bağlı olarak). Metin modu, Unicode olmayan verilerde boğulma olasılığı olan Unicode çevirileri de yapabilir.
  • Dize dışı verileri okurken, yazdığınızla aynı veri türünü kullanarak okuyun. Örneğin, dosyanın ilk dört baytı açıklayıcı bir tamsayı ise, tutarlı bir şekilde işlendiğinden emin olmak için bir tamsayı alan / sağlayan bir yöntem kullanarak okuma ve yazmayı unutmayın. Aynı veri türü farklı makinelerde farklı bir boyuta sahip olabilir ve aynı makinede veri türlerinin karıştırılması da verilerin anlamını değiştirebilir (örneğin, daha uzun bir tamsayının ortasındaki bir biti bir işaret biti olarak yorumlama).
  • Endianness: Kullandığınız kütüphane bunu tutarlı bir şekilde ele almıyorsa, kendiniz halletmeniz gerekebilir. Örneğin, Java çok baytlı türler için her zaman ağ bayt sırasını (big endian) kullanır. C ve C ++, kitaplık uygulayıcının karar verdiği her şeyi kullanır, genellikle işlemci ile aynıdır (Intel'de küçük endian, diğerlerinde büyük endian). Bu, bir sistem üzerinde hızlı bir egzersizse, o kadar önemli değildir, ancak buna dikkat etmek ve gerekirse kodlamak hala iyi bir alışkanlıktır.

Spesifik ayrıntılar, çerçeveye, platforma ve dile göre değişecektir, ancak bu, dosya G / Ç'si olan temel "gotchas" ı kapsamalıdır.


3
Dize olmayan veriler için ek bir nokta: her tür için tutarlı sayıda bayt kullandığınızdan emin olun. C ve C ++ 'da an int2 ve 8 veya daha fazla bayt arasında olabilir (gerçekten sekizli).
Bart van Ingen Schenau

Bu dolaylı olarak ikinci noktama dahil edilmiştir, örneğin 32 v. 64 bit tam sayı. Farklı veri türleri olurdu.

Açık yapmak isteyebilirsiniz. intİki farklı makinede farklı veri türleri olarak kabul edilebileceği açık değildir .
Bart van Ingen Schenau

9

Bahsedilen tüm gotcha'lara ek olarak, mevcut bir formatta veri okumak ve yazmak yerine yeni bir ikili dosya formatı oluşturuyorsanız, bir dosya üstbilgisi eklemeniz kesinlikle çok önemlidir : en başta bir veri bloğu dosya biçimini açıkça tanımlayan ve gerekli olabilecek meta verileri kaydeden dosyanın.

İyi dosya başlıkları en az üç şey içerir:

  • En az dört baytlık bir " sihirli sayı ". Sihirli sayı rfc2119 dosyadaki ilk N bayt OLMALIDIR, asla kazabileceğiniz başka bir dosya formatı için kullanılmamış ZORUNLU ve yazdırılabilir ASCII karakteri olmayan en az bir bayt içermelidir ZORUNLU. Gerçekten ayrıntılı bir sihirli sayı tasarlama konusunda PNG spesifikasyonuna bakın . Bulabileceğiniz büyüklükte sihirli sayıları içeren bir veritabanı için komutun kaynak koduna bakın .file(1)

    Sihirli bir sayının amacı, dosyayı bant içinde, biçimiyle net bir şekilde etiketlemektir. Sihirli bir sayı eklemezseniz veya dosyadaki ilk şey değilse, dosyanızı başka bir dosya türü olarak yanlış tanımlayan ve veri kaybına, virüslerin tespit edilmesinden ve benzeri diğer programlara neden olma riski taşırsınız. felaketler.

  • Dosya biçiminin sürümünün bir göstergesi . Dosya biçiminizi hiçbir zaman büyük ölçüde revize etmeyeceğinizi düşünseniz bile, sihirli sayının ardından sonraki iki baytı yapın 00 00ve bunun belirli bir endianitede 16 bitlik bir sürüm numarası olduğunu (hangisini isterseniz, seçin) biri ve dosya boyunca ona yapışır ) ve sonraki verilerin anlamı kökten değişirse artırılacaktır. Gelecekteki benliğiniz size teşekkür edecektir.

    (Burada PNG belirtimi, yığın biçimlerinin dondurulduğunu ve biçimdeki gelecekteki tüm değişikliklerin yeni yığın türleri biçimini alacağını belirten farklı bir yol alır. Bu da geçerlidir, ancak basit sihirli sayı + sürüm numarası yaklaşımını öneriyorum İkili veri işlemeye yeni başlayanlar. PNG'yi tasarlayan insanlar, onlarca yıllık görüntü formatları için toplu deneyime dayanıyordu.)

  • Rasgele meta verileri dosyaya gömmek için bir tür mekanizma . Bu, sonraki iki baytın başlığın sonundan gerçek verilerin başlangıcına kadar 16 bitlik bir sapma olması kadar basit olabilir; aradaki her şey UTF-8 anahtar / değer çifti a la RFC 822 olarak yorumlanacaktır (olduğunu, " Tag: value\n" - Bu yolu ben tavsiye değil uzun hatların katlama izin). Yine PNG oldukça zekidir.


Kendi dosya biçiminizi oluşturmanıza gerek yok ... sadece verileri resim olarak saklayın. Boyutlandırmayı değiştirmeniz gerekebilir (örn. 10k x 1k), desteklenebilmesi için. Veya FITS kullanabilirsiniz . Verileriniz tek bir diziden daha karmaşıksa, HDF , CDF veya NetCDF kullanabilirsiniz .
Joe

Basit tutmanızı öneririm. 256 farklı sürüm yeterli olacaktır ve eğer değilse, 255 sürümünün alt sürümleri olarak ek sürümler tasarlanabilir. Meta veriler için benzer şekilde, gerçekten ihtiyaç duyulduklarında bunları bir sürüme eklemek yeterlidir. @Joe Image ??? Önceden herkesi karıştırarak potansiyel biçim karışıklığından kaçıyorsunuz!
maaartinus

@maaartinus Sürüm alanını iki bayt yapmak, format tasarımcısını önde bir endianiteye bağlı olmaya zorlar. Meta veriler için alan her zaman ikili biçimin 0 sürümünde olmalıdır, aksi takdirde ID3 gibi korkunç kundaklarla sarılırsınız. PNG sürümünün, biçim sürümü darbeleri yerine yeni yığın türleri aracılığıyla genişletilebilirlik mantığı için büyük bir sempati duyuyorum. Bununla birlikte, yığın halinde yapılandırılmış dosyalar kendi karmaşıklıklarını getirir, bu yüzden basit durumlar için onları tavsiye etmekten çekinmeyin. Ben edildi zaten bu konularda bir sürü ele olduğu genel biçimi olarak HDF tavsiye cazip.
zwol

2

Farklı mimarilerin tamsayılar için farklı temsilleri vardır. Buradaki ana risk, A makinesindeki bir tamsayının bayt temsilini kaydetmek ve daha sonra bunu geri okumaya ve içeriği B makinesinde tamsayı olarak yorumlamaya çalışmaktır. A ve B makinelerinin tamsayılar ve / veya farklı endianness için farklı boyutları varsa, büyük olasılıkla tanımlanmamış davranışa (örneğin C) veya bir istisnaya neden olur.

Bu sadece bir programlama örneği ve "gerçek" bir program olmadığından, bu gerçekten bir sorun değildir. Bu gerçek bir program olsaydı, kendi uygulamaya özel ikili biçiminizi döndürmek genellikle iyi bir fikir değildir; SQLite veya JSON, YAML, XML gibi dizgi tabanlı serileştirme formatları gibi daha iyi çözümler vardır. Tek değerler için dizeye dönüştürmek yeterli olacaktır; basit listeler için her satıra bir dize kaydedebilir ve girdiyi tekrar okurken yeni satırlara bölebilirsiniz.


Genel olarak katılıyorum, ancak JSON veya XML 10 ^ 7 sayı içeren bir dosyanın boyutunu önemli ölçüde artıracaktır. Ayrıca, genellikle bir kerede okunur ve ayrıştırılırlar, ancak söz konusu bölüm, kullanılabilir belleğe sığabileceğinizden daha fazla veri içeren dosyaları sıralama ile ilgilidir.
Caleb

Ne yaptığınıza bağlı. Bazen SQL'in bir ruloya karşı performans isabeti büyüktür. En son yaptığım zaman küçük kayıtlar aldım ve komşuları istememe şansım yüksekti. Diskten daha büyük bir bloğu okumak genellikle neredeyse hiçbir maliyeti olmayacaktır, bu yüzden bir kayıt istersem 1000'i önbelleğe okurum. Kayıtlarım neredeyse kesinlikle yan yana, SQL ile disk kafası her yerde sıçrayan olurdu.
Loren Pechtel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.