五、基于文件描述符的文件操作(非缓冲)

1文件描述符

内核为每个进程维护一个已打开文件的记录表,文件描述符是一个较小的正整数(0—1023),它代表记录表的一项,通过文件描述符和一组基于文件描述符的文件操作函数,就可以实现对文件的读、写、创建、删除等操作。

常用基于文件描述符的函数有open(打开)、creat(创建)、close(关闭)、read(读取)、write(写入)、ftruncate(改变文件大小)、lseek(定位)、fsync(同步)、fstat(获取文件状态)、fchmod(权限)、flock(加锁)、fcntl(控制文件属性)、dup(复制)、dup2、select和ioctl。

基于文件描述符的文件操作并非ANSI C的函数。

如果不清楚某个函数的具体实现形式,可以通过下面的方式查询

man 函数名  查看该函数的帮助。

如果要复制里面的内容,按Ctrl+Insert键,再粘贴的话用:Shift+Insert键。

2打开、创建和关闭文件

open和creat都能打开和创建函数,原型为

#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);//文件名  打开方式  权限

int creat(const char *pathname, mode_t mode); //文件名  权限   //现在已经不常用了

creat函数等价于èopen(pathname,O_CREAT|O_TRUNC|O_WRONLY,mode);

open()函数出错时返回-1,相关参数如下:

flags和mode都是一组掩码的合成值,flags表示打开或创建的方式,mode表示文件的访问权限。

flags的可选项有


掩码


含义


O_RDONLY


以只读的方式打开


O_WRONLY


以只写的方式打开


O_RDWR


以读写的方式打开


O_CREAT


如果文件不存在,则创建文件


O_EXCL


仅与O_CREAT连用,如果文件已存在,则强制open失败


O_TRUNC


如果文件存在,将文件的长度截至0


O_APPEND


已追加的方式打开文件,每次调用write时,文件指针自动先移到文件尾,用于多进程写同一个文件的情况。


O_NONBLOCK


非阻塞方式打开,无论有无数据读取或等待,都会立即返回进程之中。


O_NODELAY


非阻塞方式打开


O_SYNC


同步打开文件,只有在数据被真正写入物理设备设备后才返回

mode的可选项有:

S_IRWXU 00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
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权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。

但是通常采用直接赋数值的形式,如:

1 int fd = open(“1.txt”,O_WRONLY | O_CREAT,0755);  //表示给755的权限
2 if(-1 == fd)
3 {
4   perror("open failed!\n");
5       exit(-1);
6 }

注意:LINUX中基于文件描述符的open函数,对于一个不存在的文件,不能通过O_WRONLY的方式打开,必须加上O_CREAT选项。

close用于文件的关闭:

int close(int fd);//fd表示文件描述词,是先前由open或creat创建文件时的返回值。

文件使用完毕后,应该调用close关闭它,一旦调用close,则该进程对文件所加的锁全都被释放,并且使文件的打开引用计数减1,只有文件的打开引用计数变为0以后,文件才会被真正的关闭。

3 读写文件

读写文件的函数原型为:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);//文件描述词  缓冲区  长度

ssize_t write(int fd, const void *buf, size_t count);

对于read和write函数,出错返回-1,读取完了之后,返回0, 其他情况返回读写的个数。

Example:将dir.c中的内容复制到dir.txt中,其中dir.txt起初不存在。

4改变文件大小

函数原型:

#include <unistd.h>
int ftruncate(int fd, off_t length);

函数ftruncate会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length大,则超过的部分会被删去。
返回值 执行成功则返回0,失败返回-1。

实例:

1 int main()
2 {
3     int fd = open("a.txt", O_WRONLY);
4     ftruncate(fd, 1000);
5     close(fd);
6     return 0;
7 }

5文件定位

函数lseek将文件指针设定到相对于whence,偏移值为offset的位置

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);//fd文件描述词

whence 可以是下面三个常量的一个

SEEK_SET 从文件头开始计算

SEEK_CUR 从当前指针开始计算

SEEK_END 从文件尾开始计算

利用该函数可以实现文件空洞(对一个新建的空文件,可以定位到偏移文件开头1024个字节的地方,在写入一个字符,则相当于给该文件分配了1025个字节的空间,形成文件空洞)通常用于多进程间通信的时候的共享内存。

1 int main()
2 {
3     int fd = open("c.txt", O_WRONLY | O_CREAT);
4     lseek(fd, 1024, SEEK_SET);
5     write(fd, "a", 1);
6     close(fd);
7     return 0;
8 }

