Что такое файловые дескрипторы, объясняемые простыми словами?

384
  1. Что может быть более упрощенным описанием файловых дескрипторов по сравнению с Википедией? Зачем они нужны? Скажем, возьмем процессы оболочки в качестве примера и как это применимо к нему?

  2. Содержит ли таблица процессов более одного дескриптора файла. Если да, то почему?

Nishant
источник
3
А как насчет концепции stdin stdout stderr и т. Д.? У меня есть экземпляр, например, сказать, что процесс браузера открыт, и он открыл некоторые временные файлы для отображения моего HTML. Процесс использует тот же FD для чтения / записи? Кроме того, таблица процессов ....... имеет записи, такие как указатель fd0 указатель fd1 указатель fd2 ..... означает ли это, что все эти файлы находятся в оперативной памяти? Почему еще указатели?
Nishant
43
Когда вы открываете файл, ОС создает поток для этого файла и подключает этот поток к открытому файлу, дескриптор фактически представляет этот поток. Точно так же есть некоторые потоки по умолчанию, созданные ОС. Эти потоки подключены к вашему терминалу, а не к файлам. Поэтому, когда вы пишете что-то в терминале, оно идет в поток stdin и ОС. И когда вы пишете команду «ls» на терминале, ОС записывает вывод в поток stdout. Поток stdout подключен к терминалу вашего монитора, поэтому вы можете видеть выходной сигнал.
Тайяб
1
Что касается примера браузера, необязательно, чтобы браузер сохранял файлы открытыми. Это зависит от реализации браузера, но в большинстве случаев браузер открывает временный файл, записывает файл и закрывает файл, поэтому нет необходимости открывать файл, даже если веб-страница открыта. А дескриптор просто хранит информацию о файле и не обязательно хранит файл в оперативной памяти. Когда вы читаете данные из дескриптора, ОС считывает данные с жесткого диска. Информация в дескрипторе файла просто представляет местоположение файла на жестком диске и т.д ..
Tayyab
5
Файловый дескриптор для файла не является однозначным отображением. Я мог открыть () один и тот же файл 4 раза и получить 4 разных файловых дескриптора. Каждый из которых может быть использован (в зависимости от флагов, передаваемых open ()) для чтения, записи или для того и другого. Насколько файл находится в оперативной памяти или на диске - это скрыто от вас ядром и его различными кешами. В конечном итоге, что такое кеш, будет соответствовать тому, что находится на диске (для записи), и ядро ​​не вернется на диск для чтения, если данные уже находятся в кеше.
Beano
7
Это хорошая статья, чтобы понять это легко bottomupcs.com/file_descriptors.xhtml
Кришан Гопал

Ответы:

562

Проще говоря, когда вы открываете файл, операционная система создает запись для представления этого файла и сохранения информации об этом открытом файле. Таким образом, если в вашей ОС открыто 100 файлов, то в ОС будет 100 записей (где-то в ядре). Эти записи представлены целыми числами, такими как (... 100, 101, 102 ....). Этот номер записи является дескриптором файла. Так что это просто целое число, которое уникально представляет открытый файл в операционной системе. Если ваш процесс открывает 10 файлов, то ваша таблица процессов будет иметь 10 записей для файловых дескрипторов.

Аналогично, когда вы открываете сетевой сокет, он также представляется целым числом и называется дескриптором сокета. Я надеюсь, вы понимаете.

