Jaka jest różnica między deskryptorem pliku a wskaźnikiem pliku?

Odpowiedzi:

144

Deskryptor pliku to „uchwyt” niskiego poziomu, będący liczbą całkowitą, używaną do identyfikacji otwartego pliku (lub gniazda, lub cokolwiek innego) na poziomie jądra, w Linuksie i innych systemach uniksopodobnych.

Zdasz „naked” deskryptorów plików do rzeczywistych połączeń, takich jak Unix read(), write()i tak dalej.

FILEWskaźnik jest C konstrukt standardowe na poziomie biblioteki, która służy do reprezentowania pliku. FILEOwija deskryptor pliku i dodaje buforowanie i inne funkcje, aby wejść / wyjść łatwiejsze.

Przekazujesz FILEwskaźniki do standardowych funkcji C, takich jak fread()i fwrite().

rozwijać
źródło
@nvl: fildes jest z pewnością dostępny dla systemu Windows, np. msdn.microsoft.com/en-us/library/z0kc8e3z%28VS.80%29.aspx
kennytm
2
@unwind Co masz na myśli, mówiąc o „nagich” deskryptorach plików? Połączone odwołanie mówi, że fdjest pierwszym argumentem do read(). Dlaczego nazywasz to nagim?
Geek
3
@Geek W porównaniu z FILE *typem biblioteki standardowej , deskryptor pliku liczb całkowitych jest „mniej zawinięty”, tj. „Nagi”.
odpoczynek
57

Jeden jest buforowany ( FILE *), a drugi nie. W praktyce chcesz używać go FILE *prawie zawsze, gdy czytasz z „prawdziwego” pliku (tj. Na dysku), chyba że wiesz, co robisz lub jeśli twój plik jest gniazdem lub czymś podobnym.

Możesz pobrać deskryptor pliku z FILE *using fileno()i możesz otworzyć buforowany FILE *z deskryptora pliku za pomocąfdopen()

Ben
źródło
12
+1 za wskazanie fileno (), organizacja stron podręcznika man utrudnia znalezienie tego. To samo dotyczy fdopen ().
BD w Rivenhill
20

Deskryptor pliku to po prostu liczba całkowita, którą otrzymujesz z open()wywołania POSIX . Używając standardowego C fopen(), otrzymujesz FILEstrukturę z powrotem. Struktura FILEzawiera ten deskryptor pliku, między innymi, takie jak koniec pliku i wskaźnik błędu, pozycja strumienia itp.

Więc użycie fopen()daje pewną ilość abstrakcji w porównaniu z open(). Ogólnie powinieneś używać, fopen()ponieważ jest to bardziej przenośne i możesz używać wszystkich innych standardowych funkcji C, które używają FILEstruktury struct, tj. fprintf()I rodziny.

Nie ma problemów z wydajnością przy użyciu.

Martin Wickman
źródło
8
+1 za podniesienie przenośności. FILE jest częścią standardowej biblioteki C (wstecz do C89 / C90); deskryptory plików nie są.
tomlogic
15

Deskryptor pliku a wskaźnik pliku

Deskryptor pliku:

Deskryptor pliku to liczba całkowita zwracana przez open()wywołanie systemowe.

int fd = open (filePath, mode);

  1. Obsługa niskiego poziomu / jądra.
  2. passe do odczytu () i zapisu () wywołań systemowych UNIX.
  3. Nie obejmuje buforowania i takich funkcji.
  4. Mniej przenośny i brakuje mu wydajności.

Wskaźnik pliku:

Wskaźnik pliku jest wskaźnikiem do struktury C zwróconej przez fopen()funkcję biblioteczną, która służy do identyfikacji pliku, zawijania deskryptora pliku, funkcji buforowania i wszystkich innych funkcji potrzebnych do operacji we / wy . Wskaźnik pliku jest typu FILE , którego definicja można znaleźć w „/usr/include/stdio.h” . Ta definicja może się różnić w zależności od kompilatora.

FILE *fp = fopen (filePath, mode);