6获取文件信息

可以通过fstat和stat函数获取文件信息,调用完毕后,文件信息被填充到结构体struct stat变量中,函数原型为:

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

int stat(const char *file_name, struct stat *buf);   //文件名  stat结构体指针

int fstat(int fd, struct stat *buf);   //文件描述词   stat结构体指针

结构体stat的定义为:

struct stat {

dev_t         st_dev;      /*如果是设备,返回设备表述符,否则为0*/

ino_t         st_ino;      /* i节点号 */

mode_t        st_mode;     /* 文件类型 */

nlink_t       st_nlink;    /* 链接数 */

uid_t         st_uid;      /* 属主ID */

gid_t         st_gid;      /* 组ID */

dev_t         st_rdev;     /* 设备类型*/

off_t         st_size;     /* 文件大小,字节表示 */

blksize_t     st_blksize;  /* 块大小*/

blkcnt_t      st_blocks;   /* 块数 */

time_t        st_atime;    /* 最后访问时间*/

time_t        st_mtime;    /* 最后修改时间*/

time_t        st_ctime;    /* 创建时间 */

};

对于结构体的成员st_mode,有一组宏可以进行文件类型的判断



描述


S_ISLNK(mode)


判断是否是符号链接


S_ISREG(mode)


判断是否是普通文件


S_ISDIR(mode)


判断是否是目录


S_ISCHR(mode)


判断是否是字符型设备


S_ISBLK(mode)


判断是否是块设备


S_ISFIFO(mode)


判断是否是命名管道


S_ISSOCK(mode)


判断是否是套接字

通常用于判断:if(S_ISDIR(st.st_mode)){}

Example:获得文件的大小

1 #include<sys/stat.h>
2 #include<unistd.h>
3 main()
4 {
5     struct stat buf;
6     stat (“/etc/passwd”,&buf);
7     printf(“/etc/passwd file size = %d \n”,buf.st_size);//st_size可以得到文件大小
8 }

如果用fstat函数实现,如下: 
int fd = open (“/etc/passwd”,O_RDONLY);  //先获得文件描述词
fstat(fd, &buf); 
实例:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <errno.h>
 4 #include <sys/stat.h>
 5 #include <sys/types.h>
 6 #include <unistd.h>
 7 #include <fcntl.h>
 8 #include <time.h>
 9 int main()
10 {
11     int fd = open("/home/wangxiao/0926/a.txt", O_RDONLY);
12     if(fd == -1)
13     {
14         perror("open error");
15         exit(-1);
16     }
17     struct stat buf;
18     int iRet = fstat(fd, &buf);
19     if(iRet == -1)
20     {
21         perror("fstat error");
22         exit(-1);
23     }
24     if(S_ISREG(buf.st_mode))
25     {
26        printf("regular file!\n");
27     }
28     if(S_ISDIR(buf.st_mode))
29     {
30         printf("directory!\n");
31     }
32     if(S_ISLNK(buf.st_mode))
33     {
34         printf("link file!\n");
35 }
36 printf("the size of file is : %d\n", buf.st_size);
37 time_t tt = buf.st_atime;
38 struct tm *pT = gmtime(&tt);
39 printf("%4d-%02d-%02d   %02d:%02d:%02d\n", (1900+pT->tm_year), (1+pT->tm_mon), pT->tm_mday, (8+pT->tm_hour), pT->tm_min, pT->tm_sec);
40 //  printf("the last access time is : %d\n", buf.st_atime);
41 close(fd);
42 return 0;
43 }

7 文件描述符的复制

系统调用函数dup和dup2可以实现文件描述符的复制,经常用来重定向进程的stdin(0),stdout(1),stderr(2)。

dup返回新的文件描述符(没有使用的文件描述符的最小编号)。这个新的描述符是旧文件描述符的拷贝。这意味着两个描述符共享同一个数据结构。

dup2允许调用者用一个有效描述符(oldfd)和目标描述符(newfd),函数成功返回时,目标描述符将变成旧描述符的复制品,此时两个文件描述符现在都指向同一个文件,并且是函数第一个参数(也就是oldfd)指向的文件。

原型为:

#include <unistd.h>   //头文件包含

int dup(int oldfd);

int dup2(int oldfd, int newfd);

文件描述符的复制是指用另外一个文件描述符指向同一个打开的文件,它完全不同于直接给文件描述符变量赋值,例如:

描述符变量的直接赋值:

char szBuf[32];

int fd=open(“./a.txt”,O_RDONLY);

int fd2=fd;   //类似于C语言的指针赋值,当释放掉一个得时候,另一个已经不能操作了

close(fd); //导致文件立即关闭

printf(“read:%d\n”,read(fd2),szBuf,sizeof(szBuf)-1); //读取失败

close(fd2); //无意义

在此情况下,两个文件描述符变量的值相同,指向同一个打开的文件,但是内核的文件打开引用计数还是为1,所以close(fd)或者close(fd2)都会导致文件立即关闭掉。

描述符的复制:

char szBuf[32];

int fd=open(“./a.txt”,O_RDONLY);

int fd2=dup(fd); //内核的文件打开引用计算+1,变成2了

close(fd); //当前还不会导致文件被关闭,此时通过fd2照样可以访问文件

printf(“read:%d\n”,read(fd2),szBuf,sizeof(szBuf)-1);

close(fd2); //内核的引用计数变为0,文件正式关闭

Example:

 1  #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 int main(int argc,char *argv[])
 8 {
 9        char szBuf[32]={0};
10         int fda=open("./a.txt",O_RDWR); //假设a.txt的内容为:hello world
11        int fdaa=dup(fda);
12         read(fda,szBuf,4);
13         puts(szBuf);     //关闭之前先输入原来的内容
14         close(fda);
15 //    lseek(fdaa, 0, SEEK_SET);
16         read(fdaa,szBuf,sizeof(szBuf));
17         puts(szBuf);     //输出现在的内容
18         close(fdaa);
19 }

解析:假设a.txt中的内容为:hello world.上面的例子会发现第一次输出的结果是hell。关闭close(fda)的时候,文件实际上还没有真正的关闭,此时文件指针已经向后移动了。执行第二次read命令将o world读出来,最后关闭fdaa。

dup有时会用在一些特定的场合,如下:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <fcntl.h>
 4 #include <sys/stat.h>
 5 #include <sys/types.h>
 6 #include <stdlib.h>
 7 int main()
 8 {
 9         int fd = open("a.txt", O_WRONLY | O_CREAT);
10         if(fd == -1)
11         {
12                perror("open error");
13                 exit(-1);
14         }
15         printf("\n");    /* 必不可少 */
16         close(1);
17         int fd2 = dup(fd);
18         close(fd);
19         printf("hello world\n");
20         close(fd2);
21         return 0;
22 }    

该程序首先打开了一个文件,返回一个文件描述符,因为默认的就打开了0,1,2表示标准输入,标准输出,标准错误输出。而用close(1);则表示关闭标准输出,此时这个文件描述符就空着了。后面又用dup,此时dup(fd);则会复制一个文件描述符到当前未打开的最小描述符,此时这个描述符为1.后面关闭fd自身,然后在用标准输出的时候,发现标准输出重定向到你指定的文件了。那么printf所输出的内容也就直接输出到文件了。

dup2(int fdold,int fdnew)也是进行描述符的复制,只不过采用此种复制,新的描述符由用户用参数fdnew显示指定,而不是象dup一样由内核帮你选定(内核选定的是随机的)。对于dup2,如果fdnew已经指向一个已经打开的文件,内核会首先关闭掉fdnew所指向的原来的文件。此时再针对于fdnew文件描述符操作的文件,则采用的是fdold的文件描述符。如果成功dup2的返回值于fdnew相同,否则为-1.

思考下面程序的结果:

 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 int main(int argc,char *argv[])
 8 {
 9     char szBuf[32]={0};
10     int fda=open("./a.txt",O_RDONLY);
11     int fdb=open("./b.txt",O_RDONLY);
12     int fdbb=dup(fdb);
13     int fda2=dup2(fda,fdb);  //可以设定为:int fda2 = dup2(fda,5);即自己设为5
14     printf("fda:%d fdb:%d fdbb:%d fda2:%d",fda,fdb,fdbb,fda2);
15     read(fdb,szBuf,sizeof(szBuf)-1);     //此时fdb已经不再定位b.txt而是a.txt
16     printf("result:%s\n",szBuf);
17     close(fda);
18     close(fdb);
19     close(fdbb);
20     close(fda2);
21 }

8标准输入输出文件描述符

与标准的输入输出流对应,在更底层的实现是用标准输入、标准输出、标准错误文件描述符表示的。它们分别用STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO三个宏表示,值分别是0、1、2三个整型数字。

