Co to są deskryptory plików, wyjaśnione w prosty sposób?


383
  1. Jaki byłby bardziej uproszczony opis deskryptorów plików w porównaniu do Wikipedii? Dlaczego są wymagane? Powiedzmy, weźmy procesy powłoki jako przykład i jak się do tego stosuje?

  2. Czy tabela procesów zawiera więcej niż jeden deskryptor pliku. Jeśli tak, dlaczego?


3
Co z koncepcjami stdin stdout stderr itp? Mam instancję taką, jak powiedzmy, że proces przeglądarki został otwarty i otworzył kilka plików tymczasowych do wyświetlenia mojego pliku HTML. Proces używa tego samego fd do odczytu / zapisu? Również tabela procesów ....... zawiera wpisy takie jak wskaźnik fd0 wskaźnik fd1 wskaźnik fd2 ..... czy to znaczy, że wszystkie te pliki są w pamięci RAM? Po co jeszcze wskaźniki?
Nishant,

43
Po otwarciu pliku system operacyjny tworzy strumień do tego pliku i łączy ten strumień z otwartym plikiem, deskryptor faktycznie reprezentuje ten strumień. Podobnie istnieją pewne domyślne strumienie tworzone przez system operacyjny. Te strumienie są podłączone do terminala zamiast plików. Więc kiedy piszesz coś w terminalu, przechodzi do standardowego strumienia i systemu operacyjnego. A kiedy napiszesz polecenie „ls” na terminalu, system operacyjny zapisuje dane wyjściowe w strumieniu standardowym. Strumień wyjścia standardowego jest podłączony do terminala monitora, dzięki czemu można tam wyświetlić dane wyjściowe.
Tayyab,

1
Jeśli chodzi o przykład przeglądarki, przeglądarka nie musi otwierać plików. Zależy to od implementacji przeglądarki, ale w większości przypadków przeglądarka otwiera plik tymczasowy, zapisuje plik i zamyka plik, więc nie jest konieczne otwieranie pliku, nawet jeśli strona internetowa jest otwarta. A deskryptor po prostu przechowuje informacje o pliku i niekoniecznie przechowuje plik w pamięci RAM. Podczas odczytywania danych z deskryptora system operacyjny odczytuje dane z dysku twardego. Informacje w deskryptorze pliku reprezentują tylko lokalizację pliku na dysku twardym itp.
Tayyab

5
Deskryptor pliku do pliku nie jest mapowaniem jeden na jeden. Mógłbym otworzyć () ten sam plik 4 razy i uzyskać 4 różne deskryptory plików. Każdy z nich może być użyty (w zależności od flag przekazanych do open ()) do czytania, pisania lub obu. Jeśli chodzi o to, czy plik znajduje się w pamięci RAM, czy na dysku - jest to ukryte przed tobą przez jądro i jego różne pamięci podręczne. Ostatecznie to, co jest w buforze, będzie pasowało do tego, co jest na dysku (do zapisu), a jądro nie wróci na dysk, do odczytu, jeśli dane są już w buforze.
Beano,

7
To dobry artykuł, aby łatwo to zrozumieć bottomupcs.com/file_descriptors.xhtml
Krishan Gopal

Odpowiedzi:


561

Krótko mówiąc, po otwarciu pliku system operacyjny tworzy wpis reprezentujący ten plik i przechowujący informacje o tym otwartym pliku. Więc jeśli w twoim systemie jest otwartych 100 plików, w systemie będzie 100 wpisów (gdzieś w jądrze). Te wpisy są reprezentowane przez liczby całkowite, takie jak (... 100, 101, 102 ....). Ten numer wpisu jest deskryptorem pliku. Jest to więc liczba całkowita, która jednoznacznie reprezentuje otwarty plik w systemie operacyjnym. Jeśli twój proces otworzy 10 plików, twoja tabela procesów będzie miała 10 pozycji dla deskryptorów plików.

Podobnie, gdy otwierasz gniazdo sieciowe, jest ono również reprezentowane przez liczbę całkowitą i nazywa się Script Descriptor. Mam nadzieję że rozumiesz.


