Есть ли обычная причина использовать open() вместо fopen()?

StackOverflow https://stackoverflow.com/questions/544662

  •  23-08-2019
  •  | 
  •  

Вопрос

Я делаю небольшой проект на C после довольно долгого перерыва.Они включают в себя некоторую обработку файлов.В различной документации я заметил, что есть функции, которые возвращают FILE * дескрипторы и другие, которые возвращают дескрипторы (маленькое целое число).Оба набора функций предлагают одни и те же базовые услуги, которые мне нужны, поэтому не имеет значения, чем я пользуюсь.

Но мне любопытна мудрость коллекции:лучше ли использовать fopen() и друзья, или open() и друзья?

Редактировать Поскольку кто-то упомянул буферизованные и небуферизованные устройства и доступ к устройствам, я должен добавить, что одна часть этого небольшого проекта будет писать драйвер файловой системы пользовательского пространства под FUSE.Таким образом, доступ на уровне файла может быть легко реализован на устройстве (например,компакт-диск или дисковод SCSI), как в «файле» (т.е.изображение).

Это было полезно?

Решение

Возражение, что «fopen» является переносимым, а «open» — нет, является фиктивным.

fopen — часть libc, open — системный вызов POSIX.

Каждый из них так же портативен, как и место, откуда он родом.

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

Какой смысл открывать, например, узел устройства, например, /dev/sg0 или /dev/tty0...Чем ты планируешь заняться?Вы собираетесь выполнить ioctl для ФАЙЛА*?Удачи с этим.

Возможно, вы хотите открыть его с помощью некоторых флагов, таких как O_DIRECT — использование fopen() не имеет смысла.

Другие советы

Лучше использовать open(), если вы придерживаетесь unix-подобных систем и вам может потребоваться:

  • Получите более детальный контроль над битами разрешений Unix при создании файлов.
  • Используйте функции более низкого уровня, такие как чтение/запись/mmap, в отличие от функций ввода-вывода буферизованного потока C.
  • Используйте планирование ввода-вывода на основе файлового дескриптора (fd) (опрос, выбор и т. д.). Конечно, вы можете получить fd из FILE * с помощью fileno(), но необходимо соблюдать осторожность, чтобы не смешивать потоковые функции на основе FILE * с функциями на основе fd. .
  • Откройте любое специальное устройство (не обычный файл)

Для максимальной переносимости лучше использовать fopen/fread/fwrite, поскольку это стандартные функции C, а функции, упомянутые выше, таковыми не являются.

fopen работает на более высоком уровне, чем open....fopen возвращает указатель на поток FILE, который похож на абстракцию потока, которую вы читаете в C++.

open возвращает файловый дескриптор открытого файла...Он не предоставляет вам абстракцию потока, и вы сами несете ответственность за обработку битов и байтов...Это более низкий уровень по сравнению с fopen.

Потоки Stdio буферизуются, а файловые дескрипторы open() — нет.Зависит от того, что вам нужно.Вы также можете создать одно из другого:

int fileno (FILE * поток) возвращает файловый дескриптор для FILE *, FILE * fdopen(int fildes, const char * mode) создает FILE * из файлового дескриптора.

Будьте осторожны при смешивании буферизованного и небуферизованного ввода-вывода, поскольку вы потеряете содержимое буфера, если не очистите его с помощью fflush().

Да.Когда вам нужен дескриптор низкого уровня.

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

Кроме того, низкоуровневые дескрипторы обеспечивают лучшую совместимость с ABI, чем указатели FILE.

обычно вам следует использовать стандартную библиотеку (fopen).Однако бывают случаи, когда вам придется использовать open напрямую.

Один из примеров, который приходит на ум, — это обход ошибки в старой версии Solaris, из-за которой fopen завершался сбоем после открытия 256 файлов.Это произошло потому, что они ошибочно использовали беззнаковый символ для поля fd в своей реализации структуры FILE вместо int.Но это был очень специфический случай.

читать() & писать() используйте небуферизованный ввод-вывод.(ФД:целочисленный дескриптор файла)

читать() & fwrite() используйте буферизованный ввод-вывод.(ФАЙЛ* указатель структуры)

Двоичные данные, записываемые в канал с помощью писать() может нет уметь читать двоичные данные с помощью читать(), из-за выравнивания байтов, размеров переменных и т. д.Это дерьмовая стрельба.

