Prowadziliśmy tutaj dyskusję na temat tego, dlaczego fread i fwrite przyjmują rozmiar na członka i liczą i zwracają liczbę elementów członkowskich odczytanych / zapisanych, a nie tylko przyjmować bufor i rozmiar. Jedynym zastosowaniem, jakie możemy wymyślić, jest to, że chcesz odczytać / zapisać tablicę struktur, które nie są równo podzielne przez wyrównanie platformy i dlatego zostały wypełnione, ale to nie może być tak powszechne, aby uzasadniać ten wybór w projektowaniu.
Z FREAD (3) :
Funkcja fread () odczytuje nmemb elementy danych, każdy rozmiar w bajtach, ze strumienia wskazywanego przez stream, przechowując je w lokalizacji podanej przez ptr.
Funkcja fwrite () zapisuje nmemb elementów danych, każdy rozmiar w bajtach, do strumienia wskazywanego przez stream, uzyskując je z lokalizacji podanej przez ptr.
fread () i fwrite () zwracają liczbę pomyślnie odczytanych lub zapisanych elementów (tj. nie liczbę znaków). Jeśli wystąpi błąd lub osiągnięto koniec pliku, zwracaną wartością jest krótka liczba elementów (lub zero).
Odpowiedzi:
Opiera się na sposobie implementacji fread .
Pojedyncza specyfikacja UNIX mówi
fgetc ma również tę notatkę:
Oczywiście poprzedza to fantazyjne kodowanie znaków o zmiennej bajtach, takie jak UTF-8.
SUS zauważa, że jest to faktycznie zaczerpnięte z dokumentów ISO C.
źródło
Różnica w fread (buf, 1000, 1, stream) i fread (buf, 1, 1000, stream) polega na tym, że w pierwszym przypadku otrzymujesz tylko jedną porcję 1000 bajtów lub nic, jeśli plik jest mniejszy i ma W drugim przypadku otrzymujesz wszystko w pliku mniej niż i do 1000 bajtów.
źródło
To czyste spekulacje, jednak dawno temu (niektóre wciąż istnieją) wiele systemów plików nie było zwykłymi strumieniami bajtów na dysku twardym.
Wiele systemów plików było opartych na rekordach, więc aby zapewnić takie systemy plików w efektywny sposób, będziesz musiał określić liczbę elementów („rekordów”), dzięki czemu fwrite / fread będą działać w pamięci jako rekordy, a nie tylko strumienie bajtów.
źródło
Tutaj, pozwól mi naprawić te funkcje:
Jeśli chodzi o uzasadnienie parametrów do
fread()
/fwrite()
, to już dawno zgubiłem kopię K&R, więc mogę się tylko domyślać. Myślę, że prawdopodobną odpowiedzią jest to, że Kernighan i Ritchie mogli po prostu pomyśleć, że wykonywanie binarnych operacji we / wy byłoby najbardziej naturalne na tablicach obiektów. Mogli także pomyśleć, że blokowe wejścia / wyjścia będą szybsze / łatwiejsze do zaimplementowania lub cokolwiek innego na niektórych architekturach.Mimo że norma C to określa
fread()
ifwrite()
powinna zostać wdrożona w zakresiefgetc()
ifputc()
, należy pamiętać, że norma ta powstała długo po zdefiniowaniu C przez K&R i że rzeczy określone w normie mogły nie znajdować się w oryginalnych pomysłach projektantów. Jest nawet możliwe, że rzeczy powiedziane w „Języku programowania C” firmy K&R mogą nie być takie same, jak przy pierwszym projektowaniu języka.Na koniec, oto, co PJ Plauger ma do powiedzenia
fread()
w „The Standard C Library”:Zasadniczo mówi, że
fread()
interfejs jest uszkodzony. Dlafwrite()
zauważa, że „błędy zapisu są zazwyczaj rzadkie, więc nie jest to poważny mankament” - stwierdzenie, że nie zgodzi się.źródło
fread(buf, size*n, 1, stream);
jeśli niekompletne odczyty są stanem błędu, łatwiejfread
jest po prostu zwrócić 0 lub 1 zamiast liczby odczytanych bajtów. Następnie możesz zrobić takie rzeczy, jakif (!fread(...))
zamiast porównywać wynik z żądaną liczbą bajtów (co wymaga dodatkowego kodu C i dodatkowego kodu maszynowego).Prawdopodobnie wraca do sposobu implementacji operacji we / wy pliku. (dawno temu) Mogło być szybsze zapisywanie / odczytywanie plików w blokach niż zapisywanie wszystkiego naraz.
źródło
Posiadanie oddzielnych argumentów dla rozmiaru i liczby może być korzystne w implementacji, która pozwala uniknąć odczytywania częściowych rekordów. Gdyby ktoś używał odczytów jednobajtowych z czegoś takiego jak potok, nawet gdyby korzystał z danych o stałym formacie, należałoby uwzględnić możliwość rozdzielenia rekordu na dwa odczyty. Gdyby zamiast tego mógł zażądać np. Nieblokującego odczytu do 40 rekordów po 10 bajtów każdy, gdy dostępne są 293 bajty, i kazać systemowi zwrócić 290 bajtów (29 całych rekordów), pozostawiając 3 bajty gotowe do następnego odczytu, będzie znacznie wygodniejszy.
Nie wiem, w jakim stopniu implementacje fread radzą sobie z taką semantyką, ale z pewnością mogą być przydatne w przypadku implementacji, które mogłyby je wspierać.
źródło
fread(buffer, 10000, 2, stdin)
a użytkownik wpisze nową linię -ctrl-D po wpisaniu 18000 bajtów, byłoby miło, gdyby funkcja mogła zwrócić pierwsze 10000 bajtów, pozostawiając pozostałe 8000 oczekujące na przyszłe mniejsze żądania odczytu, ale czy są jakieś wdrożenia, w których to by się stało? Gdzie byłoby przechowywanych 8000 bajtów w oczekiwaniu na te przyszłe żądania?size
więcej niż 1, cóż ... Dla przypomnienia, mogą również istnieć ioctls lub inne bzdury, które możesz zastosować do strumienia, aby to zrobić zachowuję się inaczej, nie zagłębiłem się tak głęboko.fread
praca na takich strumieniach zgodna z opisem byłaby przydatna, gdyby istniał sposób na zidentyfikowanie strumieni, które działają w ten sposób.Myślę, że to dlatego, że C nie ma przeciążenia funkcji. Gdyby tak było, rozmiar byłby zbędny. Ale w C nie możesz określić rozmiaru elementu tablicy, musisz go określić.
Rozważ to:
Jeśli fwrite zaakceptowaną liczbę bajtów, możesz napisać:
Ale to jest po prostu nieefektywne. Będziesz mieć sizeof (int) razy więcej wywołań systemowych.
Kolejną kwestią, którą należy wziąć pod uwagę, jest to, że zazwyczaj nie chcesz, aby część elementu tablicy była zapisywana w pliku. Chcesz całą liczbę całkowitą albo nic. fwrite zwraca liczbę pomyślnie zapisanych elementów. Więc jeśli odkryjesz, że zapisane są tylko 2 niskie bajty elementu, co byś zrobił?
W niektórych systemach (z powodu wyrównania) nie można uzyskać dostępu do jednego bajtu liczby całkowitej bez tworzenia kopii i przesuwania.
źródło