C fopen vs open

219

Czy jest jakiś powód (inny niż składniowy), z którego chciałbyś skorzystać

FILE *fdopen(int fd, const char *mode);

lub

FILE *fopen(const char *path, const char *mode);

zamiast

int open(const char *pathname, int flags, mode_t mode);

podczas używania C w środowisku Linux?

LJM
źródło
Miałeś na myśli fdopeni openlub fopeni open?
user7116,
Nie masz na myśli fopen, a nie fdopen?
Wszechobecny
9
fopenjest częścią standardowej biblioteki C, opennie jest. Użyj fopenpodczas pisania przenośnego kodu.
Aziz
Tak, miałem na myśli fopen. Właśnie go zaktualizowałem, ale myślę, że ta sama zasada obowiązuje.
LJM,
6
@Aziz, openjest jednak funkcją POSIX.
dreamlax

Odpowiedzi:

242

Po pierwsze, nie ma szczególnie dobrego powodu, aby użyć, fdopenjeśli fopenjest to opcja i openjest to drugi możliwy wybór. Nie powinieneś był openotwierać pliku, jeśli chcesz FILE *. Dlatego umieszczenie fdopenna tej liście jest niepoprawne i mylące, ponieważ nie jest bardzo podobne do innych. Teraz będę go ignorować, ponieważ ważne jest tutaj rozróżnienie między standardem C.FILE * a deskryptorem pliku specyficznym dla systemu operacyjnego.

Istnieją cztery główne powody, aby używać fopenzamiast open.

  1. fopenzapewnia buforowanie operacji we / wy, które mogą okazać się znacznie szybsze niż to, co robisz open.
  2. fopen wykonuje translację zakończeń linii, jeśli plik nie jest otwarty w trybie binarnym, co może być bardzo pomocne, jeśli Twój program jest kiedykolwiek przenoszony do środowiska innego niż Unix (chociaż świat wydaje się być zbieżny tylko w LF (z wyjątkiem sieci tekstowej IETF) protokoły takie jak SMTP i HTTP itp.).
  3. A FILE *daje możliwość korzystania z fscanfinnych funkcji stdio.
  4. Twój kod może kiedyś wymagać przeniesienia na inną platformę, która obsługuje tylko ANSI C i nie obsługuje tej openfunkcji.

Moim zdaniem tłumaczenie kończące wiersz częściej fscanfprzeszkadza, niż pomaga, a parsowanie jest tak słabe, że nieuchronnie kończy się to rzuceniem go na coś bardziej przydatnego.

I większość platform obsługujących C ma openfunkcję.

To pozostawia pytanie buforujące. W miejscach, w których głównie czytasz lub zapisujesz plik sekwencyjnie, obsługa buforowania jest naprawdę pomocna i znacznie poprawia szybkość. Ale może to prowadzić do interesujących problemów, w których dane nie kończą się w pliku, gdy się go spodziewasz. Musisz pamiętać o tym fcloselub fflushw odpowiednich momentach.

Jeśli poszukujesz (aka fsetposlub fseekdrugi jest nieco trudniejszy do użycia w sposób zgodny ze standardami), użyteczność buforowania szybko spada.

Oczywiście, moja stronniczość polega na tym, że często pracuję z gniazdami, a tam jest fakt, że naprawdę chcesz robić nie blokujące IO (które FILE *całkowicie nie obsługuje w żaden rozsądny sposób) bez buforowania i często złożone wymagania dotyczące parsowania naprawdę koloryzują moje postrzeganie.

Wszelaki
źródło
4
Nie zamierzam kwestionować twoich doświadczeń, ale chciałbym usłyszeć, jak trochę się nad tym zastanawiasz. Jakiego rodzaju aplikacje utrudniają wbudowane buforowanie? Na czym dokładnie polega problem?
Emil H
1
Nie widziałem ostatniego akapitu. Ważny punkt, IMHO. O ile wiem, pytanie dotyczyło pliku IO.
Emil H
7
Wyjaśnienie, kiedy przeszkadza buforowanie. To wtedy, gdy używasz wyszukiwania. Poniższy odczytu z dowolnej komendzie ( fgets, fgetc, fscanf, fread), zawsze będzie przeczytać cały rozmiar bufora (4K, 8K lub cokolwiek ustawić). Korzystając z bezpośredniego wejścia / wyjścia możesz tego uniknąć. W takim przypadku lepiej jest użyć preadzamiast pary wyszukiwania / odczytu (1 syscall zamiast 2).
Patrick Schlüter
2
Obsługa przerwanych read()i write()wywołań jest wygodnym piątym powodem korzystania z rodziny funkcji libc.
nccc
3
@ m-ric: To trochę niezwiązane pytanie, ale tak. Wszystkie obsługiwane platformy obsługują ioctltakże filenopołączenie, które przyjmuje FILE *numer i zwraca numer, którego można użyć w ioctlpołączeniu. Bądź jednak ostrożny. FILE *wywołania pokrewne mogą zadziwiająco oddziaływać z użyciem ioctldo zmiany czegoś na temat podstawowego deskryptora pliku.
Wszechobecny
53