// A FILE Structure returned by fopen 
    typedef struct 
    {
        unsigned char   *_ptr;
        int     _cnt;
        unsigned char   *_base;
        unsigned char   *_bufendp;
        short   _flag;
        short   _file;
        int     __stdioid;
        char    *__newbase;
#ifdef _THREAD_SAFE
        void *_lock;
#else
        long    _unused[1];
#endif
#ifdef __64BIT__
        long    _unused1[4];
#endif /* __64BIT__ */
    } FILE;
  1. Jest to interfejs wysokiego poziomu.
  2. Przekazywane do funkcji fread () i fwrite ().
  3. Obejmuje buforowanie, wskazywanie błędów i wykrywanie EOF itp.
  4. Zapewnia większą przenośność i wydajność.
Yogeesh HT
źródło
1
Czy jesteś w stanie poprzeć to roszczenie dotyczące wyższej wydajności? Nigdy tego nie słyszałem.
Gid,
1
Twierdzenie o „wydajności” może wynikać z buforowania. W przypadku deskryptora pliku każde polecenie read () lub write () jest wywołaniem systemowym, a każde wywołanie systemowe należy traktować jako kosztowne. W przypadku PLIKU * buforowanie oznacza, że ​​niektóre odczyty i zapisy nie będą wywołania systemowe.
Mike Spear,
12

Chcesz dodać punkty, które mogą być przydatne.

O FILE *

  1. nie może być używany do komunikacji międzyprocesowej (IPC).
  2. użyj go, gdy potrzebujesz buforowanego wejścia / wyjścia ogólnego przeznaczenia. (printf, frpintf, snprintf, scanf)
  3. Używam go wiele razy do dzienników debugowania. przykład,

                 FILE *fp;
                 fp = fopen("debug.txt","a");
                 fprintf(fp,"I have reached till this point");
                 fclose(fp);

O FILE DESCRIPTOR

  1. Zwykle jest używany do IPC.

  2. Daje niskopoziomową kontrolę nad plikami w systemach * nix. (Urządzenia, pliki, gniazda itp.), Przez co jest bardziej wydajny niż FILE *.

Akshay Patil
źródło
Nie możesz używać fdopen()do takich rzeczy, jak IPC i urządzenia FILE*?
osvein
Właściwie zarówno tak, jak i nie. Nie możesz skonfigurować i zainicjować IPC za pomocą FILE*, ale możesz utworzyć FILE*z deskryptora pliku ( fdopen()), a później FILEzamknąć również deskryptor. Dlatego możesz zrobić IPC, ale musisz trochę poradzić sobie z deskryptorami plików, aby ułatwić bezpośrednie IPC.
Micah W
3

FILE *jest bardziej przydatna podczas pracy z plikami tekstowymi i wejściem / wyjściem, ponieważ pozwala na użycie funkcji API jak sprintf(), sscanf(), fgets(), feof()itd

API deskryptora plików jest niskopoziomowe, więc pozwala na pracę z gniazdami, potokami, plikami mapowanymi w pamięci (i oczywiście zwykłymi plikami).

qrdl
źródło
1
+1, ponieważ dodałeś pliki mapowane w pamięci, ponieważ w moim obecnym czytaniu inne odpowiedzi zostały już dostarczone.
ernie.cordell
3

Tylko uwaga na zakończenie dyskusji (jeśli zainteresowany) ....

fopenmoże być niezabezpieczone i prawdopodobnie powinieneś używać fopen_slub openz ustawionymi na wyłączność bitami. C1X oferuje xtryby, dzięki czemu można fopenz trybów "rx", "wx"itp

Jeśli używasz open, możesz rozważyć open(..., O_EXCL | O_RDONLY,... )lub open(..., O_CREAT | O_EXCL | O_WRONLY,... ).

Zobacz, na przykład, Nie rób założeń dotyczących fopen () i tworzenia plików .

jww
źródło
Ponieważ fopen_snie wydaje się być dostępny z POSIX, zakładam, że najbardziej przenośnym soultion byłoby to open(2)i wtedy fdopen(2). (pozostawiając okna na bok). Co byłoby szybsze fopen_s()lub co open(2)nastąpiłoby po nim fdopen(2)?
Mihir
1

Wywołania systemowe używają głównie deskryptora pliku, na przykład readi write. Funkcja biblioteki użyje wskaźników plików ( printf, scanf). Ale funkcje biblioteczne używają tylko wewnętrznych wywołań systemowych.