标准输入文件描述符   èSTDIN_FILENO    0

标准输出文件描述符  STDOUT_FILENO  1

标准错误输出文件描述符  STDERR_FILENO  2

示例:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <string.h>
 4 int main()
 5 {
 6     char szBuf[32],szBuf2[50];
 7     printf("Input string:");
 8     fflush(stdout);    //要刷新标准输出流,才可以立即在屏幕上显示”Input  string”
 9     //fflush用于linux中的时候,只对fflush(stdout)有效。
10     int iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf));
11     szBuf[iRet]=0;    //read是以无类型指针方式读的数据,不会自动在缓冲区后加0结束标记。
12     sprintf(szBuf2,"The string is:%s",szBuf);
13     write(STDOUT_FILENO,szBuf2,strlen(szBuf2));
14     return 0;
15 }

9 I/O多路转接模型

·   I/O多路转接模型:在这种模型下,如果请求的I/O操作阻塞,且它不是真正阻塞I/O,而是让其中的一个函数等待,在这期间,I/O还能进行其他操作。如本节要介绍的select()函数,就是属于这种模型。

Select函数:

#include <sys/select.h>

#include <sys/time.h>

int select(int maxfd, fd_set *readset,fd_set *writeset, fd_set *exceptionset, const struct timeval * timeout);

返回:就绪描述字的正数目,0——超时,-1——出错

参数解释:

maxfd: 最大的文件描述符(其值应该为最大的文件描述符字 + 1)

readset: 内核读操作的描述符字集合

writeset:内核写操作的描述符字集合

exceptionset:内核异常操作的描述符字集合

timeout:等待描述符就绪需要多少时间。NULL代表永远等下去,一个固定值代表等待固定时间,0代表根本不等待,检查描述字之后立即返回。

其中readset、writeset、exceptionset都是fd_set集合。该集合的相关操作如下:

void FD_ZERO(fd_set *fdset);  /* 将所有fd清零 */

void FD_SET(int fd, fd_set *fdset);  /* 增加一个fd */

void FD_CLR(int fd, fd_set *fdset);  /* 删除一个fd */

int FD_ISSET(int fd, fd_set *fdset);  /* 判断一个fd是否有设置 */

一般来说,在使用select函数之前,首先要使用FD_ZERO和FD_SET来初始化文件描述符集,在使用select函数时,可循环使用FD_ISSET测试描述符集,在执行完对相关文件描述符之后,使用FD_CLR来清除描述符集。

另外,select函数中的timeout是一个struct timeval类型的指针,该结构体如下:

struct timeval

{

long tv_sec; /* second */   //秒

long tv_usec;  /* microsecond */ //微秒

};

Example:多路转接模型 select

 1 #include <sys/select.h>
 2 #include <sys/time.h>
 3 #include <sys/types.h>
 4 #include <unistd.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 #include <stdio.h>
 8 #include <stdlib.h>
 9 #define FILENAME1 "a.txt"
10 #define FILENAME2 "dir.c"
11 int main()
12 {
13         char buf[10] = {0};
14         int fd1 = open(FILENAME1,O_RDWR);
15        int fd2 = open(FILENAME2,O_RDWR);
16         int fd3 = open(FILENAME1,O_RDWR);
17         int fd4 = open(FILENAME2,O_RDWR);
18         if( (-1 == fd1) || (-1 == fd2) || (-1 == fd3) || (-1 == fd4) )
19         {
20              perror("open");
21             exit(-1);
22         }
23         fd_set fdrd,fdwr;     //绑定读写集合
24         FD_ZERO(&fdrd);     //清除以前读的绑定
25         FD_ZERO(&fdwr);     //清除以前写的绑定
26         FD_SET(fd1,&fdrd);     //将fd1与读绑定
27         FD_SET(fd2,&fdrd);
28         FD_SET(fd3,&fdwr);     //将fd3与写绑定
29         FD_SET(fd4,&fdwr);
30         int max1 = fd1 > fd2 ? fd1 : fd2;     //获取读绑定中的文件描述词最大值
31         int max2 = fd3 > fd4 ? fd3 : fd4;        //获取写绑定中的文件描述词最大值
32         int max = max1 > max2 ? max1 : max2;     //获得读写文件描述词最大值
33         struct timeval tv;     //用于记录时间,表示过这么长时间不响应就退出
34         tv.tv_sec = 2;     //秒
35         tv.tv_usec = 0;     //微妙
36         while(1)
37         {
38             if( select(max+1, &fdrd, &fdwr, NULL, &tv) == -1 )    //从1—max+1查找
39             {
40                      perror("select");
41                     break;
42             }
43             if( FD_ISSET(fd1,&fdrd) )    //如果fd1设置的是读绑定
44             {
45                     read(fd1,buf,sizeof(buf)-1);
46                     puts(buf);
47                     sleep(1);
48             }
49             if( FD_ISSET(fd2,&fdrd) )
50             {
51                     read(fd2,buf,sizeof(buf)-1);
52                     puts(buf);
53                        sleep(1);
54             }
55             if( FD_ISSET(fd3,&fdwr) )     //如果fd3设置的是写绑定
56                 {
57                     write(fd3,buf,sizeof(buf));
58                     sleep(2);
59             }
60             if( FD_ISSET(fd4,&fdwr) )
61             {
62                        write(fd4,buf,sizeof(buf));
63                     sleep(2);
64             }
65         }
66             close(fd1);
67             close(fd2);
68             close(fd3);
69             close(fd4);
70 }            