open()jest niskopoziomowym połączeniem OS. fdopen()konwertuje deskryptor pliku na poziomie systemu operacyjnego na abstrakcyjną PLIK abstrakcję języka C.fopen()wywołuje open()w tle i daje bezpośrednio wskaźnik PLIKU.

Istnieje kilka korzyści z używania obiektów PLIK zamiast raczej surowych deskryptorów plików, co obejmuje większą łatwość użycia, ale także inne zalety techniczne, takie jak wbudowane buforowanie. Zwłaszcza buforowanie generalnie zapewnia znaczną przewagę wydajności.

Emil H.
źródło
3
Czy są jakieś wady korzystania z buforowanych wersji „f ...” programu open?
LJM,
5
@L. Moser, tak, kiedy już buforujesz dane, a zatem dodatkowy bufor dodaje niepotrzebne kopiowanie i narzut pamięci.
Michael Aaron Safyan
6
w rzeczywistości istnieją inne wady. fopen()nie zapewnia tego samego poziomu kontroli podczas otwierania plików, na przykład tworzenia uprawnień, trybów udostępniania i innych. zazwyczaj open()warianty zapewniają znacznie większą kontrolę, zbliżoną do tego, co faktycznie zapewnia system operacyjny
Matt Joiner,
2
Istnieją również skrajne przypadki, w których mmapplik i zmiany są wykonywane przy użyciu normalnego wejścia / wyjścia (choć wydaje się to niewiarygodne, faktycznie robimy to w naszym projekcie i to z naprawdę dobrych powodów), buforowanie byłoby przeszkodą.
Patrick Schlüter
Możesz także użyć innych funkcji systemowych, takich jak użycie open () do wstępnego ładowania plików do pamięci podręcznej strony za pomocą readahead (). Myślę, że ogólną zasadą jest „użyj fopen, chyba że absolutnie potrzebujesz open ()”, open () faktycznie pozwala ci robić wymyślne rzeczy (ustawienie / brak ustawienia O_ATIME i podobne).
Tomas Pruzina
34

fopen vs open w C

1) fopenjest funkcją biblioteki, podczas gdy openjest wywołaniem systemowym .

2) fopenzapewnia buforowane we / wy, które jest szybsze w porównaniu z tym, openktóre nie jest buforowane .

3) fopenjest przenośny, ale opennie przenośny ( otwarty jest specyficzny dla środowiska ).

4) fopenzwraca wskaźnik do struktury PLIKU (PLIK *) ; openzwraca liczbę całkowitą identyfikującą plik.

5) A FILE *daje możliwość korzystania z fscanf i innych funkcji stdio.

Yogeesh HT
źródło
9
openjest standardem POSIX, więc jest dość przenośny
osvein
12

O ile nie należysz do 0,1% aplikacji, w których używanie opento rzeczywista poprawa wydajności, naprawdę nie ma dobrego powodu, aby nie używać fopen. Jeśli chodzi fdopeno deskryptory plików, nie potrzebujesz tego połączenia.

Stick with fopena jego rodzina metod ( fwrite, fread, fprintf, et al) i będziesz bardzo zadowolony. Co równie ważne, inni programiści będą zadowoleni z twojego kodu.

użytkownik7116
źródło
11

Jeśli masz FILE *, możesz korzystać z funkcji takich jak fscanf, fprintfi fgetsitd. Jeśli masz tylko deskryptor pliku, masz ograniczone (ale prawdopodobnie szybciej) procedury wejścia i wyjścia read, writeetc.

dreamlax
źródło
7