В большинстве низкоуровневых кодов драйверов устройств используются небуферизованные вызовы ввода-вывода.

Большинство операций ввода-вывода уровня приложения используют буферизацию.

Использование ФАЙЛ* и связанные с ним функции в порядке на машине:Но переносимость теряется на других архитектурах при чтении и написании бинарных данных.FWRITE () - буферизованный ввод -вывод и может привести к ненадежным результатам, если написано для 64 -битной архитектуры, и запустить 32 -битную;или (Windows/Linux).Большинство ОС имеют макросы совместимости в собственном коде, чтобы предотвратить это.

Для низкоуровневой переносимости двоичного ввода-вывода читать() и писать() Гарантируйте те же бинарные чтения и записывает при составлении в различных архитектурах.Основная вещь - выбрать так или иной путь и быть последовательным в этом, по всему двоичному набору.

<stdio.h>  // mostly FILE*  some fd input/output parameters for compatibility
             // gives you a lot of helper functions -->
List of Functions
       Function      Description
       ───────────────────────────────────────────────────────────────────
       clearerr      check and reset stream status
       fclose        close a stream
       fdopen        stream open functions //( fd argument, returns FILE*)                      feof          check and reset stream status
       ferror        check and reset stream status
       fflush        flush a stream
       fgetc         get next character or word from input stream
       fgetpos       reposition a stream
       fgets         get a line from a stream
       fileno        get file descriptor   // (FILE* argument, returns fd) 
       fopen         stream open functions
       fprintf       formatted output conversion
       fpurge        flush a stream
       fputc         output a character or word to a stream
       fputs         output a line to a stream
       fread         binary stream input/output
       freopen       stream open functions
       fscanf        input format conversion
       fseek         reposition a stream
       fsetpos       reposition a stream
       ftell         reposition a stream
       fwrite        binary stream input/output
       getc          get next character or word from input stream
       getchar       get next character or word from input stream
       gets          get a line from a stream
       getw          get next character or word from input stream
       mktemp        make temporary filename (unique)
       perror        system error messages
       printf        formatted output conversion
       putc          output a character or word to a stream
       putchar       output a character or word to a stream
       puts          output a line to a stream
       putw          output a character or word to a stream
       remove        remove directory entry
       rewind        reposition a stream
       scanf         input format conversion
       setbuf        stream buffering operations
       setbuffer     stream buffering operations
       setlinebuf    stream buffering operations
       setvbuf       stream buffering operations
       sprintf       formatted output conversion
       sscanf        input format conversion
       strerror      system error messages
       sys_errlist   system error messages
       sys_nerr      system error messages
       tempnam       temporary file routines
       tmpfile       temporary file routines
       tmpnam        temporary file routines
       ungetc        un-get character from input stream
       vfprintf      formatted output conversion
       vfscanf       input format conversion
       vprintf       formatted output conversion
       vscanf        input format conversion
       vsprintf      formatted output conversion
       vsscanf       input format conversion

Поэтому для базового использования я бы лично использовал вышеизложенное, не слишком смешивая идиомы.

Напротив,

<unistd.h>   write()
             lseek()
             close()
             pipe()
<sys/types.h>
<sys/stat.h>
<fcntl.h>  open()
           creat()
           fcntl() 
all use file descriptors.

Они обеспечивают мелкозернистый контроль над чтением и письменными байтами (рекомендуется для специальных устройств и FIFO (трубы)).

Итак, еще раз: используйте то, что вам нужно, но сохраняйте последовательность в своих идиомах и интерфейсах.Если большая часть вашей кодовой базы использует один режим, используйте это тоже, если нет реальной причины не делать этого.Оба набора функций библиотеки ввода/вывода чрезвычайно надежны и используются миллионы раз в день.

примечание-- Если вы взаимодействуете CI/O с другим языком (Perl, Python, Java, C#, Lua ...) проверить То, что разработчики этих языков рекомендуют, прежде чем написать свой код C и сохранить себе некоторые проблемы.

fopen и его родственники буферизуются.открытие, чтение и запись не буферизуются.Ваше приложение может волноваться, а может и не волноваться.

fprintf и scanf имеют более богатый API, который позволяет читать и записывать форматированные текстовые файлы.чтение и запись используют фундаментальные массивы байтов.Преобразования и форматирование должны выполняться вручную.

Разница между файловыми дескрипторами и (FILE *) на самом деле несущественна.

Рэнди

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top