Tayyab
источник
8
Кроме того, именно поэтому вы можете исчерпать файловые дескрипторы, если открываете много файлов одновременно. Что помешает запуску систем * nix, так как они постоянно открывают дескрипторы для заполнения /proc.
Спенсер Рэтбун
8
@ErbenMo: Нет, это не может быть так же. Когда вы открываете файл, операционная система назначает доступный FD, а когда вы закрываете его, ОС освобождает FD и может назначить этот FD другому файлу, открытому после этого. Операционная система отслеживает открытые файлы и не имеет ничего общего с конкретным файлом.
Тайяб
49
« Так что это просто целое число, которое уникально представляет открытый файл в операционной системе. » Это неверно. Это целое число уникально представляет открытый файл в процессе . Например, дескриптор файла 0 будет представлять один открытый файл в одном процессе и совершенно другой открытый файл в другом процессе.
Кит Томпсон
15
@Tayyab: я считаю, что вы ошибаетесь. Файловые дескрипторы 0, 1 и 2 являются стандартным вводом, стандартным выводом и стандартной ошибкой для каждого запущенного процесса. Успешный начальный вызов open()даст вам файловый дескриптор 3, даже если другой запущенный процесс имеет файловый дескриптор 3. См. Определение POSIXopen() : «Функция open () должна вернуть файловый дескриптор для именованного файла, который является самым низким дескриптор файла в данный момент не открыт для этого процесса . " (выделение добавлено).
Кит Томпсон
17
@KeithThompson: Да, вы правы. На самом деле это об уровне абстракции. На самом деле поддерживаются две таблицы, первая из которых предназначена для каждого процесса, а вторая - для всей системы. FD в таблице процессов (т. Е. Fdtable) не является уникальной для всей системы. Однако он сопоставляется с таблицей v-узлов, которая содержит уникальные записи всей системы. Таким образом, когда вы вызываете функции fopen () и fileno () для проверки дескриптора, вы можете получить одно и то же число FD в 2 разных процессах, потому что он возвращает индекс fdtable для каждого процесса. Спасибо, что подняли это!
Тайяб
116

Файловый дескриптор - это непрозрачный дескриптор, который используется в интерфейсе между пользователем и пространством ядра для идентификации файловых / сокетных ресурсов. Следовательно, когда вы используете open()или socket()(системные вызовы для взаимодействия с ядром), вы получаете файловый дескриптор, который является целым числом (на самом деле это индекс в структуре процессов, но это не важно). Поэтому, если вы хотите , чтобы непосредственно взаимодействовать с ядром, используя системные вызовы read(), write(), и close()т.д. ручка вы используете файловый дескриптор.

На системные вызовы накладывается слой абстракции, который является stdioинтерфейсом. Это обеспечивает больше функциональности / возможностей, чем базовые системные вызовы. Для этого интерфейса непрозрачный дескриптор, который вы получаете - это FILE*, который возвращается fopen()вызовом. Есть много много функций , которые используют stdioинтерфейс fprintf(), fscanf(), fclose(), которые находятся там , чтобы сделать вашу жизнь проще. В C stdin, stdoutи stderrесть FILE*, что в UNIX соответственно карту для дескрипторов файлов 0, 1и 2.

гулянка
источник
6
Я лично считаю, что этот ответ лучше, чем тот, который помечен как ответ. Upvoted.
Тарик
101

Услышь это изо рта лошади: APUE (Ричард Стивенс).
В ядре все открытые файлы называются дескрипторами файлов. Файловый дескриптор является неотрицательным числом.

Когда мы открываем существующий файл или создаем новый файл, ядро ​​возвращает файловый дескриптор процессу. Ядро поддерживает таблицу всех открытых дескрипторов файлов, которые используются. Распределение файловых дескрипторов, как правило, является последовательным, и они выделяются для файла в качестве следующего свободного файлового дескриптора из пула бесплатных файловых дескрипторов. Когда мы закрываем файл, дескриптор файла освобождается и доступен для дальнейшего выделения.
Смотрите это изображение для более подробной информации:

Два процесса

Когда мы хотим прочитать или записать файл, мы отождествляем файл с дескриптором файла, который был возвращен вызовом функции open () или create () , и используем его в качестве аргумента для read () или write () .
По соглашению системные оболочки UNIX связывают дескриптор файла 0 со стандартным вводом процесса, дескриптор файла 1 со стандартным выводом и дескриптор файла 2 со стандартной ошибкой .
Дескриптор файла варьируется от 0 до OPEN_MAX. Максимальное значение дескриптора файла можно получить с помощью ulimit -n. Для получения дополнительной информации просмотрите 3-ю главу книги APUE.

Шехар кумар
источник
1
Поскольку 0, 1, 2 связаны с «stdin», «stdout» и «stderr» процесса, можем ли мы использовать эти дескрипторы одновременно для разных процессов?
Тарик
@Tarik: файловые дескрипторы для каждого процесса. Чтобы увидеть это, загрузите osquery и выполните osqueryi <<< echo '.all process_open_files'в оболочке bash.
Бен
29

Другие ответы добавили отличные вещи. Я добавлю только мои 2 цента.

