Odpowiedzi:
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.
FILE
Wskaźnik jest C konstrukt standardowe na poziomie biblioteki, która służy do reprezentowania pliku. FILE
Owija deskryptor pliku i dodaje buforowanie i inne funkcje, aby wejść / wyjść łatwiejsze.
Przekazujesz FILE
wskaźniki do standardowych funkcji C, takich jak fread()
i fwrite()
.
fd
jest pierwszym argumentem do read()
. Dlaczego nazywasz to nagim?
FILE *
typem biblioteki standardowej , deskryptor pliku liczb całkowitych jest „mniej zawinięty”, tj. „Nagi”.
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()
Deskryptor pliku to po prostu liczba całkowita, którą otrzymujesz z open()
wywołania POSIX . Używając standardowego C fopen()
, otrzymujesz FILE
strukturę z powrotem. Struktura FILE
zawiera 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ą FILE
struktury struct, tj. fprintf()
I rodziny.
Nie ma problemów z wydajnością przy użyciu.
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);
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;
Chcesz dodać punkty, które mogą być przydatne.
O FILE *
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
Zwykle jest używany do IPC.
Daje niskopoziomową kontrolę nad plikami w systemach * nix. (Urządzenia, pliki, gniazda itp.), Przez co jest bardziej wydajny niż FILE *
.
fdopen()
do takich rzeczy, jak IPC i urządzenia FILE*
?
FILE*
, ale możesz utworzyć FILE*
z deskryptora pliku ( fdopen()
), a później FILE
zamknąć również deskryptor. Dlatego możesz zrobić IPC, ale musisz trochę poradzić sobie z deskryptorami plików, aby ułatwić bezpośrednie IPC.
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).
Tylko uwaga na zakończenie dyskusji (jeśli zainteresowany) ....
fopen
może być niezabezpieczone i prawdopodobnie powinieneś używać fopen_s
lub open
z ustawionymi na wyłączność bitami. C1X oferuje x
tryby, dzięki czemu można fopen
z 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 .
fopen_s
nie 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)
?
Wywołania systemowe używają głównie deskryptora pliku, na przykład read
i write
. Funkcja biblioteki użyje wskaźników plików ( printf
, scanf
). Ale funkcje biblioteczne używają tylko wewnętrznych wywołań systemowych.
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.