Korzystanie z otwartego, odczytu, zapisu oznacza, że ​​musisz się martwić interceptami sygnałów.

Jeśli wywołanie zostało przerwane przez moduł obsługi sygnałów, funkcje zwrócą -1 i ustawią errno na EINTR.

Tak więc właściwym sposobem byłoby zamknięcie pliku

while (retval = close(fd), retval == -1 && ernno == EINTR) ;
digy
źródło
4
Na closeto zależy od systemu operacyjnego. Pętla nie jest wykonywana w systemie Linux, AIX i niektórych innych systemach operacyjnych.
strcat
Ponadto korzystanie z odczytu i zapisu będzie miało ten sam problem, tzn. Mogą zostać przerwane przez sygnał przed całkowitym przetworzeniem wejścia / wyjścia, a programista musi poradzić sobie z takimi sytuacjami, podczas gdy fread i fwrite ładnie radzą sobie z przerwami w sygnale.
Marcelo
6

open()to wywołanie systemowe specyficzne dla systemów opartych na Uniksie i zwraca deskryptor pliku. Możesz pisać do deskryptora pliku, używając write()innego wywołania systemowego.
fopen()to wywołanie funkcji ANSI C, które zwraca wskaźnik pliku i jest przenośne na inne systemy operacyjne. Możemy pisać do wskaźnika pliku za pomocą fprintf.

W
systemie Unix: wskaźnik pliku można uzyskać z deskryptora pliku, używając:

fP = fdopen(fD, "a");

Deskryptor pliku można uzyskać ze wskaźnika pliku, używając:

fD = fileno (fP);
Arun Chettoor
źródło
4

open () zostanie wywołany na końcu każdej funkcji rodziny fopen () . open () to wywołanie systemowe, a biblioteki fopen () są dostarczane przez biblioteki jako funkcje otoki dla łatwego użycia przez użytkownika

theadnangondal
źródło
2

Zmieniłem na open () z fopen () dla mojej aplikacji, ponieważ fopen powodował podwójne odczyty przy każdym uruchomieniu fopen fgetc. Podwójne odczyty zakłócały to, co próbowałem osiągnąć. wydaje się, że open () robi to, o co go prosisz.

Ersatz Splatt
źródło
2

Zależy również od tego, jakie flagi są wymagane do otwarcia. W odniesieniu do użycia do pisania i czytania (i przenośności) należy użyć f *, jak argumentowano powyżej.

Ale jeśli w zasadzie chcesz podać więcej niż standardowe flagi (takie jak flagi rw i append), będziesz musiał użyć interfejsu API specyficznego dla platformy (jak POSIX open) lub biblioteki, która wyodrębnia te szczegóły. Standard C nie ma takich flag.

Na przykład możesz chcieć otworzyć plik, tylko jeśli zostanie zamknięty. Jeśli nie określisz flagi tworzenia, plik musi istnieć. Jeśli dodasz wyłączność do utworzenia, plik zostanie utworzony tylko wtedy, gdy nie istnieje. Jest o wiele więcej.

Na przykład w systemach Linux dostępny jest interfejs LED odsłonięty przez sysfs. Odsłania jasność diody LED przez plik. Zapis lub odczyt liczby w postaci ciągu od 0-255. Oczywiście nie chcesz tworzyć tego pliku i pisać do niego tylko wtedy, gdy on istnieje. Fajna rzecz: użyj fdopen do odczytu / zapisu tego pliku za pomocą standardowych wywołań.

Ritualmaster
źródło
0

otwierając plik za pomocą fopen,
zanim będziemy mogli odczytać (lub zapisać) informacje z (do) pliku na dysku, musimy go otworzyć. aby otworzyć plik, wywołaliśmy funkcję fopen.

1.firstly it searches on the disk the file to be opened.
2.then it loads the file from the disk into a place in memory called buffer.
3.it sets up a character pointer that points to the first character of the buffer.

ten sposób zachowania funkcji fopen
ma pewne przyczyny podczas buforowania, może upłynąć limit czasu. więc porównując fopen (wysoki poziom we / wy) z otwartym wywołaniem systemowym (niski poziom we / wy), i jest to szybsze bardziej odpowiednie niż fopen .

prashad
źródło
jest otwarty szybciej niż fopen?
obayhan
tak, otwarte jest wywołanie systemowe, które jest szybsze niż fopen - porównawczo @obayhan
prashad