目录
前言
1, open()
2,creat()
3, close()
4,自己写创建文件的命令(可以附加上权限设置,期待后续)
5, read()
6, write()
7, lseek()
8, dup、dup2
9, fcntl
10, ioctl
前言
fopen,fclose,fread,fwrite,fseek;是C语言标准库的,方便移植;
文件的创建,打开,关闭,读,写,光标:
creat,open,close,read,write,lseek;
什么是文件描述符?
文件描述符是Unix特有的,其为一个非负整数,取值范围是0-NR_OPEN,对于Linux,NR_OPEN=255;也就是每个程序只能打开256 个文件;当使用open或者creat打开或者创建一个文件的时候,如果成功则将返回一个文件描述符,在进行读写操作时(read/write),文件描述符作为参数传递给(read/write);
文件描述符0代表标准输入文件,一般就是键盘,1代表标准输出文件,一般就是显示器,2代表标准错误输出,一般也是显示器;
1, open()
#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_SYNC,O_NONBLOCK,O_NDELAY同步异步阻塞非阻塞等等(待解决)
当使用O_CREAT时,才使用参数mode,用来说明新文件的权限(权限实际上是mode||umask),mode的取值:
2,creat()
#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>int creat(const char *pathname , mode_t mode);
创建或者覆盖原有文件
pathname,含路径的文件名
mode与open的相同
3, close()
#include<unistd.h>int close(int fd);
fd:文件描述符。
调用成功返回0,失败返回-1;
不保证数据全部存回硬盘。
4,自己写创建文件的命令(可以附加上权限设置,期待后续)
#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdio.h>#include<unistd.h>#include<errno.h>int main(int argc,char ** argv){int fd;char *path;if(argc<2){printf("%s<mode num><target file>\n",argv[0]);_exit(0);}path=argv[1];if((fd=open(path,O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1){perror("open");_exit(1);}else{printf("creat a file success");}close(fd);return 0;}
5, read()
#include<unistd.h>ssize_t read(int fd, void *buf,size_t count);
从文件描述符所指向的文件中读取count个字符到buf所指向的缓存中。
当count=0,read不读取数据,只返回0;
读取成功返回读取到的字节数,与count作比较,如果返回字节数目比count少,则是读到了文件末尾或者读取过程中信号被中断了等等。读取失败则返回-1;存到errno中;
文件读写指针随着读写移动;
6, write()
#include<unistd.h>ssize_t write(int fd, void *buf,size_t count);
将buf指向的缓冲区中的count个字节写到fd所指示的文件当中。
返回写入的字节数
错误返回-1,存到errno中;
7, lseek()
#include<sys/types.h>#include<unistd.h>off_t lseek(int fildes,off_t offset,int whence);
lseek()用来控制该文件的读写文件;
参数fildes为已经打开的文件的文件描述符;
参数offset为根据whence来移动读写位置的位移数;
参数whence:
lseek允许文件指针的值设置到文件结束符(EOF)之后,但并不会改变文件大小,在此位置写入数据之后,此段数据与之前的(EOF)之间是数据0;
有些设备文件不能使用lseek,比如Linux的tty文件,用lseek会返回错误代码ESPIPE;
#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<errno.h>#include<string.h>//报错函数void my_err(const char *err_string,int line){fprintf(stderr,"line:%d",line);perror(err_string);_exit(1);}//读数据函数int my_read(int fd){int len;int ret;int i;char read_buf[64];//指针移到最后if(lseek(fd,0,SEEK_END)==-1){my_err("lseek",__LINE__);}//最后位置到文件开始位置字节数if((len=lseek(fd,0,SEEK_CUR))==-1){my_err("lseek",__LINE__);}//指针回到文件开始处,下一步方便读取数据if(lseek(fd,0,SEEK_SET)==-1){my_err("lseek",__LINE__);}printf("len:%d\n",len);//读取数据,返回读取字节数if((ret=read(fd,read_buf,len))<0){my_err("read",__LINE__);}//打印for(i=0;i<len;i++){printf("%c",read_buf[i]);}printf("\n");return ret;}int main(){int fd;char write_buf[32]="Hello World";char write_buf2[32]="Q";if((fd=open("test.txt",O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR))==-1){my_err("open",__LINE__);}else{printf("creat the file success\n");}if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf)){my_err("write",__LINE__);}printf("---------------------------------\n");if(lseek(fd,10,SEEK_END)==-1){my_err("lseek",__LINE__);}if(write(fd,write_buf2,strlen(write_buf2))!=strlen(write_buf2)){my_err("write",__LINE__);}my_read(fd);close(fd);return 0;}
__LINE__内置宏,提示错误位置
类似还有__TIME__,__FUNCTION__,__FILE__等等;
8, dup、dup2
都是用于复制文件描述符(意义不同于平时的复制文本)
#include<unistd.h>int dup(int oldfd);int dup2(int oldfd,int newfd);
dup成功返回最小尚未被使用的文件描述符,失败返回-1;新文件描述符等同于旧文件描述符;
dup2返回指定的文件描述符newfd;newfd被占用时先释放newfd,再复制,当oldfd=newfd时,不释放。成功返回newfd,失败返回-1。
输入输出重定向?
9, fcntl
对已经打开的文件描述符进行操作改变其各种属性
#include<unistd.h>#include<funtl.h>int fcntl(int fd,int cmd);int fcntl(int fd,int cmd,long arg);int fcntl(int fd,int cmd,struct flock *lock);
参数cmd:
(a)F_DUPFD。同dup
(b)F_GETFD。获取文件描述符的close-on-exec标志,成功返回标志值,若其最后一位为0,则表示执行exec相关函数之后文件描述符韩式打开的,不然则是已经该关闭文件描述符;失败返回-1。
(c)F_SETFD。将close-on-exec标志为arg的最后一位,成功返回0,失败返回-1;
(d)F_GETFD。获取文件打开方式。成功返回标志值失败返回-1。见open的参数flags。
(e)F_SETFD。设置打开方式为arg的指定方式(O_APPEND,O_NONBLOCK与O_ASYNC之一)。见open参数flags。
例子:
#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<sys/types.h>#include<sys/stat.h>void my_err(const char *err_string,int line){fprintf(stderr,"line:%d",line);perror(err_string);_exit(1);}int main(){int ret;int access_mode;int fd;if((fd=open("test.txt",O_RDONLY))==-1){my_err("open",__LINE__);}if((ret=fcntl(fd,F_GETFL,0))<0){my_err("fcntl",__LINE__);}access_mode=ret&O_ACCMODE;if(access_mode==O_RDONLY){printf("test.txt access mode:read only");}else if(access_mode==O_WRONLY){printf("test.txt access mode:read only");}else if(access_mode==O_RDWR){printf("test.txt access mode:read + write");}if(ret&O_APPEND){printf(" ,append");}if(ret&O_NONBLOCK){printf(" ,nonblock");}if(ret&O_SYNC){printf(" ,sync");}printf("\n");return 0;}
测试结果:
(f)F_GETLK。参数lock指向一个希望设置的锁的结构体,如果目标位置的锁能够被设置,那么修改结构体的i_type为U_UNLCK,然后返回。如果目标位置有锁且冲突,那么返回一个冲突的锁的结构。
(g)F_SETLK。设置或者释放锁。i_type为F_RDLCK或者F_WRLCK时,指定区域设置锁,当i_type时释放锁。当锁被其他进程占用时,返回-1,且设置errno为EACCES或者EAGAIN。注意文件的打开方式要相应,例如设置读锁要以可读方式打开
(h)F_SETLKW。功能与F_SETLK相似,不过当有其他锁存在而被阻值时,会等待冲突的锁被释放
(i)F_GETOWN
(j)F_SETOWN
(k)F_SETSIG
(l)F_GETSIG
10, ioctl
用来控制设备
#include<sys/ioctl.h>int ioctl(int fd,int request,...);
第三个参数一般为char *argp,其随reques不同而不同,request决定argp是向ioctl传递数据还是获取数据。
#include<stdio.h>#include<unistd.h>#include<sys/ioctl.h>#include<stdlib.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/types.h>#include<net/if.h>#include<string.h>unsigned char g_macaddr[6];unsigned int g_subnetmask;unsigned int g_ipaddr;unsigned int g_broadcast_ipaddr;void init_net(void){int i;int sock;struct sockaddr_in sin;struct ifreq ifr;char g_eth_name[16];sock=socket(AF_INET,SOCK_DGRAM,0);if(sock==-1){perror("socket");}strcpy(g_eth_name,"ens33");//注意ens33,应该ifconfig一下在决定是什么,未知原因,没学到网络编程,后续补充strcpy(ifr.ifr_name,g_eth_name);printf("eth name:\t%s\n",g_eth_name);if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0){perror("ioctl");}memcpy(g_macaddr,ifr.ifr_hwaddr.sa_data,6);printf("local mac:\t");for(i=0;i<5;i++){printf("%.2x:",g_macaddr[i]);}printf("%.2x:\n",g_macaddr[i]);if(ioctl(sock,SIOCGIFADDR,&ifr)<0){perror("ioctl");}memcpy(&sin,&ifr.ifr_addr,sizeof (sin));g_ipaddr=sin.sin_addr.s_addr;printf("local eth0:\t%s\n",inet_ntoa(sin.sin_addr));if(ioctl(sock,SIOCGIFBRDADDR,&ifr)<0){perror("ioctl");}memcpy(&sin,&ifr.ifr_addr,sizeof (sin));g_broadcast_ipaddr=sin.sin_addr.s_addr;printf("broadcast:\t%s\n",inet_ntoa(sin.sin_addr));if(ioctl(sock,SIOCGIFNETMASK,&ifr)<0){perror("ioctl");}memcpy(&sin,&ifr.ifr_addr,sizeof (sin));g_broadcast_ipaddr=sin.sin_addr.s_addr;printf("subnetmask:\t%s\n",inet_ntoa(sin.sin_addr));close(sock);}int main(){init_net();return 0;}