Yorumlar derken, fread
, dosyanızdaki baytları herhangi bir yorum yapmadan okur. Dosya clients.txt
, ilk satırda 16, ikinci satırda 18, üçüncü satırda 14, artı iki satır karakterinde 50 karakterden oluşur. (Üçüncü satırdan sonra, istemciler.txt, yakında göreceğiniz gibi üçüncü satır içermez.) Yeni satır karakteri, UNIX veya Mac OS X makinelerinde tek bir bayt \n
, ancak (muhtemelen) Windows makinelerinde \r\n
iki bayttır. 50 veya 51 karakter.
3130 3020 4a6f 6e65 7320 3536 342e 3930 100 Jones 564.90
0a32 3030 2052 6974 6120 3534 2e32 330a \n200 Rita 54.23\n
3330 3020 5269 6368 6172 6420 2d34 352e 300 Richard -45.
3030 00
Sizin fread
açıklamada kopyalar doğrudan rec1
veri yapısına hiçbir yorum yapılmadan bu bayt: Burada onaltılık ASCII bayt dizisidir. Bu yapı, ilk dört baytı int
olarak yorumlamak için int account;
ile başlar. Belirtilen yorumlardan biri olarak, programınızı küçük bir makinede (büyük ihtimalle bir Intel makinesi) çalıştırıyorsunuz, bu yüzden en az anlamlı bayt ilk ve en önemli bayt dördüncü. Böylece, fread
, dört ASCII karakterinin sırasını, 0x20303031
dört bayt tamsayı olarak, ondalık, 540028977
olarak eşit olarak yorumlamak için söyledi. Yapınızın bir sonraki üyesi char name[100];
, yani rec1
'daki sonraki 100 baytlık veri name
olacaktır. Ancak fread
'a sizeof(rec1)=112
bayt (4 baytlık hesap, 100 bayt isim, 8 baytlık balans) okuması söylendi. Dosyanız yalnızca 50 (veya 52) karakter olduğu için, fread
yalnızca rec1
'un çok sayıda baytını doldurabilecektir. fread
'un geri dönüş değeri, onu atmamış olsaydınız, okumanın talep ettiğiniz bayt sayısının az olduğunu söylemiş olurdu. EOF'a bastığınız için, feof
çağrısı, ilk geçişten sonra tüm dosyayı bir yudumda harcayarak döngüden çıktı.
Tüm çıktılarınız, yalnızca fprintf
numaralı aramaya göre üretildi. 540028977 sayısı ve aşağıdaki alan "%d "
ve rec1.account
bağımsız değişkeni tarafından üretilmiştir. Sonraki bit sadece kısmen belirlenir ve şansınız vardır: "%s"
belirteci ve ilgili rec1.name
bağımsız değişkeni, \0
bayt bulunana kadar sonraki karakterleri ASCII olarak basacaktır.(Veya herhangi bir metin dosyası olarak), hangi anlamı dosyanızda hiç \0
bayt olduğundan, sonsuza devam potansiyel ve - iki yeni satır dahil - Böylece çıktı dosyanızın 50-4
(veya 52-4
) kalan karakterler ile başlayacak bu dosyanızın son karakterini yazdırma sonra, ne görmeye ne olursa olsun çöp programınızı başladığında otomatik değişken rec1
olması oldu olduğunu. (Kasıtsız çıktı Bu tür OpenSSL'deki ünlü Heartbleed hata benzer.) Pisliğin yalnızca birkaç düzine daha karakterden sonra bir \0
byte dahil şanslıyız. printf
'un, rec1.name
'un yalnızca 100 baytlık bir dizi olarak bildirildiğini bilmenin bir yolu olmadığını unutmayın - yalnızca name
'un başlangıcına işaretçiyi aldı - rec1.name
'un bir sonlandırma \0
bayt olduğunu garanti etmek sizin sorumluluğunuzdaydı ve asla yaptı.
Biz biraz daha söyleyebilir. ("%f"
biçimde oldukça çirkin) sayısı -9.2559631349317831e61
rec1.balance
değeridir. (Senin Intel ve tüm modern bilgisayarlar gibi) IEEE 754 bilgisayarında bu double
değeri 8 bayt onaltılık 0xcccccccccccccccc
içindedir. tuhaf ╠
sembolün Altmış dört sizin "%s"
çıkış rec1.name
sonunu kapalı tükendi böylece sadece 100-46 = 54 karakter 100 kalırken, rec1.name
tekabül "%s"
çıkışında görünecek ve pazarlık içine rec1.balance
içermektedir ve Terminal programınızın ASCII olmayan 0xcc
karakterini ╠
olarak yorumladığını öğrenin. 127'den büyük (0x7f) baytları yorumlamanın birçok yolu vardır; latin-1'de örneğin Ì
olurdu. Grafiksel karakter ╠
, eski MS-DOS karakter kümesinde, Windows kod sayfası 437'deki 0xcc (204) baytının gösterimidir. Yalnızca bir Intel makinesinde çalışmamanız değil, bir Windows makinesi (tabii ki büyük olasılıkla) ile başlamak için).
İlk iki sorunuzu yanıtlıyor. Üçüncü sorunuzu anladığımdan emin değilim. Umarım "dezavantajları" açıktır.
Nasıl düzeltileceğine gelince, fread
kullanarak bir metin dosyasını okumak ve yorumlamak için makul bir yol yoktur. Bunu yapmak için, libc
fscanf
işlevindeki kodun çoğunu çoğaltmanız gerekir. Tek mantıklı yol, ilk kez bir ikili dosya oluşturmak için fwrite
kullanmasıdır; Daha sonra fread
, geri okumak için doğal olarak çalışacaktır. Yani iki program olmalı - biri ikili bir clients.bin
dosyası yazacak ve bir saniye geri okuyacak. Tabii ki, bu ilk programın verilerinin ilk etapta nereden gelmesi gerektiği sorununu çözmez. fscanf
kullanarak clients.txt
okunabilir.
struct rec recs[] = {{100, "Jones", 564.90},
{200, "Rita", 54.23},
{300, "Richard", -45.00}};
Yoksa MySQL veritabanı okuma gelebilir ya ... tek bir yerde onu: Ya böyle struct rec
bir dizi başlatarak örneğin fwrite
programının kaynak kodu, dahil edilebilir Olası bir ikili dosyada (kolaylıkla) fread
ile okunabilir olması muhtemel değildir.
Lütfen "Neden" while (! Feof (dosya)) "her zaman yanlış mı?" (Http://stackoverflow.com/q/5431941/2173917) –
Lütfen okuyunuz Neden [while is while (! Feof (fptr))) 'her zaman yanlış] (http://stackoverflow.com/a/26557243/1983495). –
fread, ham ikiliyi okur. Clients.txt bir metin dosyasıdır, bu yüzden bu dosyayı ham ikili veri olarak okuyan bir nokta yoktur. –