Linux文件系统【02】creat,open,close,read,write,lseek;ioctl,fcntl,dup,dup2,自定义创建文件命令

目录

前言

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;
}

  • 30
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UNIX环境高级编程_第2版 ----------------------------------------------------------- 共两个压缩包( UNIX环境高级编程_第2版.part1 UNIX环境高级编程_第2版.part1 ) ------------------------------------------------------------ 原书名: Advanced Programming in the UNIX Environment 原出版社: Addison-Wesley 作者: (美)W.Richard Stevens, Stephen A.Rago [作译者介绍] 译者: 尤晋元 张亚英 戚正伟 丛书名: 图灵程序设计丛书 操作系统 出版社:人民邮电出版社 ISBN:7115147310 上架时间:2006-5-17 出版日期:2006 年5月 开本:16开 页码:758 版次:2-1 内容简介 ----------------------------------------------------------- 本书是被誉为UNIX编程“圣经”的Advanced Programming in the UNIX Environment一书的第2版。在   本书第1版出版后的十几年中,UNIX行业已经有了巨大的变化,特别是影响UNIX编程接口的有关标准变   化很大。本书在保持了前一版风格的基础上,根据最新的标准对内容进行了修订和增补,反映了最新的技   术发展。书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程   关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在   此基础上介绍了多个应用实例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附   录中给出了函数原型和部分习题的答案。   本书内容权威,概念清晰,阐述精辟,对于所有层次UNIX/Linux程序员都是一本不可或缺的参考书。 目录 ----------------------------------------------------------- 第1章unix基础知识1 1.1 引言1 1.2 unix体系结构1 1.3 登录1 1.4 文件和目录3 1.5 输入和输出6 1.6 程序和进程8 1.7 出错处理10 1.8 用户标识12 1.9 信号14 1.10 时间值15 1.11 系统调用和库函数16 1.12 小结17 习题18 第2章unix标准化及实现19 2.1 引言19 2.2 unix标准化19 2.2.1 iso c 19 2.2.2 ieee posix 20 2.2.3 single unix specification 25 .2.2.4 fips 26 2.3 unix系统实现26 2.3.1 svr4 26 2.3.2 4.4bsd 27 2.3.3 freebsd 27 2.3.4 linux 27 2.3.5 mac os x 28 2.3.6 solaris 28 2.3.7 其他unix系统28 2.4 标准和实现的关系28 2.5 限制29 2.5.1 iso c限制29 2.5.2 posix限制30 2.5.3 xsi限制32 2.5.4 sysconf、pathconf和fpathconf 函数32 2.5.5 不确定的运行时限制38 2.6 选项42 2.7 功能测试宏44 2.8 基本系统数据类型45 2.9 标准之间的冲突45 2.10 小结46 习题46 第3章文件i/o 47 3.1 引言47 3.2 文件描述符47 3.3 open函数48 3.4 creat函数49 3.5 close函数50 3.6 lseek函数50 3.7 read函数53 3.8 write函数54 3.9 i/o的效率54 3.10 文件共享56 3.11 原子操作59 3.12 dupdup2函数60 3.13 sync、fsync和fdatasync函数61 3.14 fcntl函数62 3.15 ioctl函数66 3.16 /dev/fd 67 3.17 小结68 习题68 第4章文件和目录71 4.1 引言71 4.2 stat、fstat和lstat函数71 目录 4.3 文件类型72 4.4 设置用户id和设置组id 74 4.5 文件访问权限75 4.6 新文件和目录的所有权77 4.7 access函数77 4.8 umask函数79 4.9 chmod和fchmod函数81 4.10 粘住位83 4.11 chown、fchown和lchown函数84 4.12 文件长度85 4.13 文件截短86 4.14 文件系统86 4.15 link、unlink、remove和rename 函数89 4.16 符号链接91 4.17 symlink和readlink函数94 4.18 文件的时间94 4.19 utime函数95 4.20 mkdir和rmdir函数97 4.21 读目录98 4.22 chdir、fchdir和getcwd函数102 4.23 设备特殊文件104 4.24 文件访问权限位小结106 4.25 小结106 习题107 第5章标准i/o库109 5.1 引言109 5.2 流和file对象109 5.3 标准输入、标准输出和标准出错110 5.4 缓冲110 5.5 打开流112 5.6 读和写流114 5.7 每次一行i/o 116 5.8 标准i/o的效率117 5.9 二进制i/o 119 5.10 定位流120 5.11 格式化i/o 121 5.12 实现细节125 5.13 临时文件127 5.14 标准i/o的替代软件130 5.15 小结130 习题130 第6章系统数据文件和信息133 6.1 引言133 6.2 口令文件133 6.3 阴影口令136 6.4 组文件137 6.5 附加组id138 6.6 实现的区别139 6.7 其他数据文件139 6.8 登录账户记录140 6.9 系统标识141 6.10 时间和日期例程142 6.11 小结146 习题146 第7章进程环境147 7.1 引言147 7.2 main函数147 7.3 进程终止147 7.4 命令行参数151 7.5 环境表152 7.6 c程序的存储空间布局152 7.7 共享库154 7.8 存储器分配154 7.9 环境变量157 7.10 setjmp和longjmp函数159 7.11 getrlimit和setrlimit函数164 7.12 小结168 习题168 第8章进程控制171 8.1 引言171 8.2 进程标识符171 8.3 fork函数172 8.4 vfork函数176 8.5 exit函数178 8.6 wait和waitpid函数179 8.7 waitid函数183 8.8 wait3和wait4函数184 8.9 竞争条件185 8.10 exec函数188 2 目录 8.11 更改用户id和组id 192 8.12 解释器文件196 8.13 system函数200 8.14 进程会计203 8.15 用户标识208 8.16 进程时间208 8.17 小结210 习题211 第9章进程关系213 9.1 引言213 9.2 终端登录213 9.3 网络登录216 9.4 进程组218 9.5 会话219 9.6 控制终端220 9.7 tcgetpgrp、tcsetpgrp和tcgetsid 函数221 9.8 作业控制222 9.9 shell执行程序225 9.10 孤儿进程组228 9.11 freebsd实现230 9.12 小结231 习题232 第10章信号233 10.1 引言233 10.2 信号概念233 10.3 signal函数240 10.4 不可靠的信号242 10.5 中断的系统调用244 10.6 可重入函数246 10.7 sigcld语义248 10.8 可靠信号术语和语义250 10.9 kill和raise函数251 10.10 alarm和pause函数252 10.11 信号集256 10.12 sigprocmask函数258 10.13 sigpending函数259 10.14 sigaction函数261 10.15 sigsetjmp和siglongjmp函数266 10.16 sigsuspend函数268 10.17 abort函数274 10.18 system函数276 10.19 sleep函数280 10.20 作业控制信号282 10.21 其他特征284 10.22 小结285 习题285 第11章线程287 11.1 引言287 11.2 线程概念287 11.3 线程标识288 11.4 线程的创建288 11.5 线程终止291 11.6 线程同步297 11.7 小结311 习题311 第12章线程控制313 12.1 引言313 12.2 线程限制313 12.3 线程属性314 12.4 同步属性318 12.5 重入324 12.6 线程私有数据328 12.7 取消选项331 12.8 线程和信号333 12.9 线程和fork 336 12.10 线程和i/o 339 12.11 小结340 习题340 第13章守护进程341 13.1 引言341 13.2 守护进程的特征341 13.3 编程规则342 13.4 出错记录345 13.5 单实例守护进程348 13.6 守护进程的惯例350 13.7 客户进程-服务器进程模型354 13.8 小结354 目录  3 习题354 第14章高级i/o355 14.1 引言355 14.2 非阻塞i/o 355 14.3 记录锁357 14.4 streams 370 14.5 i/o多路转接379 14.5.1 select和pselect函数381 14.5.2 poll函数384 14.6 异步i/o 386 14.6.1 系统v异步i/o 386 14.6.2 bsd异步i/o 387 14.7 readv和writev函数387 14.8 readn和writen函数389 14.9 存储映射i/o 390 14.10 小结395 习题396 第15章进程间通信397 15.1 引言397 15.2 管道398 15.3 popen和pclose函数403 15.4 协同进程408 15.5 fifo 412 15.6 xsi ipc 415 15.6.1 标识符和键415 15.6.2 权限结构416 15.6.3 结构限制417 15.6.4 优点和缺点417 15.7 消息队列418 15.8 信号量422 15.9 共享存储427 15.10 客户进程-服务器进程属性432 15.11 小结434 习题434 第16章网络ipc:套接字437 16.1 引言437 16.2 套接字描述符437 16.3 寻址439 16.3.1 字节序440 16.3.2 地址格式441 16.3.3 地址查询442 16.3.4 将套接字与地址绑定449 16.4 建立连接450 16.5 数据传输452 16.6 套接字选项464 16.7 带外数据466 16.8 非阻塞和异步i/o 467 16.9 小结468 习题468 第17章高级进程间通信469 17.1 引言469 17.2 基于streams的管道469 17.2.1 命名的streams管道472 17.2.2 唯一连接473 17.3 unix域套接字476 17.3.1 命名unix域套接字477 17.3.2 唯一连接478 17.4 传送文件描述符482 17.4.1 经由基于streams的管道传送 文件描述符484 17.4.2 经由unix域套接字传送文件 描述符486 17.5 open服务器版本1 493 17.6 open服务器版本2 498 17.7 小结505 习题505 第18章终端i/o507 18.1 引言507 18.2 综述507 18.3 特殊输入字符512 18.4 获得和设置终端属性516 18.5 终端选项标志516 18.6 stty命令522 18.7 波特率函数523 18.8 行控制函数524 18.9 终端标识524 18.10 规范模式529 18.11 非规范模式532 18.12 终端的窗口大小537 18.13 termcap,terminfo和curses 539 4 目录 18.14 小结540 习题540 第19章伪终端541 19.1 引言541 19.2 概述541 19.3 打开伪终端设备544 19.3.1 基于streams的伪终端547 19.3.2 基于bsd的伪终端549 19.3.3 基于linux的伪终端551 19.4 pty_fork函数553 19.5 pty程序555 19.6 使用pty程序559 19.7 高级特性564 19.8 小结565 习题565 第20章数据库函数库567 20.1 引言567 20.2 历史567 20.3 函数库568 20.4 实现概述569 20.5 集中式或非集中式572 20.6 并发574 20.7 构造函数库574 20.8 源代码575 20.9 性能598 20.10 小结600 习题601 第21章与网络打印机通信603 21.1 引言603 21.2 网络打印协议603 21.3 超文本传输协议605 21.4 打印假脱机技术605 21.5 源代码607 21.6 小结644 习题645 附录a 函数原型647 附录b 其他源代码677 附录c 部分习题答案685 参考书目709 索引715

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值