7
Również dlatego możesz zabraknąć deskryptorów plików, jeśli otworzysz wiele plików jednocześnie. Co uniemożliwi działanie systemów * nix, ponieważ przez /proccały czas otwierają deskryptory .
Spencer Rathbun

8
@ErbenMo: Nie, może nie być taki sam. Kiedy otworzysz plik, system operacyjny przypisze FD, który jest dostępny, a kiedy go zamkniesz, system operacyjny zwolni FD i może przypisać ten FD do innego pliku, który zostanie otwarty później. Sposób śledzenia otwartych plików przez system operacyjny nie ma nic wspólnego z konkretnym plikiem.
Tayyab

49
Więc jest to tylko liczba całkowita, która jednoznacznie reprezentuje otwarty plik w systemie operacyjnym. ” To jest niepoprawne. Ta liczba całkowita jednoznacznie reprezentuje otwarty plik w procesie . Na przykład deskryptor pliku 0 będzie reprezentował jeden otwarty plik w jednym procesie i zupełnie inny otwarty plik w innym procesie.
Keith Thompson

15
@Tayyab: Myślę, że się mylisz. Deskryptory plików 0, 1 i 2 to standardowe wejście, standardowe wyjście i standardowy błąd dla każdego uruchomionego procesu. Pomyślne początkowe wywołanie open()da deskryptor pliku 3, nawet jeśli inny uruchomiony proces ma deskryptor pliku 3. Zobacz definicję POSIXopen() : „Funkcja open () zwróci deskryptor pliku dla nazwanego pliku, który jest najniższy deskryptor pliku nie jest obecnie otwarty dla tego procesu . ” (podkreślenie dodane).
Keith Thompson

17
@KeithThompson: Tak, masz rację. Właściwie chodzi o poziom abstrakcji. W rzeczywistości utrzymywane są dwie tabele, przy czym pierwsza z nich dotyczy poszczególnych procesów, a druga obejmuje cały system. FD w tabeli na proces (tj. Fdtable) nie jest unikalnym systemem. Jednak mapuje do tabeli węzłów typu v, która zawiera unikalne wpisy systemowe. Kiedy więc wywołujesz funkcje fopen () i fileno () w celu sprawdzenia deskryptora, możesz uzyskać ten sam numer FD w 2 różnych procesach, ponieważ zwraca on indeks fdtable dla każdego procesu. Dzięki za poruszenie tego tematu !!
Tayyab

116

Deskryptor pliku jest nieprzezroczystym uchwytem używanym w interfejsie między przestrzenią użytkownika a jądrem do identyfikowania zasobów plików / gniazd. Dlatego, kiedy używasz open()lub socket()(systemowe wywołania interfejsu do jądra), dostajesz deskryptor pliku, który jest liczbą całkowitą (jest to faktycznie indeks struktury procesów - ale to nie jest ważne). Dlatego, jeśli chcesz współpracować bezpośrednio z jądra, używając wywołań systemowych read(), write(), close()itp uchwyt używasz jest deskryptor pliku.

Na wywołania systemowe nakładana jest warstwa abstrakcji, którą jest stdiointerfejs. Zapewnia to więcej funkcji / funkcji niż podstawowe wywołania systemowe. W przypadku tego interfejsu nieprzezroczysty uchwyt, który otrzymujesz FILE*, jest zwracany przez fopen()wywołanie. Istnieje wiele wiele funkcji, które korzystają z stdiointerfejsu fprintf(), fscanf(), fclose(), które są tam, aby ułatwić Ci życie. W C stdin, stdouti stderrto FILE*, co w systemie UNIX odpowiednio mapować do deskryptorów plików 0, 1a 2.


6
Osobiście uważam, że ta odpowiedź jest lepsza niż ta oznaczona jako odpowiedź. Pozytywne.
Tarik

101

Posłuchaj go z Horse's Mouth: APUE (Richard Stevens).
Do jądra wszystkie otwarte pliki są przywoływane przez deskryptory plików. Deskryptor pliku jest liczbą nieujemną.

