Чому в системах Unix нам доводиться чітко `відкривати ()` і `закривати ()` файли, щоб мати можливість їх читати () або писати ()?


50

Чому open()і close()існує в розробці файлової системи Unix?

Не могла ОС просто вперше виявити read()або write()подзвонила і зробила б все, open()що зазвичай робилося?


22
Варто зазначити, що ця модель не є частиною файлової системи, а скоріше Unix API . Файлова система стосується лише того, куди на диску надходять байти і куди слід поставити ім'я файлу тощо. Цілком можливо було б мати альтернативну модель, яку ви описуєте, поверх файлової системи Unix, наприклад UFS або ext4, було б до ядро для перекладу цих викликів у належні оновлення для файлової системи (так само, як зараз).
marcelm

18
Як висловлюватись, я думаю, що це більше про те, чому open()існує. "Чи не могла ОС просто виявити перший раз читання () або запис () і зробити все, що відкрито (), як правило, робити?" Чи є відповідна пропозиція щодо того, коли буде закриття ?
Джошуа Тейлор

7
Як би ви сказали read()або до write()якого файлу отримати доступ? Імовірно, пройшовши шлях. Що робити, якщо шлях до файлу змінюється під час доступу до нього (між двома read()або write()викликами)?
користувач253751

2
Крім того, ви зазвичай не здійснюєте контроль доступу, read()а write()просто open().
Павло Шімерда,

6
@Johnny: Ви, можливо, забуваєте, наскільки обмежене обладнання було в ті часи. PDP-7, на якому вперше було впроваджено Unix, максимум 64 Кб оперативної пам’яті та тактова частота 0,333 МГц - набагато менше, ніж простий мікроконтролер в ці дні. Таке збирання сміття або використання системного коду для контролю доступу до файлів призвело б до того, що система поставить на коліна.
jamesqf

Відповіді:


60

Денніс Рітчі згадує в «Еволюції Unix час обміну системи» , що openі closeразом з read, writeі creatприсутні в правій системі з самого початку.

Я думаю, що система без openі closeне була б немислимою, проте я вважаю, що це ускладнить дизайн. Як правило, ви хочете робити кілька дзвінків для читання і запису, а не лише один, і це, мабуть, особливо стосується старих комп'ютерів з обмеженою оперативною пам’яттю, на якій створено UNIX. Маючи ручку, яка підтримує поточну позицію файлу, це спрощує це. Якщо readабоwriteщоб повернути ручку, вони повинні були б повернути пару - ручку та власний статус повернення. Частка ручки пари була б марною для всіх інших дзвінків, що зробило б цю домовленість незручною. Залишаючи стан курсору до ядра, дозволяє йому підвищити ефективність не лише буферизацією. Існує також деяка вартість, пов’язана з пошуком шляху - наявність ручки дозволяє сплатити її лише один раз. Крім того, деякі файли в світогляді UNIX навіть не мають шляху до файлової системи (або ні - зараз вони роблять такі речі /proc/self/fd).


7
Вартість пошуку шляху та перевірки дозволів тощо тощо дуже велика. Якщо ви хотіли зробити систему без open/ close, ви впевнені в застосуванні таких матеріалів, як /dev/stdoutдозволити трубопроводи.
Пітер Кордес

5
Я думаю, що ще один аспект цього полягає в тому, що ви можете зберігати цю ручку в одному файлі, використовуючи кілька читання, коли ви тримаєте файл відкритим. В іншому випадку у вас можуть бути випадки, коли інший процес від’єднує і відновлює файл з тим самим іменем, і читання файлу в шматках може бути абсолютно непослідовним. (Дещо з цього може залежати і від файлової системи.)
Бруно,

2
Я розробив його без закриття (); Ви передаєте номер inode та зсув для читання () та write (). Я не можу без open () дуже легко, тому що саме там живе роздільна здатність імен.
Джошуа

