写程序熟悉read()、write()、stat()、open()、access()等函数

本文总结了 Unix 环境下高级编程中的文件 I/O 操作涉及的关键函数,包括 open、read、write 和 stat 系列函数的使用方法,并通过一个文件复制程序实例演示了这些函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这些函数在学习APUE(Unix环境高级编程)文件I/O时碰到,在这里做一个总结。


首先熟悉系统调用和库函数



系统调用是操作系统为用户态运行的进程与硬件设备(CPU、 磁盘、 打印机等)进行交互提供的一组接口函数;


库函数: 顾名思义是把函数放到库里。 是把一些常用到的函数编完放到一个库文件里,供别人用, 别人用的时候把它所在的文件名用#include<>加到里面就可以了。 可分为两类, 一类是c语言标准规定的库函数, 一类是编译器特定的库函数。 


想知道具体哪个函数如何使用,可以使用man命令

man 手册第一部分是命令 man 1 printf
man
手册第二部分是系统调用 man 2 write
man
手册第三部分是库函数 man 3 printf


open()函数

int open(const char *pathname, int flags,。。。);

The argument flags must include one of the following  access  modes:  O_RDONLY,  O_WRONLY,  or  O_RDWR.   These
       request opening the file read-only, write-only, or read/write,

打开的函数可以设置为,读O_RDONLY,写 O_WRONLY,读写O_RDWR。

。。。后面可以加些如权限等信息,不是必须的,但是*pathname, int flags是必须的。


path: 要打开的文件、 设备的路径名
oflag: 由多个选项进行运算构造oflag参数
必选
O_RDONLY (只读)O_WRONLY(只写)O_RDWR(读写)
可选
O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 文件不存在则创建它, 使用该选项需要第三个参数mode
O_NONBLOCK
如果path是一个FIFO、 块设备、 字符特殊文件则此选项为文件的本
次打开和后续的
I/O操作设置非阻塞模式方式。
O_TRUNC 如果文件存在, 而且为只写或读写成功打开, 则将其长度截取为0
O_EXECO_SEARCHO_CLOEXEC O_NOCTTY....
mode: oflag
O_CREAT选项时, 必须带该参数用来指定打开文件的权限模式, 如066 


read()/write() 函数


在打开文件后,可以进行读写等操作。

read()函数用来从打开的文件中读取数据:
ssize_t read(int fd, void *buf, size_t nbytes);


write()函数用来往打开的文件中写入数据:
ssize_t write(int fd, const void *buf, size_t nbytes);



stat系列函数 

stat系列函数用来返回文件或目录的相关信息

int stat(const char * restrict path, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
 //fd为文件描述符,对于内核而言, 所有打开的文件、 设备、 网络socket都是通过文件描述符引用,文件描述符是一个非负整数。 

struct stat {
    dev_t         st_dev;       //文件的设备编号
    ino_t         st_ino;       //节点
    mode_t        st_mode;      //文件的类型和存取的权限
    nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t         st_uid;       //用户ID
    gid_t         st_gid;       //组ID
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
    off_t         st_size;      //文件字节数(文件大小)
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;    //块数
    time_t        st_atime;     //最后一次访问时间
    time_t        st_mtime;     //最后一次修改时间
    time_t        st_ctime;     //最后一次改变时间(指属性)
};


access()函数

access可以用来测试文件是否存在或测试其权限位:
int access(const char *path, int mode);


R_OK      测试读许可权  
W_OK      测试写许可权  
X_OK      测试执行许可权  
F_OK      测试文件是否存在 


下面用一个copy程序来熟悉上面的那些函数用法,该程序用来实现将“test.txt”文件中的内容拷贝到“test2.txt”中


  1 /*********************************************************************************
  2  *      Copyright:  (C) 2017 fanmaolin<fanmaolinn@gmail.com>
  3  *                  All rights reserved.
  4  *
  5  *       Filename:  test-copy.c
  6  *    Description:  This file 
  7  *                 
  8  *        Version:  1.0.0(04/22/2017)
  9  *         Author:  fanmaolin <fanmaolinn@gmail.com>
 10  *      ChangeLog:  1, Release initial version on "04/22/2017 04:54:01 PM"
 11  *                 
 12  ********************************************************************************/
 13 #include <sys/types.h>
 14 #include <sys/stat.h>
 15 #include <fcntl.h>
 16 #include <unistd.h>
 17 #include <stdio.h>
 18 #include <error.h>
 19 
 20 #define BUF_SIZE    50
 21 #define PATH_NAME   "./test.txt" 
 22 
 23 int main(int argc, char **argv)
 24 {
 25     int     fd;
 26     int     fd2;
 27     char    buf[BUF_SIZE];
 28     int     nbytes;
 29     struct stat     sbuf;
 30     int     filesize = 0;
 31 
 32     if(access(PATH_NAME,F_OK))
 33     {
 34         printf("file %s not exit\n", "test.txt");
 35         return -1;
 36     }
 37 
 38     fd = open(PATH_NAME, O_RDWR);
 + test-copy.c                                                                                                                      
 39 
 40     if(fd < 0)
 41     {
 42         printf("open %s failure because:%s\n", PATH_NAME, strerror(error));
 43         return -2;
 44     }
 45 
 46     fd2 = open("test2.txt" ,O_RDWR|O_CREAT|O_TRUNC, 0644);//创建文件test2.txt,如果文件存在就清零
 47     if(fd2 < 0)
 48     {
 49         printf("open %s failure bacause:%s\n", "test2.txt", strerror(error));
 50         return -2;
 51     }
 52 
 53     fstat(fd, &sbuf);
 54     filesize = sbuf.st_size;
 55 
 56     while(filesize > 0)
 57     {
 58         nbytes = read(fd, buf, sizeof(buf));
 59         printf("read %d byte data\n", nbytes);
 60         write(fd2, buf, nbytes);
 61         filesize = filesize - nbytes;
 62     }
 63 
 64     close(fd);
 65     close(fd2);
 66 
 67 }


[fanmaolin@Centeros io]$ gcc test-copy.c       
[fanmaolin@Centeros io]$ ./a.out         
read 50 byte data
read 50 byte data
read 50 byte data
read 50 byte data
read 9 byte data
[fanmaolin@Centeros io]$ cat test2.txt         
aaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaa
a


aaaaaaaaaaaaaaaaaaaaaaa
sssssssss
ssssssssssssss
sssssss
bbbbbbbbbbb
bbbbbbbbbbb
bbbbbbbb
bbbbbbbbbbb
qqq


问题总结:

Segmentation fault (core dumped)

可以编译通过,但是无法执行。


原因:

printf()打印类型弄错

58  printf("chucuo %s\n",strerror(error));
 59     printf("read %d byte data\n", nbytes);
 
 59行打印整数用%d 我用成了%s (打印字符串)



我在代码的每一行加一个打印信息,然后运行,就知道在哪里出现了错误

 [fanmaolin@Centeros io]$ gcc test-copy.c 
[fanmaolin@Centeros io]$ ./a.out 
chucuo Unknown error 4195752
chucuo Unknown error 4195752
chucuo Unknown error 4195752
chucuo Unknown error 4195752
chucuo Unknown error 4195752
Segmentation fault (core dumped)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值