Согласно Википедии мы точно знаем: дескриптор файла является неотрицательным целым числом. Самая важная вещь, которую я считаю отсутствующей, это сказать:

Файловые дескрипторы привязаны к идентификатору процесса.

Мы знаем, что наиболее известные файловые дескрипторы - это 0, 1 и 2. 0 соответствует STDIN, 1 к STDOUTи 2 к STDERR.

Скажем, возьмем процессы оболочки в качестве примера и как это применимо к нему?

Проверьте этот код

#>sleep 1000 &
[12] 14726

Мы создали процесс с идентификатором 14726 (PID). Используя lsof -p 14726мы можем получить такие вещи:

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

Четвертый столбец FD и следующий столбец TYPE соответствуют дескриптору файла и типу дескриптора файла.

Некоторые значения для FD могут быть:

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

Но настоящий дескриптор файла находится под:

NUMBER – Represent the actual file descriptor. 

Символ после числа, т.е. «1u», представляет режим, в котором файл открывается. r для чтения, w для записи, u для чтения и записи.

TYPE указывает тип файла. Некоторые из значений типов:

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

Но все файловые дескрипторы являются CHR - символьный специальный файл (или файл символьного устройства)

Теперь мы можем определить дескрипторы файлов для STDIN, STDOUTи STDERRлегко с lsof -p PID, или мы можем увидеть то же самое , если мы ls /proc/PID/fd.

Также обратите внимание, что таблица файловых дескрипторов, которую отслеживает ядро, отличается от таблицы файлов или таблицы inode. Это отдельные, как объяснили некоторые другие ответы.

таблица ФД

Вы можете спросить себя, где эти файловые дескрипторы физически и что хранится, /dev/pts/6например, в

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

Ну, /dev/pts/6живет чисто в памяти. Это не обычные файлы, а так называемые файлы символьных устройств . Вы можете проверить это с помощью: ls -l /dev/pts/6и они начнутся с c, в моем случае crw--w----.

Напомним, что большинство Linux-подобных ОС определяют семь типов файлов:

  • Обычные файлы
  • Справочники
  • Файлы символьных устройств
  • Блокировать файлы устройства
  • Локальные доменные сокеты
  • Именованные трубы (FIFO) и
  • Символьные ссылки
прости
источник
1
Спасибо. Действительно важно отметить, что это на процесс! Это помогает лучше визуализировать вещи.
Nishant
1
Типы файлов, определенные ОС, которые вы упомянули в своем ответе, действительно помогают понять файлы на более низком уровне.
Рохан
20

Больше очков относительно File Descriptor:

  1. File Descriptors(FD) - неотрицательные целые числа (0, 1, 2, ...), связанные с открытыми файлами.

  2. 0, 1, 2стандартны FD «S , что соответствует STDIN_FILENO, STDOUT_FILENOи STDERR_FILENO(определены в unistd.h) открывается по умолчанию от имени оболочки при запуске программы.

  3. FD распределяются в последовательном порядке, что означает наименьшее возможное нераспределенное целочисленное значение.

  4. FD для конкретного процесса можно увидеть в /proc/$pid/fd(на системах на основе Unix).

Sandeep_black
источник
16