3
@Joshua: Така система має принципово різну семантику, тому що дескриптори файлів unix не посилаються на файли (inode), а на відкриті описи файлів , яких може бути багато для даного файлу (inode).
R ..

@Joshua, ви просто перейменували open()в get_inode()і зробив всю систему більш жорсткою (неможливо читати / писати один і той же файл в декількох позиціях одночасно).
vonbrand

53

Тоді всі readта writeдзвінки повинні передавати цю інформацію про кожну операцію:

  • назва файлу
  • дозволи файлу
  • додає або створює абонент
  • Чи абонент зробити роботу з файлом (відкидати невикористані для читання буферів і забезпечення запису-буферів дійсно закінчили писати)

Чи вважаєте ви незалежні виклики open , read, writeі closeбути простіше , ніж одноцелевой I / O повідомлення засноване на вашій філософії дизайну. Розробники Unix вирішили використовувати прості операції та програми, які можна поєднувати багатьма способами, а не одну операцію (або програму), яка все робить.


Абоненти також у більшості випадків повинні вказати бажане зміщення у файлі. Є деякі ситуації (наприклад, протокол UDP, який дозволяє отримати доступ до даних), коли наявність кожного запиту незалежно ідентифікувати файл і зміщення може бути корисним, оскільки це виключає необхідність підтримки сервера у стані, але в цілому зручніше мати сервер слідкуйте за файлом. Далі, як зазначалося в іншому місці, код, який збирається записати файли, часто потребує попереднього їх блокування та блокування після цього; розчісувати ці операції з відкритими / закритими дуже зручно.
supercat

5
"Файл" може не мати імені або дозволів в першу чергу; readі writeне обмежуються файлами, які живуть у файловій системі, і це є основним дизайнерським рішенням в Unix, як пояснює pjc50.
reinierpost

1
Також там, де у файлі для читання / запису - початок, кінець або довільне положення (як правило, одразу після закінчення останнього читання / запису) - ядро ​​відстежує це для вас (з режимом до спрямовуйте всі записи до кінця файлу, інакше файли відкриваються з позицією на початку та lseek
розширюються

51

Концепція обробки файлів важлива через вибір дизайну UNIX, що "все - це файл", включаючи речі, які не входять до файлової системи. Такі, як стрічкові накопичувачі, клавіатура та екран (або телетип!), Зчитувачі перфокарт / стрічок, послідовне з'єднання, мережеві з'єднання та (ключовий винахід UNIX), прямі підключення до інших програм, що називаються "трубами".

Якщо ви подивіться на багато з простого стандартного UNIX утиліта типу grep, особливо в їх оригінальній версії, ви помітите , що вони не включають в себе виклики до open()і , close()але тільки readі write. Ручки файлів встановлюються поза програмою оболонкою і передаються при її запуску. Таким чином, програмі не потрібно байдуже, записує вона у файл чи іншу програму.

А також open, інші способи отримання файлів дескриптори socket, listen, pipe, dup, і дуже Heath Robinson механізм для передачі дескрипторів файлів через трубу: https://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux -розетка

Редагувати: кілька конспектів лекцій, що описують шари непрямості та як це дозволяє O_APPEND розумно працювати. Зауважте, що збереження даних inode у пам’яті гарантує, що системі не доведеться знову перебирати їх і отримувати їх для наступної операції запису.


1
Крім того creat, і listenне створює fd, але коли (і якщо) запит надходить під час прослуховування, acceptстворює та повертає fd для нового (підключеного) сокета.
dave_thompson_085

18
Це правильна відповідь. Знаменитий (невеликий) набір операцій над дескрипторами файлів - це об'єднує API для всіх видів ресурсів, які виробляють або споживають дані. Ця концепція ГОЛОВНО успішна. У рядку може бути синтаксис, що визначає тип ресурсу разом з фактичним місцеположенням (URL-адреса хтось?), Але копіювати рядки, навколо яких займає кілька відсотків доступної оперативної пам’яті (що це було за PDP 7? 16 кБ?), Здається надмірним .
Пітер - Відновити Моніку

Можливо, це було б, якби дзвінки низького рівня та оболонка були розроблені одночасно. Але він pipeбув представлений через кілька років після початку розробки Unix.
Томас Дікі

1
@Thomas Dickey: Це просто показує, наскільки хорошим був оригінальний дизайн, оскільки він дозволив просте розширення на труби & c :-)
jamesqf