Kiedy otwieramy istniejący plik lub tworzymy nowy, jądro zwraca deskryptor pliku do procesu. Jądro utrzymuje tabelę wszystkich używanych deskryptorów otwartych plików. Przydział deskryptorów plików jest zasadniczo sekwencyjny i są one przydzielane do pliku jako następny wolny deskryptor pliku z puli wolnych deskryptorów plików. Kiedy zamykamy plik, deskryptor pliku zostaje zwolniony i jest dostępny do dalszego przydziału.
Zobacz ten obraz, aby uzyskać więcej informacji:

Dwa procesy

Kiedy chcemy odczytać lub zapisać plik, identyfikujemy plik za pomocą deskryptora pliku, który został zwrócony przez wywołanie funkcji open () lub create () , i używamy go jako argumentu funkcji read () lub write () .
Zasadniczo powłoki systemu UNIX kojarzą deskryptor pliku 0 ze standardowym wejściem procesu, deskryptor pliku 1 ze standardowym wyjściem , a deskryptor pliku 2 ze standardowym błędem .
Zakres deskryptorów plików wynosi od 0 do OPEN_MAX. Maksymalną wartość deskryptora pliku można uzyskać za pomocą ulimit -n. Aby uzyskać więcej informacji, przejdź do trzeciego rozdziału książki APUE.


1
Ponieważ 0, 1, 2 są powiązane z „stdin”, „stdout” i „stderr” procesu, czy możemy używać tych deskryptorów jednocześnie dla różnych procesów?
Tarik

@ Tarik: deskryptory plików są na proces. Aby to zobaczyć, pobierz osquery i uruchom osqueryi <<< echo '.all process_open_files'w powłoce bash.
Ben Creasy

29

Inne odpowiedzi dodały świetne rzeczy. Dodam tylko moje 2 centy.

Według Wikipedii wiemy na pewno: deskryptor pliku jest nieujemną liczbą całkowitą. Najważniejszą rzeczą, którą moim zdaniem brakuje, byłoby powiedzenie:

Deskryptory plików są powiązane z identyfikatorem procesu.

Wiemy, że najbardziej znane deskryptory plików to 0, 1 i 2. 0 odpowiada STDIN , 1 do STDOUTi 2 do STDERR.

Powiedzmy, weźmy procesy powłoki jako przykład i jak się do tego stosuje?

Sprawdź ten kod

#>sleep 1000 &
[12] 14726

Stworzyliśmy proces o identyfikatorze 14726 (PID). Używająclsof -p 14726 możemy uzyskać takie rzeczy:

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
sleep   14726 root  cwd    DIR    8,1     4096 1201140 /home/x
sleep   14726 root  rtd    DIR    8,1     4096       2 /
sleep   14726 root  txt    REG    8,1    35000  786587 /bin/sleep
sleep   14726 root  mem    REG    8,1 11864720 1186503 /usr/lib/locale/locale-archive
sleep   14726 root  mem    REG    8,1  2030544  137184 /lib/x86_64-linux-gnu/libc-2.27.so
sleep   14726 root  mem    REG    8,1   170960  137156 /lib/x86_64-linux-gnu/ld-2.27.so
sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

Czwarta kolumna FD i następna kolumna TYPE odpowiadają deskryptorowi pliku i typowi deskryptora pliku.

Niektóre wartości FD mogą być:

cwd – Current Working Directory
txt – Text file
mem – Memory mapped file
mmap – Memory mapped device

Ale prawdziwy deskryptor pliku znajduje się w:

NUMBER – Represent the actual file descriptor. 

Znak po liczbie, tj. „1u”, oznacza tryb, w którym plik jest otwierany. r do odczytu, w do zapisu, u do odczytu i zapisu.

TYPE określa typ pliku. Niektóre wartości TYPE to:

REG – Regular File
DIR – Directory
FIFO – First In First Out

Ale wszystkie deskryptory plików to CHR - znak specjalny plik (lub plik urządzenia znakowego)

Teraz możemy zidentyfikować deskryptorów dla STDIN, STDOUTi STDERRłatwe lsof -p PID, czy widzimy to samo, gdybyśmy ls /proc/PID/fd.

Zauważ też, że tablica deskryptorów plików, którą śledzi jądro, nie jest taka sama jak tabela plików lub tabela i-węzłów. Są to osobne, jak wyjaśniono niektóre inne odpowiedzi.

stół fd

Można zadać sobie pytanie, gdzie są te deskryptory plików fizycznie i to, co jest zapisane w /dev/pts/6na przykład

sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

Cóż, /dev/pts/6żyje wyłącznie w pamięci. Nie są to zwykłe pliki, ale tak zwane pliki urządzeń znakowych . Możesz to sprawdzić za pomocą: ls -l /dev/pts/6i zaczną od c, w moim przypadku crw--w----.

Aby przypomnieć sobie większość systemów operacyjnych typu Linux, zdefiniuj siedem rodzajów plików:

  • Zwykłe pliki
  • Katalogi
  • Pliki urządzeń znakowych
  • Zablokuj pliki urządzenia
  • Gniazda domeny lokalnej
  • Nazwane potoki (FIFO) i
  • Linki symboliczne

1
Dzięki. Rzeczywiście ważne jest, aby zaznaczyć, że jest to proces! Pomaga lepiej wizualizować rzeczy.
Nishant

1
Typy plików zdefiniowanych przez system operacyjny, o których wspomniałeś w swojej odpowiedzi, naprawdę pomagają w zrozumieniu plików na niższym poziomie.
Rohan Bhale

20

Więcej punktów dotyczących File Descriptor:

  1. File Descriptors(FD) to nieujemne liczby całkowite (0, 1, 2, ...)powiązane z otwieranymi plikami.

  2. 0, 1, 2są standardowe FD „s, która odpowiada STDIN_FILENO, STDOUT_FILENOi STDERR_FILENO(zdefiniowane w unistd.h) domyślnie otwierane w imieniu skorupy podczas uruchamiania programu.

  3. FD są przydzielane w kolejności sekwencyjnej, co oznacza najniższą możliwą nieprzydzieloną wartość całkowitą.

  4. FD dla konkretnego procesu można zobaczyć w /proc/$pid/fd(w systemach opartych na Uniksie).


16