补充:

  1. 程序参数:

1 int main(int argc,char ** argv)
2 {
3   int i = 0;
4   for( ; i< argc; i++)
5     printf("%s",argv[i]);
6 }

参数argc表示命令行传入的参数个数,并且一次保存到argv数组中。例如程序叫main.c,最后执行的时候,如果直接是./main则argc=1,此时argv[0]就是./main;如果是./main aaa bbb,则argc=3,argv[0]:./main, argv[1]:aaa argv[2]:bbb.

  1. 日志

许多应用程序需要记录它们的活动,系统程序经常需要向控制台或日志文件写消息。这些消息可能指示错误、警告或者与系统状态有关的一般信息。通常是在/var/log目录下的messages中包含了系统信息。通过syslog可以向系统的日志发送日志信息。

函数原型如下:

#include <syslog.h>

void syslog(int priority, const char* message, arguments…);

对于priority有如下几个常见的:

LOG_EMERG 紧急情况

LOG_ALERT 高优先级故障(如:数据库崩溃)

LOG_CRIT 严重错误(如:硬件错误)

LOG_ERR 错误

LOG_WARNING 警告

LOG_NOTICE 需要注意的特殊情况

LOG_INFO 一般信息

LOG_DEBUG 调试信息(写不到messages里面)

 1 #include <syslog.h>
 2 main()
 3 {
 4    //openlog("log",LOG_PID|LOG_CONS|LOG_NOWAIT,LOG_USER);
 5    syslog(LOG_ALERT,"this is alert\n");
 6    syslog(LOG_INFO,"this is info\n");
 7    syslog(LOG_DEBUG,"this is debug%d\t %s",10,"aaaa");
 8    syslog(LOG_ERR,"err");
 9    syslog(LOG_CRIT,"crit");
10    //closelog();
11 }

利用tail -10 /var/log/messages可以查看。

还可以通过函数openlog函数来改变日志信息的表达方式。openlog的原型如下:

#include <syslog.h>

void openlog(const char* ident, int logopt, int facility);

void closelog(void);

它可以设置一个字符串ident,该字符串会添加在日志信息的前面。你可以通过它来指明是哪个应用程序创建了这条信息。facility值为LOG_USER。logopt参数对后续syslog调用的行为进行配置。如下:

LOG_PID 在日志信息中包含进程标识符,这是系统分配给每个进程的一个唯一值

LOG_CONS 如果信息不能被记录到日志文件中,就把它们发送到控制台

  1. 日期

 1 #include <time.h>
 2 main()
 3 {
 4     char *wday[] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday","saterday" };
 5     time_t timep;
 6     struct tm *pTm;
 7     time(&timep);
 8     pTm = gmtime(&timep);
 9     printf("%04d-%02d-%02d\t",(1900 + pTm->tm_year), (1 + pTm->tm_mon), (pTm->tm_mday));
10     printf("%02d:%02d:%02d\t",(8 + pTm->tm_hour), (pTm->tm_min), (pTm->tm_sec));  //似乎小时总是相差8,所以加上8试试
11     printf("%s\n",wday[pTm->tm_wday]);
12 }

时间: 2024-07-29 06:33:43

五、基于文件描述符的文件操作(非缓冲)的相关文章

