open是linux下的底层系统调用函数,fopen与freopen c/c++下的标准I/O库函数,带输入/输出缓冲。
linux下的fopen是open的封装函数,fopen最终还是要调用底层的系统调用open,所以在linux下如果需要对设备进行明确的控制,那最好使用底层系统调用(open)。
open对应的文件操作有:close, read, write,ioctl 等。
fopen 对应的文件操作有:fclose, fread, fwrite, freopen, fseek, ftell, rewind等。
freopen用于重定向输入输出流的函数,该函数可以在不改变代码原貌的情况下改变输入输出环境,但使用时应当保证流是可靠的。
open和fopen的区别:
1,fread是带缓冲的,read不带缓冲.
2,fopen是标准c里定义的,open是POSIX中定义的.
3,fread可以读一个结构.read在linux/unix中读二进制与普通文件没有区别.
4,fopen不能指定要创建文件的权限.open可以指定权限.
5,fopen返回文件指针,open返回文件描述符(整数).
6,linux/unix中任何设备都是文件,都可以用open,read.
1、open系统调用(linux)
头文件:#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
函数原型:int open( const char * pathname, int oflags);
int open( const char * pathname,int oflags, mode_t mode);
mode仅当创建新文件时才使用,用于指定文件的访问权限。
pathname 是待打开/创建文件的路径名;
oflags用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成。
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
以上三者是互斥的,即不可以同时使用。
打开/创建文件时,至少得使用上述三个常量中的一个。以下常量是选用的:
O_APPEND 每次写操作都写入文件的末尾
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK
以下用于同步输入输出
O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O
当你使用带有O_CREAT标志的open调用来创建文件时,你必须使用有3个参数格式的open调用。第三个参数mode是几个标志按位或后得到的,
这些标志在头文件sys/stat.h中定义,如下所示:
S_IRUSR: 读权限,文件属主
S_IWUSR: 写权限,文件属主
S_IXUSR: 执行权限,文件属主
S_IRGRP: 读权限,文件所属组
S_IWGRP: 写权限,文件所属组
S_IXGRP: 执行权限,文件所属组
S_IROTH: 读权限,其它用户
S_IWOTH: 写权限,其它用户
S_IXOTH: 执行权限,其它用户
返回值:成功则返回文件描述符,否则返回 -1。 返回文件描述符(整型变量0~255)。由open 返回的文件描述符一定是该进程尚未使用的最小描述符。只要有一个权限被禁止则返回-1。
错误代码:(均已E开头,将其去掉就是有关于错误的方面的单词或单词的缩写)
EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS 参数pathname所指的文件不符合所要求测试的权限。
EROFS 欲测试写入权限的文件存在于只读文件系统内。
EFAULT 参数pathname指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname不是目录。
ENOMEM 核心内存不足。
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误。
2、fopen库函数
头文件:<stdio.h>
函数原型:FILE * fopen(const char * path, const char * mode);
path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。
mode有下列几种形态字符串:
"r"或"rb" 以只读方式打开文件,该文件必须存在。
"w"或"wb" 以写方式打开文件,并把文件长度截短为零。
"a"或"ab" 以写方式打开文件,新内容追加在文件尾。
"r+"或"rb+"或"r+b" 以更新方式打开(读和写)
"w+"或"wb+"或"w+b" 以更新方式打开,并把文件长度截短为零。
"a+"或"ab+"或"a+b" 以更新方式打开,新内容追加在文件尾。
字母b表示文件时一个二进制文件而不是文本文件。(linux下不区分二进制文件和文本文件)
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中。
3、freopen
函数原型:FILE * freopen ( const char * filename, const char * mode, FILE * stream );
参数:
filename: 要打开的文件名
mode: 文件打开的模式,和fopen中的模式(r/w)相同
stream: 文件指针,通常使用标准流文件(stdin/stdout/stderr)
返回值:如果成功则返回该指向该stream的指针,否则为NULL。
作用:用于重定向输入输出流的函数,将stream中的标准输入、输出、错误或者文件流重定向为filename文件中的内容。linux下需要重定向输出很容易使用 ./程序名 >test (>>test 追加),windows下的输入输出重定向可以使用freopen。
使用方法: 因为文件指针使用的是标准流文件,因此我们可以不定义文件指针。
我们使用freopen()函数以只读方式r(read)打开输入文件test.in ,freopen("test.in", "r", stdin);
这样程序的输入就会从标准输入流stdin转换到从文件"test.in"中输入
然后使用freopen()函数以写入方式w(write)打开输出文件test.out,freopen("test.out", "w", stdout);
程序的输出就会从原来的标准输出变成写入文件"test.out"中
===============================================================================================
C语言open()和creat()函数创建文件时,文件权限设置相关
open()和creat()创建文件时,文件权限说明
首先了解一下 umask 命令,该命令用来设置限制新文件权限的掩码。当新文件被创建时,其最初的权限由文件创建掩码决定。简单地来说,umask和open()及creat()函数的权限码(mode_t mode参数)共同决定你的新建文件的权限。具体关系为mode & ~umask。
下面通过简单的程序来验证它们之间的关系。
由于open()和creat()创建文件,结果一致,我们直接采用creat()函数:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main()
{
if( creat("/aicamel/boa/file.txt",0777) < 0 ) {
printf("文件创建失败!\n");
} else {
printf("文件创建成功!\n");
}
return 0;
}
编译和运行
root@aicamel-machine:/aicamel/boa# gcc -o test test.c
root@aicamel-machine:/aicamel/boa# ./test
文件创建成功!
root@aicamel-machine:/aicamel/boa# ls -l file.txt
-rwxr-xr-x 1 root root 0 7月 5 09:24 file.txt
root@aicamel-machine:/aicamel/boa# umask
0022
root@aicamel-machine:/aicamel/boa#
我们可以看到实际创建的 file.txt 文件权限为 -rwx r-x r-x,并且当前系统的 umask 值为 0022 。我们创建文件时,希望创建的文件权限为 0777 ,也就是-rwx rwx rwx。我们现在来验证一下是否满足mode & ~umask。
~umask即为umask 取反值为 1755
我们创建文件的 mode 值为 0777
mode & ~umask 为 0755,也就是-rwx r-x r-x,与实际创建的文件权限一致。
看到这你应该知道怎么一回事了,但是如果我们的程序运行在ARM开发板上时,有时会出现umask值同样为0022,mode值同样为0777,当创建出的文件权限始终为-rw- - - - - - -,无论我们如何修改umask值和mode值,创建出的文件权限始终不变,如果遇到这种情况,我们需要使用umask()函数,即可解决这个问题。
使用umask()函数
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main()
{
umask(0000); //将umask值设置为0000,实际创建的文件权限即为下面的mode值
if( creat("/aicamel/boa/file.txt",0777) < 0 ) {
printf("文件创建失败!\n");
} else {
printf("文件创建成功!\n");
}
return 0;
}
编译运行结果为
root@aicamel-machine:/aicamel/boa# gcc -o test test.c
root@aicamel-machine:/aicamel/boa# ./test
文件创建成功!
root@aicamel-machine:/aicamel/boa# ls -l file.txt
-rwxrwxrwx 1 root root 0 7月 5 09:51 file.txt
root@aicamel-machine:/aicamel/boa# umask
0022
root@aicamel-machine:/aicamel/boa#
从运行结果来看,代码中使用umask()函数,并不会改变系统的umask值,只会临时改变umask值。所以个人建议,我们使用open()和creat()时,在代码上方加上一句umask(0000);,这样我们在使用open()和creat()时,就不需要特别计算mode值了。