Jako uzupełnienie innych odpowiedzi, unix traktuje wszystko jako system plików. Twoja klawiatura jest plikiem, który jest czytany tylko z perspektywy jądra. Ekran jest plikiem tylko do zapisu. Podobnie foldery, urządzenia wejścia-wyjścia itp. Są również uważane za pliki. Za każdym razem, gdy plik jest otwierany, powiedzmy, gdy sterowniki urządzeń [dla plików urządzeń] żądają otwarcia () lub gdy proces otwiera plik użytkownika, jądro przydziela deskryptor pliku, liczbę całkowitą, która określa dostęp do tego pliku, tak że jest on tylko do odczytu , pisz tylko itd. [dla odniesienia: https://en.wikipedia.org/wiki/Everything_is_a_file ]


Deskryptory plików mogą również odnosić się do rzeczy, które nie istnieją w systemie plików, takich jak anonimowe potoki i gniazda sieciowe.
kbolino

12

Deskryptory plików (FD):

  • W systemie Linux / Unix wszystko jest plikiem. Zwykłe pliki, katalogi, a nawet urządzenia to pliki. Każdy plik ma przypisany numer o nazwie File Descriptor (FD).
  • Twój ekran ma również deskryptor pliku. Po uruchomieniu programu dane wyjściowe są wysyłane do deskryptora pliku ekranu, a dane wyjściowe programu są wyświetlane na monitorze. Jeśli dane wyjściowe są wysyłane do deskryptora pliku drukarki, wynik programu zostałby wydrukowany.

    Błąd przekierowania:
    Za każdym razem, gdy wykonujesz program / polecenie na terminalu, 3 pliki są zawsze otwarte
    1. standardowe wejście
    2. standardowe wyjście
    3. Standardowy błąd.

    Pliki te są zawsze obecne przy każdym uruchomieniu programu. Jak wyjaśniono przed deskryptorem pliku, jest on powiązany z każdym z tych plików.
    Plik                                        Deskryptor pliku
    Standardowe wejście STDIN 0
    Standardowe wyjście STDOUT 1
    Standardowy błąd STDERR 2

  • Na przykład podczas wyszukiwania plików zwykle dostaje się błędy odmowy uprawnień lub inne błędy. Błędy te można zapisać w określonym pliku.
    Przykład 1

$ ls mydir 2> errorfile.txt

Deskryptorem pliku dla standardowego błędu jest 2.
Jeśli nie ma katalogu o nazwie mydir, dane wyjściowe polecenia zostaną zapisane w pliku errorfile.txt
Za pomocą „2>” przekierowujemy wyjście błędu do pliku o nazwie „errorfile”. txt "
W ten sposób wyniki programu nie są zaśmiecone błędami.

Mam nadzieję, że dostałeś swoją odpowiedź.


5

Każdy system operacyjny ma uruchomione procesy (p), powiedzmy p1, p2, p3 i tak dalej. Każdy proces zwykle stale wykorzystuje pliki.

Każdy proces składa się z drzewa procesów (lub tabeli procesów, w innym sformułowaniu).

Zwykle systemy operacyjne reprezentują każdy plik w każdym procesie przez liczbę (to znaczy w każdym drzewie / tabeli procesu).

Pierwszy plik użyty w tym procesie to plik0 , drugi to plik1 , trzeci to plik2 i tak dalej.

Każda taka liczba jest deskryptorem pliku.

Deskryptory plików są zwykle liczbami całkowitymi (0, 1, 2, a nie 0,5, 1,5, 2,5).

Biorąc pod uwagę, że często opisujemy procesy jako „tabele procesów”, a biorąc pod uwagę, że tabele zawierają wiersze (wpisy), możemy powiedzieć, że komórka deskryptora pliku w każdym wpisie używa do reprezentowania całego wpisu.

W podobny sposób po otwarciu gniazda sieciowego ma on deskryptor gniazda.

W niektórych systemach operacyjnych może zabraknąć deskryptorów plików, ale taki przypadek jest niezwykle rzadki i przeciętny użytkownik komputera nie powinien się tym martwić.

Deskryptory plików mogą być globalne (proces A rozpoczyna się w powiedz 0, a kończy powiedz w 1; Proces B zaczyna powiedz w 2, a kończy powie w 3) i tak dalej, ale o ile wiem, zwykle w nowoczesnych systemach operacyjnych plik deskryptory nie są globalne i faktycznie są specyficzne dla procesu (proces A rozpoczyna się w powiedz 0 i kończy powiedz w 5, podczas gdy proces B rozpoczyna się w 0 i kończy powiedz w 10).


Przeczytaj więcej na temat FD w Linuksie tutaj: unix.stackexchange.com/questions/358022/…

1
świetna odpowiedź :)
humble_wolf

5

Deskryptory plików

  • Do jądra wszystkie otwarte pliki są określane przez deskryptory plików.
  • Deskryptor pliku jest nieujemną liczbą całkowitą.
  • Kiedy otwieramy istniejący lub tworzymy nowy plik, jądro zwraca deskryptor pliku do procesu.
  • Kiedy chcemy czytać lub pisać na pliku, identyfikujemy plik za pomocą deskryptora pliku, który został ponownie przestrojony przez open lub create, jako argument do odczytu lub zapisu.
  • Każdy proces UNIX ma 20 deskryptorów plików i jest do dyspozycji, ponumerowany od 0 do 19, ale został rozszerzony do 63 przez wiele systemów.
  • Pierwsze trzy są już otwarte, gdy proces rozpoczyna się 0: Standardowe wejście 1: Standardowe wyjście 2: Standardowe wyjście błędu
  • Gdy proces nadrzędny rozwiąże proces, proces potomny dziedziczy deskryptory plików rodzica

1

Uzupełnienie przede wszystkim uproszczonych odpowiedzi.
Jeśli pracujesz z plikami w skrypcie bash, lepiej użyć deskryptora pliku.
Na przykład: -
Chcesz czytać i zapisywać z / do pliku „test.txt”.
Użyj deskryptora pliku, jak pokazano poniżej

FILE=$1 # give the name of file in the command line
exec 5<>$FILE # '5' here act as the file descriptor
# Reading from the file line by line using file descriptor
while read LINE; do
    echo "$LINE"
done <&5

# Writing to the file using descriptor
echo "Adding the date: `date`" >&5 
exec 5<&- # Closing a file descriptor

-5

Deskryptory plików to deskryptory pliku. Dają linki do pliku. Za ich pomocą możemy czytać, pisać i otwierać pliki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.