随笔 - 73, 文章 - 0, 评论 - 2, 阅读 - 44710
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

05文件与IO

Posted on   勇敢的鑫  阅读(107)  评论(0编辑  收藏  举报
这节主要学习了read、write、lseek、目录访问(opendir、readdir、closedir)这几个系统调用及其简单的应用。
一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节

ssize_t read(int fd, void *buf, size_t count);

fd :想要读的文件的文件描述符
buf : 指向内存块的指针,从文件中读取来的字节放到这个内存块中
count : 从该文件复制到buf中的字节个数

返回值

  如果出现错误,返回-1

  读文件结束,返回0

  否则返回从该文件复制到规定的缓冲区中的字节数

 

用write()系统调用将数据写到一个文件中

ssize_t write(int fd, const void *buf, size_t count);

fd:要写入的文件的文件描述符
buf: 指向内存块的指针,从这个内存块中读取数据写入        到文件中
count: 要写入文件的字节个数

返回值

  如果出现错误,返回-1

  如果写入成功,则返回写入到文件中的字节个数

 下面是一个简单的从一个文件中读取内容写入到另一个文件中去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
 
int main(int argc, char *argv[])//这里用传参传入原文件和目标文件
{
    int infd;
    int outfd;
    if (argc != 3)
    {
        fprintf(stderr, "Usage %s src dest\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    infd = open(argv[1], O_RDONLY);//打开原文件
    if (infd == -1)
        ERR_EXIT("open src error");
    //打开目标文件
    if ((outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
        ERR_EXIT("open dest error");
     
    char buf[1024];
    int nread;
    while ((nread = read(infd, buf, 1024)) > 0)
    {
        write(outfd, buf, nread);
    }
 
    close(infd);
    close(outfd);
    return 0;
}

值得注意的是在用完文件描述符后最好的习惯就是关闭,做到随用随关。

要做到文件的随机读写就要涉及到另一个系统调用lseek了:

off_t lseek (int  fd,    off_t offset,   int base);

fd:需设置的文件标识符

ofset:偏移量

base:搜索的起始位置

返回值:返回新的文件偏移值
base有以下几种取值:

base

文件位置

SEEK_SET

从文件开始处计算偏移

SEEK_CUR

从当前文件的偏移值计算偏移

SEEK_END

从文件的结束处计算偏移

看一个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
 
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
 
int main(void)
{
    int fd;
    fd = open("test.txt", O_RDONLY);
    if (fd == -1)
        ERR_EXIT("open error");
 
    char buf[1024] = {0};
    int ret = read(fd, buf, 5);
    if (ret == -1)
        ERR_EXIT("read error");
    printf("buf=%s\n", buf);
     
    ret = lseek(fd, 0, SEEK_CUR);//从当前位置偏移0个量即获取当前偏移位置
    if (ret == -1)
        ERR_EXIT("lseek");
 
    printf("current offset=%d\n", ret);
    return 0;
     
}

下面介绍一下目录的相关操作:

打开一个目录:

DIR*  opendir(char *pathname);

pathname:目录的路径,路径可以是相对的也可以是绝对的

返回值:

  打开成功,返回一个目录指针

  打开失败,则返回0

下面是涉及到访问打开的目录中的一些连接的细节:

struct  dirent*  readdir(DIR  *dirptr);

这里用到了打开目录返回的DIR指针

返回值:

  返回一个指向dirent结构的指针,它包含指定目录中下一个连接的细节;

  没有更多连接时,返回0

当然最后也是一样,打开目录,用完了也要习惯的关闭一下:

int closedir (DIR  *dirptr);

返回值:调用成功返回0,失败返回-1
这里还要介绍一下一个非常重要的结构体:

 struct dirent

  {

      long d_ino;                 

      off_t d_off;                

      unsigned short d_reclen;   

      char d_name [NAME_MAX+1];   //这是我们比较关心和常用的就是目录下的文件名字

  }

下面是一个实现基本ls功能的小程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
 
 
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
 
int main(void)
{
    DIR *dir = opendir(".");  //打开当前目录
    struct dirent *de;      //定义一个包含文件细节的结构题
    while ((de = readdir(dir)) != NULL)  //循环读取目录中的信息
    {
        if (strncmp(de->d_name, ".", 1) == 0)   //这个起到过滤以.开始的文件
            continue;
 
        printf("%s\n", de->d_name);  
    }
 
    closedir(dir);   //最后关闭
    exit(EXIT_SUCCESS);   //和return 0作用类似
}

  

编辑推荐:
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
阅读排行:
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!
· Ai满嘴顺口溜,想考研?浪费我几个小时
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
点击右上角即可分享
微信分享提示