文件IO常用API

本文详细介绍了Linux系统中的文件IO操作,包括使用open()打开或创建文件、close()关闭文件、read()读取文件内容、write()写入文件以及lseek()设置文件偏移。还讨论了文件描述符的概念和作用,以及与标准IO的区别。示例代码展示了如何实现基本的文件操作,如文件复制。
摘要由CSDN通过智能技术生成

1.相关概念

文件io就是系统调用,不涉及缓冲区,只要执行一次就会调用linux内核的系统调用,然后对硬件设备进行空间

标准IO对文件操作使用文件指针

文件IO对文件操作使用文件描述符

文件描述符:

顺序分配的非负整数

内核用以标识一个特定进程正在访问的文件

进程间通信方式中大多数也是通过文件描述符进行操作的

文件描述符跟文件指针类似,也是用于标识一个文件,对文件操作需要使用文件描述符

当一个程序运行时,操作系统会自动为当前程序创建三个文件描述符

0 标准输入文件描述符

1 标准输出文件描述符

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

2.文件io常用API

2.1 open()/close()

#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_RDONLY 只读
O_WRONLY 只写
O_RDWR   读写
其他标志位:
如果有多个属性,需要用 位逻辑或 连接
O_APPEND  文件存在以追加方式打开文件
O_CREAT   文件不存在则创建
O_EXCL    一般与O_CREAT一起使用 O_EXCL|O_CREAT,如果文件存在则报错,文件不存在则创建
O_TRUNC   如果文件存在则清空
mode:
如果第二个参数指定了O_CREAT,就需要这个参数,否则不需要这个参数主要用于设置当前文件的访问权限,一般使用一个三位的八进制数来设置,分别设置用户主、用户组以及其他用户对当前文件的操作权限,分别设置读、写、执行权限,一般设置为0664
返回值:
成功:
文件描述符
失败:
-1
    
#include <unistd.h>
int close(int fd);
功能:
关闭文件描述符
参数:
fd:
文件描述符
返回值:
成功:
0
失败:
-1

2.2对比fopen和open函数的标志位:

fopen

open

含义

r

O_RDONLY

以只读的方式打开文件,如果文件不存在则报错

r+

O_RDWR

以读写的方式打开文件,如果文件不存在则报错

w

O_WRONLY | O_CREAT | O_TRUNC, 0664

以只写的方式打开文件,如果文件不存在则创建,如果文件存在则清空

w+

O_RDWR | O_CREAT | O_TRUNC, 0664

以读写的方式打开文件,如果文件不存在则创建,如果文件存在则清空

a

O_WRONLY | O_CREAT | O_APPEND, 0664

以只写的方式打开文件,如果文件不存在则创建,如果文件存在则追加

a+

O_RDWR | O_CREAT | O_APPEND, 0664

以读写的方式打开文件,如果文件不存在则创建,如果文件存在则追加

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

#define ERRLOG(errmsg) do{perror(errmsg);return -1;}while(0)

int main(int argc, char const *argv[])
{
    //使用open函数创建或者打开一个文件
    int fd;
    // if((fd = open("file.txt", O_RDONLY)) == -1)
    //if((fd = open("file.txt", O_RDONLY | O_CREAT | O_TRUNC, 0664)) == -1)
    //以只写的方式打开文件,如果文件存在则报错,如果文件不存在则创建
    if((fd = open("file.txt", O_WRONLY | O_EXCL | O_CREAT, 0664)) == -1)
    {
        ERRLOG("open error");
    }
    
    //关闭文件描述符
    close(fd);
    
    return 0;
}

2.3 read()

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:
从文件中读取内容
参数:
fd:
文件描述符
buf:
保存读取的数据
conut:
要读取的字节数
返回值:
成功:
实际读取的字节数
失败:
-1
如果文件读完,返回0

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

#define err_log(err) do{perror(err);return -1;}while(0)

int main(int argc, char const *argv[])
{
    //从终端读取数据
    //现象类似fgets
#if 0
    char buf[32] = {0};
    read(0, buf, 32);
    printf("buf = %s\n", buf);
#endif

    //从文件中读取数据
    int fd;
    if((fd = open(argv[1], O_RDONLY)) == -1)
    {
        err_log("open error");
    }

    //注意:
    //read读取文件内容时,如果文件内容足够,第三个参数是n,就会读取
    //n个字节,不会预留\0的位置,也不会说像fgets一样遇到行结束符就结束

    //一定要注意read的返回值表示实际读取的个数,往往文件最后一次读取的数据
    //都小于第三个参数设置的值

    char buf[32] = {0};
    ssize_t bytes;
    if((bytes = read(fd, buf, 20)) == -1)
    {
        err_log("read error");
    }
    printf("bytes = %ld, buf = [%s]\n", bytes, buf);

    //清空内存区域内容memset bzero
    // memset(buf, 0, sizeof(buf));
    bzero(buf, sizeof(buf));

    if((bytes = read(fd, buf, 20)) == -1)
    {
        err_log("read error");
    }
    printf("bytes = %ld, buf = [%s]\n", bytes, buf);

    close(fd);

    return 0;
}