Pavunkumar
źródło
Nie jestem pewien, dlaczego twierdzisz, że funkcje biblioteczne używają tylko wewnętrznych wywołań systemowych: jeśli masz na myśli standardowe funkcje CI / O (lub jakiekolwiek inne w tym zakresie), nie jestem pewien, czy to (ogólnie?) Prawda. W przeciwnym razie to nie to, co powiedziałeś, więc chciałbym, aby język w Twoim poście został trochę uporządkowany. Ostatnie zdanie mnie zaskakuje.
ernie.cordell
1

Znalazłem dobre źródło tutaj , dając przegląd wysoki poziom różnic pomiędzy nimi:

Jeśli chcesz wprowadzić dane do pliku lub wyprowadzić je z pliku, masz do wyboru dwa podstawowe mechanizmy reprezentowania połączenia między programem a plikiem: deskryptory plików i strumienie. Deskryptory plików są reprezentowane jako obiekty typu int, podczas gdy strumienie są reprezentowane jako obiekty typu FILE *.

Deskryptory plików zapewniają prymitywny, niskopoziomowy interfejs do operacji wejścia i wyjścia. Zarówno deskryptory plików, jak i strumienie mogą reprezentować połączenie z urządzeniem (takim jak terminal) lub potokiem lub gniazdem do komunikacji z innym procesem, a także zwykłym plikiem. Jeśli jednak chcesz wykonywać operacje sterujące, które są specyficzne dla określonego rodzaju urządzenia, musisz użyć deskryptora pliku; nie ma możliwości wykorzystania strumieni w ten sposób. Musisz także użyć deskryptorów plików, jeśli twój program musi wykonywać dane wejściowe lub wyjściowe w specjalnych trybach, takich jak nieblokujące (lub odpytywane) wejście (zobacz Flagi stanu plików).

Strumienie zapewniają interfejs wyższego poziomu, nałożony na podstawowe funkcje deskryptorów plików. Interfejs przesyłania strumieniowego traktuje wszystkie rodzaje plików prawie tak samo - jedynym wyjątkiem są trzy style buforowania, które możesz wybrać (zobacz Buforowanie strumienia).

Główną zaletą korzystania z interfejsu strumieniowego jest to, że zestaw funkcji do wykonywania rzeczywistych operacji wejścia i wyjścia (w przeciwieństwie do operacji sterujących) na strumieniach jest znacznie bogatszy i potężniejszy niż odpowiednie narzędzia do deskryptorów plików. Interfejs deskryptora plików zapewnia tylko proste funkcje do przesyłania bloków znaków, ale interfejs strumieniowy zapewnia również potężne sformatowane funkcje wejścia i wyjścia (printf i scanf), a także funkcje znakowego i liniowego wejścia i wyjścia.

Ponieważ strumienie są implementowane w postaci deskryptorów plików, można wyodrębnić deskryptor pliku ze strumienia i wykonać operacje niskiego poziomu bezpośrednio na deskryptorze pliku. Możesz również początkowo otworzyć połączenie jako deskryptor pliku, a następnie utworzyć strumień powiązany z tym deskryptorem pliku.

Ogólnie rzecz biorąc, powinieneś trzymać się strumieni zamiast deskryptorów plików, chyba że chcesz wykonać jakąś konkretną operację, którą można wykonać tylko na deskryptorze pliku. Jeśli jesteś początkującym programistą i nie masz pewności, jakich funkcji użyć, sugerujemy skoncentrowanie się na sformatowanych funkcjach wejściowych (zobacz formatowane wejście) i sformatowanych funkcjach wyjściowych (zobacz sformatowane dane wyjściowe).

Jeśli obawiasz się przenoszenia swoich programów na systemy inne niż GNU, powinieneś również mieć świadomość, że deskryptory plików nie są tak przenośne jak strumienie. Możesz oczekiwać, że każdy system z ISO C będzie obsługiwał strumienie, ale systemy inne niż GNU mogą w ogóle nie obsługiwać deskryptorów plików lub mogą implementować tylko podzbiór funkcji GNU, które działają na deskryptorach plików. Jednak większość funkcji deskryptorów plików w bibliotece GNU C jest zawarta w standardzie POSIX.1.

Suraj Jain
źródło