В дополнение к другим ответам, Unix рассматривает все как файловую систему. Ваша клавиатура - это файл, который читается только с точки зрения ядра. Экран - это файл только для записи. Аналогично, папки, устройства ввода-вывода и т. Д. Также считаются файлами. Когда файл открывается, скажем, когда драйверы устройств [для файлов устройств] запрашивают open (), или процесс открывает пользовательский файл, ядро ​​выделяет дескриптор файла, целое число, которое определяет доступ к этому файлу, так что он доступен только для чтения. , пишите только и т. д. [для справки: https://en.wikipedia.org/wiki/Everything_is_a_file ]

Балу
источник
Файловые дескрипторы могут также ссылаться на вещи, которые не существуют в файловой системе, такие как анонимные каналы и сетевые сокеты.
Кболино
12

Файловые дескрипторы (FD):

  • В Linux / Unix все является файлом. Обычный файл, каталоги и даже устройства являются файлами. Каждый файл имеет связанный номер, называемый дескриптором файла (FD).
  • Ваш экран также имеет дескриптор файла. Когда программа выполняется, вывод отправляется в дескриптор файла на экране, и вы видите вывод программы на вашем мониторе. Если выходные данные отправляются в дескриптор файла принтера, выходные данные программы будут напечатаны.

    Перенаправление ошибок:
    каждом запуске программы / команды в терминале всегда открыто 3 файла.
    1. стандартный ввод
    2. стандартный вывод
    3. стандартная ошибка.

    Эти файлы всегда присутствуют при запуске программы. Как объяснено ранее файловый дескриптор, связан с каждым из этих файлов.
    Файл                                        Дескриптор файла
    Стандартный вход STDIN 0
    Стандартный выход STDOUT 1
    Стандартная ошибка STDERR 2

  • Например, при поиске файлов обычно получаются ошибки, в которых отказано в разрешении, или какие-либо другие ошибки. Эти ошибки могут быть сохранены в конкретном файле.
    Пример 1

$ ls mydir 2> errorsfile.txt

Дескриптор файла для стандартной ошибки: 2.
Если нет каталога с именем mydir, выходные данные команды будут сохранены в файл errorfile.txt.
Используя «2>», мы перенаправим вывод ошибок в файл с именем «errorfile». txt "
Таким образом, вывод программы не загроможден ошибками.

Я надеюсь, что вы получили свой ответ.

Абхишек Камаль
источник
5

В любой операционной системе запущены процессы (p), скажем, p1, p2, p3 и так далее. Каждый процесс обычно постоянно использует файлы.

Каждый процесс состоит из дерева процессов (или таблицы процессов, в другом выражении).

Как правило, операционные системы представляют собой каждый файл в каждом процессе по к числу (то есть, в каждом процессе дерева / таблицы).

Первый файл, используемый в процессе, это файл0 , второй - файл1 , третий - файл2 и так далее.

Любое такое число является дескриптором файла.

Файловые дескрипторы обычно являются целыми числами (0, 1, 2, а не 0,5, 1,5, 2,5).

Поскольку мы часто описываем процессы как «таблицы процессов», и учитывая, что в таблицах есть строки (записи), мы можем сказать, что ячейка дескриптора файла в каждой записи использует для представления всей записи.

Аналогичным образом, когда вы открываете сетевой сокет, он имеет дескриптор сокета.

В некоторых операционных системах вы можете исчерпать файловые дескрипторы, но такой случай крайне редок, и обычному пользователю компьютера не стоит беспокоиться об этом.

Файловые дескрипторы могут быть глобальными (процесс A начинается, скажем, с 0, а заканчивается, скажем, с 1; процесс B начинается с, скажем, 2, а заканчивается, скажем, с 3) и т. Д., Но, насколько я знаю, обычно в современных операционных системах файл дескрипторы не являются глобальными и фактически зависят от процесса (процесс A начинается, скажем, с 0 и заканчивается, скажем, с 5, а процесс B начинается с 0 и заканчивается, например, с 10).


источник
Подробнее о ФЗ в Linux здесь: unix.stackexchange.com/questions/358022/...
1
отличный ответ :)
humble_wolf
5

Файловые дескрипторы

  • В ядре все открытые файлы называются файловыми дескрипторами.
  • Файловый дескриптор является неотрицательным целым числом.
  • Когда мы открываем существующий или создаем новый файл, ядро ​​возвращает файловый дескриптор процессу.
  • Когда мы хотим прочитать или записать файл, мы идентифицируем файл с дескриптором файла, который был перенастроен open или create, в качестве аргумента для чтения или записи.
  • Каждый процесс UNIX имеет 20 файловых дескрипторов и может быть удален от 0 до 19, но во многих системах он был расширен до 63.
  • Первые три уже открыты, когда начинается процесс 0: Стандартный ввод 1: Стандартный вывод 2: Стандартный вывод ошибок
  • Когда родительский процесс разветвляется, дочерний процесс наследует файловые дескрипторы родительского процесса.
Махендра Сутар
источник
1

Помимо всего прочего упрощенные ответы.
Если вы работаете с файлами в bash-скрипте, лучше использовать файловый дескриптор.
Например: -
Вы хотите читать и писать из / в файл «test.txt».
Используйте дескриптор файла, как показано ниже

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
sumitsinghdeode
источник
-5

Файловые дескрипторы являются дескрипторами файла. Они дают ссылки на файл. С их помощью мы можем читать, писать и открывать файл.

Motimahal
источник