2.4 write()

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:
向文件写入数据
参数:
fd:
文件描述符
buf:
要写入的数据
conut:
写入的字节数
返回值:
成功:
写入的字节数
失败:
-1

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

int main(int argc, char const *argv[])
{
    //向终端写入数据
    // write(1, "hello world\n", 12);

    //向文件写入数据
    int fd;
    if((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0664)) == -1)
    {
        perror("open error");
        return -1;
    }

    write(fd, "hello world\n", 12);
    write(fd, "nihao beijing\n", strlen("nihao beijing\n"));

    // char buf[32] = {0};
    // read(fd, buf, 32);
    // printf("buf = %s\n", buf);

    return 0;
}

2.5 练习:实现cp命令的功能

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

//练习:实现cp命令的功能

int main(int argc, char const *argv[])
{
    //打开或者创建好两个文件
    int fd_r, fd_w;
    if((fd_r = open(argv[1], O_RDONLY)) == -1)
    {
        perror("open error");
        return -1;
    }

    if((fd_w = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664)) == -1)
    {
        perror("open error");
        return -1;
    }

    //从一个文件中读取数据写入另一个文件
    char buf[32] = {0};
    ssize_t bytes;
    while(1)
    {
        //从源文件中读取数据
        bytes = read(fd_r, buf, sizeof(buf));
        
        //当源文件内容读取完毕,循环结束
        if(bytes == 0)
        {
            break;    
        }

        //将读取到的数据写入到目的文件
        write(fd_w, buf, bytes);
    }

    printf("cp done\n");
    
    return 0;
}

2.6 lseek()

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:
设置或者获取文件定位的偏移值
参数:
fd:
文件描述符
offset:
偏移值,可正可负
whence:
相对位置
SEEK_SET 起始位置
SEEK_CUR 当前位置
SEEK_END 末尾位置
返回值:
成功:
当前修改之后的文件的偏移值
失败:
-1

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

int main(int argc, char const *argv[])
{
    //注意:如果open函数的第二个参数包含O_APPEND,
    //写操作的偏移值是无法改变的,永远都在文件末尾,
    //但是读操作没有影响

    int fd;
    if((fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0664)) == -1)
    {
        perror("open error");
        return -1;
    }

    write(fd, "hello world\n", 12);
    write(fd, "nihao beijing\n", strlen("nihao beijing\n"));

    //获取当前文件的偏移值
    printf("offset = %ld\n", lseek(fd, 0, SEEK_CUR));

    //修改文件的偏移值
    lseek(fd, 0, SEEK_SET);
    printf("offset = %ld\n", lseek(fd, 0, SEEK_CUR));

    char buf[64] = {0};
    read(fd, buf, 64);
    printf("buf = %s\n", buf);

    puts("**********************");
    lseek(fd, -6, SEEK_END);
    printf("offset = %ld\n", lseek(fd, 0, SEEK_CUR));

    write(fd, "123456789\n", strlen("123456789\n"));

    lseek(fd, 0, SEEK_SET);

    memset(buf, 0, 64);
    read(fd, buf, 64);
    printf("buf = %s\n", buf);

    return 0;
}

2.7 文件描述符的创建问题

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

int main(int argc, char const *argv[])
{
    //文件描述符是从小到大依次递增创建的,
    //但是如果有文件描述符关闭,则新创建的文件描述符
    //的值会先等于最小的没有使用的值,然后在依次递增创建
    //所以最后创建的文件描述符不一定是最大的

    int fd1 = open("file.txt", O_RDONLY);
    int fd2 = open("file.txt", O_RDONLY);
    int fd3 = open("file.txt", O_RDONLY);
    int fd4 = open("file.txt", O_RDONLY);
    int fd5 = open("file.txt", O_RDONLY);
    int fd6 = open("file.txt", O_RDONLY);

    printf("fd1 = %d\n", fd1);
    printf("fd2 = %d\n", fd2);
    printf("fd3 = %d\n", fd3);
    printf("fd4 = %d\n", fd4);
    printf("fd5 = %d\n", fd5);
    printf("fd6 = %d\n", fd6);

    close(fd3);

    int fd7 = open("file.txt", O_RDONLY);
    printf("fd7 = %d\n", fd7);
    int fd8 = open("file.txt", O_RDONLY);
    printf("fd8 = %d\n", fd8);
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐的记事本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值