Але слідуючи цьому аргументу, ця відповідь не дає нічого нового.
Томас Дікі

10

Відповідь "ні", тому що open () і close () створюють і знищують ручку відповідно. Бувають випадки (ну, весь час, справді), коли ви можете гарантувати, що ви єдиний, хто телефонує з певним рівнем доступу, оскільки інший абонент (наприклад) записує файл, який ви несподівано розбираєте, може залишити додаток у невідомому стані або призведе до виникнення аварійних ситуацій або тупику, наприклад, лема «Філософи їдалень».

Навіть без цього врахування є наслідки для продуктивності, які слід враховувати; close () дозволяє файловій системі (якщо вона підходить або якщо ви її закликали) промивати буфер, який ви займали, дорога операція. Кілька послідовних редагувань потоку пам’яті набагато ефективніше, ніж декілька по суті непов’язаних циклів читання-зміни-модифікації у файловій системі, яка, наскільки ви знаєте, існує півсвіту, розкидана по центру обробки даних, який вартує великого затримки масового зберігання. Навіть при локальному зберіганні пам'ять, як правило, на багато порядків швидше, ніж об'ємне зберігання.


7

Open () пропонує спосіб блокувати файли під час їх використання. Якщо файли автоматично відкриваються, читаються / записуються, а потім знову закриваються ОС, то ніщо не зупинить інші програми, що змінюють ці файли між операціями.

Хоча це може бути керованим (багато систем підтримують неексклюзивний доступ до файлів) для простоти, більшість програм припускають, що відкриті ними файли не змінюються.


5

Оскільки шлях до файлу може рухатися, якщо ви припускаєте, що він залишиться колишнім.


4

Читання та запис у файлову систему може включати велику різноманітність буферних схем, ведення ОС, управління дисками низького рівня та безліч інших можливих дій. Тож дії open()та close()служать настановою для цих видів діяльності під капотом. Різні реалізації файлової системи можуть бути впорядковані за потреби та залишатися прозорими для викликової програми.

Якщо в операційній системі не було відкрито / закрити, тоді з readабо write, ці дії з файлом все одно повинні були б кожен раз виконувати ініціалізації, промивання буфера / управління тощо. Це багато накладних витрат, які потрібно накладати на повторювані читання та записи.


Не забувайте, що open () і close () також зберігає позицію у файлі (для наступного читання чи наступного запису). Отже, наприкінці або read () і write () знадобиться структура для обробки всіх параметрів, або потрібні аргументи для кожного параметра. Створення структури еквівалентно (програмістському сайту) відкритому, тому якщо ОС також знає про відкритий, у нас є лише більше переваг.
Джакомо Катенацці

1

Мантра Unix - це "запропонувати один із способів робити речі", що означає "розподілити фактори" на (багаторазові) частини, які потрібно комбінувати за бажанням. Тобто в цьому випадку відокремлюють створення та знищення ручок файлів від їх використання. Важливі переваги прийшли пізніше, з трубами та мережевими з'єднаннями (ними також маніпулюють через файлові ручки, але вони створюються іншими способами). Можливість передавати ручки файлів навколо (наприклад, передавати їх дочірнім процесам як "відкриті файли", які виживають exec(2), і навіть не пов'язані між собою процеси через трубу) можливі лише таким чином. Особливо, якщо ви хочете запропонувати контрольований доступ до захищеного файлу. Таким чином, ви можете, наприклад, відкрити/etc/passwd для написання і передайте це дочірньому процесу, якому заборонено відкривати цей файл для запису (так, я знаю, це смішний приклад, сміливо редагуйте чимось більш реалістичним).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.