ubuntuLinux下C语⾔open函数打开或创建⽂件与read,write函数详细讲解
open(打开⽂件)
相关函数
read,write,fcntl,close,link,stat,umask,unlink,fopen
表头⽂件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
定义函数
int open( const char * pathname, int flags);
int open( const char * pathname,int flags, mode_t mode);
函数说明
参数pathname 指向欲打开的⽂件路径字符串。下列是参数flags 所能使⽤的旗标:
O_RDONLY 以只读⽅式打开⽂件
O_WRONLY 以只写⽅式打开⽂件
O_RDWR 以可读写⽅式打开⽂件。上述三种旗标是互斥的,也就是不可同时使⽤,但可与下列的旗标利⽤OR(|)运算符组合。
O_CREAT 若欲打开的⽂件不存在则⾃动建⽴该⽂件。
O_EXCL 如果O_CREAT也被设置,此指令会去检查⽂件是否存在。⽂件若不存在则建⽴该⽂件,否则将导致打开⽂件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的⽂件为符号连接,则会打开⽂件失败。
O_NOCTTY 如果欲打开的⽂件为终端机设备时,则不会将该终端机当成进程控制终端机。
O_TRUNC 若⽂件存在并且以可写的⽅式打开时,此旗标会令⽂件长度清为0,⽽原来存于该⽂件的资料也会消失。
O_APPEND 当读写⽂件时会从⽂件尾开始移动,也就是所写⼊的数据会以附加的⽅式加⼊到⽂件后⾯。
O_NONBLOCK 以不可阻断的⽅式打开⽂件,也就是⽆论有⽆数据读取或等待,都会⽴即返回进程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的⽅式打开⽂件。
O_NOFOLLOW 如果参数pathname 所指的⽂件为⼀符号连接,则会令打开⽂件失败。
O_DIRECTORY 如果参数pathname 所指的⽂件并⾮为⼀⽬录,则会令打开⽂件失败。
此为Linux2.2以后特有的旗标,以避免⼀些系统安全问题。参数mode 则有下列数种组合,只有在建⽴新⽂件时才会⽣效,此外真正建⽂件时的权限会受到umask值所影响,因此该⽂件权限应该为(mode-umaks)。
S_IRWXU00700 权限,代表该⽂件所有者具有可读、可写及可执⾏的权限。
S_IRUSR 或S_IREAD,00400权限,代表该⽂件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该⽂件所有者具有可写⼊的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该⽂件所有者具有可执⾏的权限。
S_IRWXG 00070权限,代表该⽂件⽤户组具有可读、可写及可执⾏的权限。
S_IRGRP 00040 权限,代表该⽂件⽤户组具有可读的权限。
S_IWGRP 00020权限,代表该⽂件⽤户组具有可写⼊的权限。
S_IXGRP 00010 权限,代表该⽂件⽤户组具有可执⾏的权限。
S_IRWXO 00007权限,代表其他⽤户具有可读、可写及可执⾏的权限。
S_IROTH 00004 权限,代表其他⽤户具有可读的权限
S_IWOTH 00002权限,代表其他⽤户具有可写⼊的权限。fopen函数失败
S_IXOTH 00001 权限,代表其他⽤户具有可执⾏的权限。
返回值
若所有欲核查的权限都通过了检查则返回0值,表⽰成功,只要有⼀个权限被禁⽌则返回-1。
错误代码
EEXIST 参数pathname 所指的⽂件已存在,却使⽤了O_CREAT和O_EXCL旗标。
EACCESS 参数pathname所指的⽂件不符合所要求测试的权限。
EROFS 欲测试写⼊权限的⽂件存在于只读⽂件系统内。
EFAULT 参数pathname指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname不是⽬录。
ENOMEM 核⼼内存不⾜。
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误。
附加说明
使⽤access()作⽤户认证⽅⾯的判断要特别⼩⼼,例如在access()后再作open()空⽂件可能会造成系统安全上的问题。
范例
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
main()
{
int fd,size;
char s [ ]=”Linux Programmer!\n”,buffer[80];
fd=open(“/tmp/temp”,O_WRONLY|O_CREAT);
write(fd,s,sizeof(s));
close(fd);
fd=open(“/tmp/temp”,O_RDONLY);
size=read(fd,buffer,sizeof(buffer));
close(fd);
printf(“%s”,buffer);
}
执⾏
Linux Programmer!
read(由已打开的⽂件读取数据)
相关函数
readdir,write,fcntl,close,lseek,readlink,fread
表头⽂件
#include<unistd.h>
定义函数
ssize_t read(int fd,void * buf ,size_t count);
函数说明
read()会把参数fd 所指的⽂件传送count个字节到buf指针所指的内存中。若参数count为0,则read()不会有作⽤并返回0。返回值为实际读取到的字节数,如果返回0,表⽰已到达⽂件尾或是⽆可读取的数据,此外⽂件读写位置会随读取到的字节移动。
附加说明
如果顺利read()会返回实际读到的字节数,最好能将返回值与参数count作⽐较,若返回的字节数⽐要求读取的字节数少,则有可能读到了⽂件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。当有错误发⽣时则返回-1,错误代码存⼊errno中,⽽⽂件读写位置则⽆法预期。
错误代码
EINTR 此调⽤被信号所中断。
EAGAIN 当使⽤不可阻断I/O 时(O_NONBLOCK),若⽆数据可读取则返回此值。
EBADF 参数fd ⾮有效的⽂件描述词,或该⽂件已关闭。
范例
参考open()。
write(将数据写⼊已打开的⽂件内)
相关函数
open,read,fcntl,close,lseek,sync,fsync,fwrite
表头⽂件
#include<unistd.h>
定义函数
ssize_t write (int fd,const void * buf,size_t count);
函数说明
write()会把参数buf所指的内存写⼊count个字节到参数fd所指的⽂件内。当然,⽂件读写位置也会随之移动。
返回值
如果顺利write()会返回实际写⼊的字节数。当有错误发⽣时则返回-1,错误代码存⼊errno中。
错误代码
EINTR 此调⽤被信号所中断。
EAGAIN 当使⽤不可阻断I/O 时(O_NONBLOCK),若⽆数据可读取则返回此值。
EADF 参数fd⾮有效的⽂件描述词,或该⽂件已关闭。
范例
请参考open()。
拷贝⽂件实例:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main(int argc, char **argv) {
int from_fd, to_fd;
int bytes_read, bytes_write;
char buffer[BUFFER_SIZE];
char *ptr;
if (argc != 3) {
fprintf(stderr, "Usage:%s fromfile tofile\n\a", argv[0]);
exit(1);
}
/* 打开源⽂件 */
if ((from_fd = open(argv[1], O_RDONLY)) == -1) {
fprintf(stderr, "Open %s Error:%s\n", argv[1], strerror(errno));
exit(1);
}
/* 创建⽬的⽂件 */
if ((to_fd = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
fprintf(stderr, "Open %s Error:%s\n", argv[2], strerror(errno));
exit(1);
}
/* 以下代码是⼀个经典的拷贝⽂件的代码 */
while (bytes_read = read(from_fd, buffer, BUFFER_SIZE)) {
/
* ⼀个致命的错误发⽣了 */
if ((bytes_read == -1) && (errno != EINTR)) break;
else if (bytes_read > 0) {
ptr = buffer;
while (bytes_write = write(to_fd, ptr, bytes_read)) {
/* ⼀个致命错误发⽣了 */
if ((bytes_write == -1) && (errno != EINTR))break;
/* 写完了所有读的字节 */
else if (bytes_write == bytes_read) break;
/* 只写了⼀部分,继续写 */
else if (bytes_write > 0) {
ptr += bytes_write;
bytes_read -= bytes_write;
}
}
/* 写的时候发⽣的致命错误 */
if (bytes_write == -1)break;
}
}
close(from_fd);
close(to_fd);
close(to_fd);    exit(0);
}