文件IO函数

一、linux中的文件

        在 Linux 系统中,一切都是“文件”:普通文件、驱动程序、网络通信等等。所有的操作,都是通过“文件 IO”来操作的。所以,很有必要掌握文件操作的常用接口。

二、文件IO

在 Linux上操作文件时,有两套函数:标准IO、系统调用I0。

标准I0相关函数:fopen/fread/fwrite/fseek/fflush/fclose等。

系统调用I0的相关函数:open/read/write/lseek/fsync/close。

二者区别:

系统调用IO函数每次操作都会进入内核。

标准IO函数引入了用户Buffer,先访问一次内核将数据存入Buffer,然后进行读写操作,不会频繁访问内核。但其底层仍然使用系统调用IO函数。

三、主函数 

3.1 主函数

int main(int argc ,char **argv)

argc:参数个数

argv:参数数组

例子:

./open 1.txt

则argc=2,argv[0]=./open;argv[1]=1.txt

3.2 函数查看方法

Linux 下有 3 大帮助方法:help、man、info。

help 只能用于查看某个命令的用法,而 man 手册既可以查看命令的用法,还可以查看函数的详细介绍等等。它含有 9 大分类

四、open函数:

(1) 在Ubuntu终端上使用“man 2 open”指令可以查看open函数原型及所需要包含的头文件。

(2) 包含的头文件:#include <sys/types.h>、#include <sys/stat.h>、#include <fcntl.h>

(3) 原型:①int open(const char *pathname, int flags);

②int open(const char *pathname, int flags, mode_t mode);

相关形参解释如下:

(4) 功能:打开或创建一个文件。 

4.1  open函数打开文件实验:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main(int argc ,char  **argv)
{
    if(argc!=2)
    {
        printf("Usage: %s <file>\n",argv[1]);
        return -1;
    }
    int fd;
    fd=open(argv[1],O_RDWR);
    if(fd<0)
    {
        printf("无法打开 %s\n",argv[1]);
        // printf("errno = %d\n", errno);  //错误代码
        //printf("err=%s\n",strerror(errno));  //将错误代码翻译成具体信息
        perror("err");  //打印错误信息
    }
    else
    {
        printf("open success\n");
    }
    close(fd);
    return 0;
}

errno是一个全局变量,存放上一个错误码,使用时需要包含头文件<errno.h>。

perror()函数可以打印错误信息。
在Usage: %s <file>中
<>表示文件不可省略

[]表示可以省略

4.2  测试执行

gcc -o test test.c
./test 1.txt &
ps  //查询当前运行的进程状态
cd /proc/4339 //proc主要用于获取系统和进程信息,4339是进程号
kill -9 4339  //杀死进程

&:程序在后台运行

ps:命令查询当前运行的进程状态

kill -9 进程号 : 用来杀死进程

4.3 open函数创建文件:

int open(const char *pathname, int flags, mode_t mode);

flags:表示打开文件所采取的操作

mode:表示创建的文件的权限

注意:打开已经存在的文件,无法修改其权限;新建文件的时候可以指定权限

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;
    if (argc != 2)
    {
        printf("Usage: %s <file>\n", argv[0]);
        return -1;
    }
    /*
    打开文件,可读可写,存在则截断为0,
    不存在则创建权限为777的文件,记得umask,
    所以最终权限只有775
    */
    fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0777);
    if (fd < 0)
    {
        perror("err");
    }
    else
    {
        printf("fd = %d\n", fd);
    }
    close(fd);
    return 0;
}

1.调用open函数时,flags处可以将多个参数以|进行分隔。

2.umask能够设置文件在创建时mode的掩码。

例如,使用umask命令得到"0002"的结果,那么文件创建时模式掩码为"000 000 000 010"。

3.使用open创建文件时最终的权限结果为:"mode & ~umask"。因此,当指定创建文件权限为777时,111 111 111 &  ~(111 111 101) = 111 111 101,所以创建文件的权限结果为775。

五、write函数 

5.1 函数原型

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

作用:将buf 中的 count 字节数据写入指定文件描述符的文件中。

fd:指定要写入的文件描述符

buf:缓冲区,一般是一个数组,指要写入文件的对象

count:要写入的实际字节数

返回值:

成功时: 返回实际写入的字节数。 

失败时: 返回 -1。

5.2 write函数写入多个字符串

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;
    int len;
    if (argc < 3 )
    {
        printf("Usage: %s <file> string1 ...\n", argv[0]);
        return -1;
    }
    fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0777);
    if (fd < 0)
    {
        perror("err");
    }
    else
    {
        printf("fd = %d\n", fd);
    }
    for(int i = 2;i < argc; i++)
    {
        len = write(fd, argv[i], strlen(argv[i]));
        if(len != strlen(argv[i]))
        {
            perror("write");
            break;
        }
        write(fd , "\r\n" , 2);
    }
    close(fd);
    return 0;
}

5.3 在现存内容中间插入新字符串(write + lseek函数)

5.3.1 函数原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

作用:重新定位读/写文件偏移

fd:指定要偏移的文件描述符

offset:文件偏移量

whence:开始添加偏移 offset 的位置

SEEK_SET,offset相对于文件开头进行偏移

SEEK_CUR,offset相对文件当前位置进行偏移

SEEK_END,offset相对于文件末尾进行偏移

 5.3.2 代码实现
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;
    int len;
    if (argc < 3 )
    {
        printf("Usage: %s <file> string1 ...\n", argv[0]);
        return -1;
    }
    fd = open(argv[1], O_RDWR | O_CREAT, 0777);
    if (fd < 0)
    {
        perror("err");
    }
    else
    {
        printf("fd = %d\n", fd);
    }
    lseek(fd,3,SEEK_SET);
    write(fd,argv[2],strlen(argv[2]));
    close(fd);
    return 0;
}

5.3.3运行结果

插入的字符串出现在偏移量的后面,但是会覆盖原来的字符 。

六、read函数

6.1 函数原型

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

作用:从给定的文件描述符指定的文件中,读取 count 个字节的数据,存放至 buf中。

fd:指定要读写的文件描述符

buf:缓冲区,一般是一个数组,用于存放读取的内容

count:一次要读取的最大字节数

返回值:

  • 正值:成功读取的字节数,可能小于请求的字节数。
  • 0:表示到达文件末尾。
  • -1:出现错误。

 6.2 read函数读取文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;
    int len;
    unsigned char buf[100];
    if (argc !=2 )
    {
        printf("Usage: %s <file> \n", argv[0]);
        return -1;
    }
    fd = open(argv[1], O_RDONLY);
    if (fd < 0)
    {
        perror("open");
    }
    else
    {
        printf("fd = %d\n", fd);
    }
    while(1)
    {
        len = read(fd,buf,sizeof(buf)-1);
        if(len == -1)
        {
            perror("read");
            close(fd);
            return -1;
        }
        else if(len == 0)
        {
            break;
        }
        else
        {
            buf[len] = '\0';
            printf("%s\n",buf);
        }
    }
    
    close(fd);
    return 0;
}

6.3遇到的错误

 len = read(fd,buf,sizeof(buf)-1);
    if(len == -1)
    {
        perror("read");
        close(fd);
        return -1;
    }
    else
    {
        buf[len] = '\0';
        printf("%s\n",buf);
    }

1.在写sizeof(buf)-1这行代码,写成了sizeo(buf-1),相当于sizeo(-1),也就是一个指针的大小,8个字节,导致输出一直只有8个字母

2.一般使用小缓存buf,加上循环多次read,提高效率。

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值