Existe alguma razão comum para usar open () em vez de fopen ()?
Pergunta
Eu estou fazendo um pequeno projeto em C depois de muito tempo longe dele. Estes acontecem para incluir alguns manipulação de arquivos. Eu observei em vários documentos que existem funções que retornam alças FILE *
e outros que retornam (pequeno inteiro) descritores. Ambos os conjuntos de funções de oferecer os mesmos serviços básicos que eu preciso para que ele realmente não importa que eu uso.
Mas estou curioso sobre a sabedoria coleção: é melhor usar fopen()
e amigos, ou open()
e amigos
Editar Desde Alguém mencionou tamponada vs dispositivos sem buffer e acessar, devo acrescentar que uma parte deste pequeno projeto vai escrever um driver userspace arquivos no FUSE. Assim, o nível de acesso de arquivo poderia facilmente estar em um dispositivo (por exemplo, um CD-ROM ou uma unidade SCSI) como em um "arquivo" (ou seja, uma imagem).
Solução
A objeção de que "fopen" é portátil e "aberto" não é é falso.
fopen faz parte do libc, aberto é uma chamada de sistema POSIX.
Cada um é tão portátil como o lugar de onde vêm.
E / S para arquivos fopen'ed é (você deve assumir que seja, e para efeitos práticos, é) tamponada por libc, arquivo descritores open () 'ed não são tamponados por libc (que pode muito bem ser, e normalmente são colocados no sistema de arquivos -., mas não tudo o que abrir () é um arquivo em um sistema de arquivos
O que é o ponto de fopen'ing, por exemplo, um nó de dispositivo como / dev / sg0, digamos, ou / dev / tty0 ... O que você vai fazer? Você vai fazer um ioctl em um arquivo *? Boa sorte com isso.
Talvez você deseja abrir com algumas bandeiras como O_DIRECT - não faz sentido com fopen ()
.Outras dicas
É melhor usar open () se você está aderindo a sistemas Unix-like e que você pode gostar:
- ter mais controle de grão fino sobre bits de permissão unix na criação do arquivo.
- Use as funções de nível mais baixo, tais como leitura / escrita / mmap em oposição à C tamponada de fluxo de I / O funções.
- Use descritor de arquivo (fd) agendamento com base IO (pesquisa, selecionar, etc.) Você pode obter de curso de um fd de um FILE * usando fileno (), mas é preciso ter cuidado para não misturar FILE * funções de fluxo com base com fd funções baseadas.
- Abra qualquer dispositivo especial (não um arquivo regular)
É melhor usar fopen / fread / fwrite para máxima portabilidade, uma vez que estas são funções C padrão, as funções que eu mencionei acima não são.
obras fopen a um nível mais elevado do que aberto .... fopen Retorna um ponteiro para fluxo de arquivo que é semelhante ao fluxo de abstração que você lê em C ++
abertas Retorna um descritor de arquivo para o arquivo aberto ... Ele não fornece uma abstração fluxo e você é responsável por manipular os bits e bytes-se ... Esta é a um nível inferior em comparação com fopen
streams stdio são tamponados, enquanto Open () descritores de arquivos não são. Depende do que você precisa. Você também pode criar um do outro:
fileno int (FILE * stream) retorna o descritor de arquivo para um arquivo *, FILE * fdopen (fildes int, char const * mode) cria um arquivo * de um descritor de arquivo.
Tenha cuidado ao misturar-tamponada e não tamponada IO, já que você vai perder o que está em seu buffer quando você não nivelá-lo com fflush ().
Sim. Quando você precisar de uma alça de baixo nível.
sistemas operacionais em Unix, você pode geralmente identificadores de arquivo de troca e tomadas.
Além disso, alças de baixo nível para fazer uma melhor compatibilidade ABI do que os ponteiros de arquivo.
Normalmente, você deve favorecer usando a biblioteca padrão (fopen). No entanto, há ocasiões em que você vai precisar usar aberto diretamente.
Um exemplo que vem à mente é a de trabalho em torno de um bug em uma versão mais antiga do Solaris que fez fopen falhar após 256 arquivos estavam abertos. Isso porque eles erroniously utilizado um unsigned char para o campo fd na sua implementação struct arquivo em vez de um int. Mas este era um caso muito específico.
read () e write () usar sem buffer I / O. ( fd : integer descritor de arquivo)
fread () e fwrite () uso tamponada I / O. ( arquivo * ponteiro estrutura)
Os dados binários gravados em um tubo com write () não pode ser capaz de ler dados binários com fread () , por causa de alinhamentos byte, tamanhos variáveis, etc. É uma porcaria-shoot.
A maioria dos dispositivos de baixo nível usa o código do driver sem buffer de E / S chamadas.
A maioria dos usos nível de aplicação de E / S em buffer.
Utilize o arquivo * e suas funções associadas é OK em uma base de máquina-a-máquina, mas a portabilidade está perdido em outras arquiteturas na leitura e escrita de dados binários. fwrite () é tamponada de I / O e podem conduzir a resultados incertos se escrito para uma arquitetura de 64 bits e de execução em um 32 bits; ou (Windows / Linux). A maioria OSs têm macros de compatibilidade dentro de seu próprio código para evitar isso.
Para binários de baixo nível I / O portabilidade read () e write () garantia o mesmo binário lê e escreve quando compilado em arquiteturas diferentes. A coisa básica é escolher uma forma ou de outra e ser consistente sobre isso, todo o conjunto de binário.
<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
Assim, para uso básico Eu pessoalmente usar o acima sem misturar expressões idiomáticas muito.
Por outro lado,
<unistd.h> write()
lseek()
close()
pipe()
<sys/types.h>
<sys/stat.h>
<fcntl.h> open()
creat()
fcntl()
all use file descriptors.
Estes fornecem controle de grão fino sobre leitura e escrita bytes (Recomendado para dispositivos especiais e fifos (tubos)).
Então, novamente, usar o que você precisa, mas manter consistente em seus idiomas e interfaces. Se a maior parte de sua base de código usa um modo, o uso que também, a menos que haja uma verdadeira razão para não. Ambos os conjuntos de funções de I / O de biblioteca são extremamente confiáveis e usado milhões de vezes por dia.
Nota - Se você está interface C / S com outro idioma, (Perl, Python, Java, C #, lua ...) confira o que os desenvolvedores desses idiomas recomendo antes de escrever o código C e poupar algum problema.
fopen e seus primos são tamponados. aberto, ler e escrever não são tamponados. Sua aplicação pode ou não se importa.
fprintf e scanf Tem uma API mais rico que lhe permite ler e escrever arquivos de texto formatado. ler e escrever usar matrizes fundamentais de bytes. Conversões e formatação devem ser feitas à mão.
A diferença entre descritores de arquivo e (FILE *) é realmente irrelevante.
Randy