基于文件描述符的文件操作(非缓冲)

1.1. 文件描述符:内核为每个进程维护一个已打开文件的记录表,文件描述符是一个较小的正整数(0-1023),它代表记录表的一项,通过文件描述符和一组基于文件描述符的文件操作函数,就可以实现对文件的读.写.创建.删除等操作.常用基于文件描述符的函数有open(打开).creat(创建).close(关闭).read(读取).write(写入).ftruncate(改变文件大小).lseek(定位).fsync(同步).fstat(获取文件状态).fchmod(权限).flock(加锁).fcnt

Linux下基于文件描述符的文件操作(非缓冲)

1 文件描述符 内核为每个进程维护一个已打开文件的记录表(实现为结构体数组),文件描述符是一个较小的正整数(0-1023)(结构体数组下标),它代表记录表的一项,通过文件描述符和一组基于文件描述符的文件操作函数,就可以实现对文件的读.写.创建.删除等操作. 常用基于文件描述符的函数有open(打开).creat(创建).close(关闭).read(读取).write(写入).ftruncate(改变文件大小).lseek(定位).fsync(同步).fstat(获取文件状态).fchmod(权

浅谈文件描述符与文件指针

一.文件描述符: 内核利用文件描述符(file descriptor)来访问文件.文件描述符是非负整数.打开现存文件或新建文件时,内核会返回一个文件描述符. 1.优点: 1.基于文件描述符的I/O操作兼容POSIX(可移植操作系统接口)标准 2.UNIX/LINUX的系统调用中,大量系统调用都依赖于文件描述符 2.缺点: 1.在非UNIX/LINUX操作系统上,无法基于这一概念进行编程 2.它在形式上不过是个整数,当代码量增大时,会使编程者难以分清哪些整数是数据,哪些是文件描述符.所以完成的代码

文件描述符、文件描述符表、打开文件表、目录项、索引节点之间的联系

文件描述符.文件描述符表.打开文件表.目录项.索引节点之间的联系如下图所示: 每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针,已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体. 在file结构体中维护File Status Flag(file结构体的成员f_flags)和当前读写位置(file结构体的成员f_pos).在上图中,进程1和进程2都打开同一文件,

文件描述符和文件指针的区别

文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数.每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针. 文件指针:C语言中使用文件指针做为I/O的句柄.文件指针指向进程用户区中的一个被称为FILE结构的数据结构.FILE结构包括一个缓冲区和一个文件描述符.而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符

文件描述符、文件表项、V节点表项的一些总结

转自  http://blog.csdn.net/gzzheyi/article/details/7739556 表格可以参见APUE 第三版 P61. 文件描述符(进程级别): 1).在每个进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,可将其视察为一个矢量(数组),每个描述符占用一项.与每个文件描述符相关联的是: (a).文件描述符标志. (b).指向一个文件表项的指针.(不同的文件描述符可以指向同一个文件表项,例如用dup函数复制文件描述符,得到一个新的文件描述符,但是它们指向

Linux下的文件操作(2)——基于文件描述符的文件操作

概要: 打开.创建和关闭文件 读写文件 文件定位 获取文件信息 打开.创建和关闭文件 函数原型: #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);//文件名 打开方

文件描述符与文件指针等文件操作的几个问题

1.二者对比: 文件描述符就是open文件时产生的一个整数,直到一个索引作用,它用于UNIX系统中,用于标识文件.它是系统调用产生的. 文件指针是指向一个FILE的结构体,这个结构体里有一个元素就是文件描述符.它用于ANSI C标准的IO库调用中,用于标识文件.fopen是依赖于open的: 既然FILE中包含文件描述符元素,可以用fopen()直接获取指针fp,然后使用fp获得fp中所包含文件描述符fd的信息. 文件描述符应该是唯一的,但文件指针(值)却不是唯一的,但指向的对象却应该是唯一的.

文件描述符、文件表项指针、inode节点的关系

内核使用3种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程的影响. (1) 每个进程在进程表中都有一个纪录项,纪录项中包含一张打开文件描述符表,每个文件描述符各占一项,与每个文件描述符相关的是 a. 文件描述符标志 b. 指向一个文件表项的指针 (2) 内核为所有打开文件维护一张文件表项,每个文件表项包含: a. 文件状态(读 写 同步 非阻塞等) b. 当前文件偏移量 c. 指向改文件V节点(i节点)的指针 (3) 没打开一个文件或设备,都有一个V节点结构,V节