文件理解:从C标准库到系统调用

目录

一、C 标准库文件操作

1. 文件的写入

2. 文件的读取

3. 数据输出到显示器

4. 标准输入输出流

二、C 标准库文件操作模式

三、系统调用文件操作

1. 文件的打开与描述符

2. 文件的读取

3. 文件操作标志

4. 文件权限

5. 文件描述符

四、C 标准库与系统调用的比较

1. 功能对比

2. 底层交互

3. 使用场景


一、C 标准库文件操作

1. 文件的写入

以下是一个使用 C 标准库函数 fwrite 写入文件的示例:

#include <stdio.h>
#include <string.h>

int main() 
{
    FILE *fp = fopen("myfile", "w"); // 以写模式打开文件
    if (!fp) 
    {
        printf("fopen error!\n");
        return 1;
    }
    const char *msg = "hello bit!\n";
    int count = 5;
    while (count--) 
    {
        fwrite(msg, strlen(msg), 1, fp); // 将字符串写入文件
    }
    fclose(fp); // 关闭文件
    return 0;
}
  • fopen 函数用于打开或创建文件。"w" 模式表示以写模式打开文件,如果文件不存在则创建一个新文件,如果文件存在则清空其内容

  • fwrite 函数将指定内存区域的内容写入文件。第一个参数是内存区域的指针,第二个参数是每个元素的大小,第三个参数是元素的数量,第四个参数是文件指针。

  • fclose 函数用于关闭文件,释放与文件相关的资源。

2. 文件的读取

以下是一个使用 C 标准库函数 fread 读取文件的示例:

#include <stdio.h>
#include <string.h>

int main() 
{
    FILE *fp = fopen("myfile", "r"); // 以读模式打开文件
    if (!fp) 
    {
        printf("fopen error!\n");
        return 1;
    }
    char buf[1024];
    const char *msg = "hello bit!\n";
    while (1) 
    {
        ssize_t s = fread(buf, 1, strlen(msg), fp); // 从文件中读取数据到缓冲区
        if (s > 0) 
        {
            buf[s] = 0; // 将缓冲区内容转换为字符串
            printf("%s", buf);
        }
        if (feof(fp)) 
        {   
            // 检查是否到达文件末尾
            break;
        }
    }
    fclose(fp);
    return 0;
}
  • fopen 函数以读模式打开文件。

  • fread 函数从文件中读取数据到指定的缓冲区。第一个参数是缓冲区的指针,第二个参数是每个元素的大小,第三个参数是元素的数量,第四个参数是文件指针。

  • feof 函数用于检查文件是否已到达末尾。

3. 数据输出到显示器

以下是一个使用多种方法将数据输出到显示器的示例:

#include <stdio.h>
#include <string.h>

int main() 
{
    const char *msg = "hello fwrite\n";
    fwrite(msg, strlen(msg), 1, stdout); // 使用 fwrite 输出到标准输出
    printf("hello printf\n"); // 使用 printf 输出
    fprintf(stdout, "hello fprintf\n"); // 使用 fprintf 输出

    return 0;
}
  • stdout 是标准输出流,指向显示器。

  • fwriteprintffprintf 都可以将数据输出到标准输出流。

4. 标准输入输出流

C 语言默认提供三个标准输入输出流:

  • stdin:标准输入流,默认为键盘输入。

  • stdout:标准输出流,默认为显示器输出。

  • stderr:标准错误流,默认为显示器输出。

以下是一个示例:

#include <stdio.h>
#include <string.h>

int main() 
{
    char buf[1024];
    ssize_t s = read(0, buf, sizeof(buf)); // 从标准输入(文件描述符0)读取
    if (s > 0) 
    {
        buf[s] = 0;
        write(1, buf, strlen(buf)); // 写入到标准输出(文件描述符1)
        write(2, buf, strlen(buf)); // 写入到标准错误(文件描述符2)
    }
    return 0;
}
  • 文件描述符 0 对应 stdin

  • 文件描述符 1 对应 stdout

  • 文件描述符 2 对应 stderr

二、C 标准库文件操作模式

C 标准库的 fopen 函数支持多种文件操作模式,以下是一些常见的模式:

模式描述
r打开纯文本文件以只读方式,文件不能不存在。
r+打开纯文本文件用于读/写,文件不能不存在。
w打开纯文本文件用于写覆盖,若文件存在则清空,不存在则创建。
w+打开纯文本文件用于读/写覆盖,若文件存在则清空,不存在则创建。
a打开纯文本文件用于在文件尾部追加写入。
a+打开纯文本文件用于读/写,并在尾部追加新数据。

以下是一个使用 a+ 模式的示例:

#include <stdio.h>

int main() 
{
    FILE *fp = fopen("myfile", "a+"); // 追加写入模式
    if (!fp) 
    {
        printf("fopen error!\n");
        return 1;
    }
    const char *msg = "add new line\n";
    fwrite(msg, strlen(msg), 1, fp);
    fclose(fp);
    return 0;
}
  • a+ 模式表示以读写方式打开文件,并在文件尾部追加新数据。

三、系统调用文件操作

1. 文件的打开与描述符

以下是一个使用系统调用 open 打开文件的示例:

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

int main() 
{
    umask(0); // 设置文件权限掩码
    int fd = open("myfile", O_WRONLY | O_CREAT, 0644); // 打开或创建文件
    if (fd < 0) 
    {
        perror("open");
        return 1;
    }
    const char *msg = "hello bit!\n";
    int len = strlen(msg);
    write(fd, msg, len); // 写入数据到文件
    close(fd); // 关闭文件
    return 0;
}
  • open 函数用于打开或创建文件。第二个参数是标志位,第三个参数是文件权限。

  • O_WRONLY | O_CREAT 表示以只写方式打开文件,如果文件不存在则创建。

  • 0644 是文件权限,表示文件所有者具有读写权限,组用户和其他用户具有只读权限。

  • write 函数将数据写入文件。第一个参数是文件描述符,第二个参数是数据的指针,第三个参数是数据的长度。

  • close 函数用于关闭文件描述符。

2. 文件的读取

以下是一个使用系统调用 read 读取文件的示例:

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

int main() 
{
    int fd = open("myfile", O_RDONLY); // 以只读模式打开文件
    if (fd < 0) {
        perror("open");
        return 1;
    }
    const char *msg = "hello bit!\n";
    char buf[1024];
    ssize_t s = read(fd, buf, strlen(msg)); // 读取文件数据
    if (s > 0) {
        printf("%s", buf);
    }
    close(fd);
    return 0;
}
  • read 函数从文件描述符中读取数据。第一个参数是文件描述符,第二个参数是数据的缓冲区,第三个参数是最大读取长度。

  • 返回值 s 表示实际读取的字节数。

3. 文件操作标志

系统调用 open 的第二个参数是标志位,以下是一些常见的标志位:

标志位描述
O_RDONLY以只读方式打开文件。
O_WRONLY以只写方式打开文件。
O_RDWR以读写方式打开文件。
O_CREAT如果文件不存在则创建。
O_APPEND以追加模式写入。
O_TRUNC如果文件存在,则清空文件内容。
O_EXCL如果使用 O_CREAT 标志时文件已存在,则失败。

4. 文件权限

系统调用 open 的第三个参数是文件权限,使用八进制表示。以下是一些常见的权限位:

权限位描述
0400所有者具有读权限。
0200所有者具有写权限。
0100所有者具有执行权限。
0040组用户具有读权限。
0020组用户具有写权限。
0010组用户具有执行权限。
0004其他用户具有读权限。
0002其他用户具有写权限。
0001其他用户具有执行权限。

5. 文件描述符

  • 文件描述符是一个小整数,由操作系统分配。

  • 程序默认拥有三个文件描述符:

    • 0:标准输入(stdin)。

    • 1:标准输出(stdout)。

    • 2:标准错误(stderr)。

以下是一个使用文件描述符输出数据的示例:

#include <unistd.h>
#include <string.h>

int main() 
{
    char buf[] = "Hello World!\n";
    write(1, buf, strlen(buf)); // 使用文件描述符1(stdout)输出
    return 0;
}
  • write(1, buf, strlen(buf)) 表示将数据写入到标准输出流。

        文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针。本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件 。

四、C 标准库与系统调用的比较

1. 功能对比

功能C 标准库系统调用
文件打开fopenopen
文件读取freadread
文件写入fwritewrite
文件关闭fcloseclose
文件定位fseeklseek
标准输入输出stdin, stdout, stderr文件描述符0、1、2

2. 底层交互

  • C 标准库函数是封装好的函数,内部调用了系统调用。

    • 例如,fopen 是基于 open 实现的。

    • fwrite 是基于 write 实现的。

  • 系统调用直接与操作系统内核交互,执行效率更高,但使用更复杂。

3. 使用场景

  • C 标准库

    • 适合快速开发和处理简单的文件操作。

    • 提供了缓冲机制,数据处理更高效。

  • 系统调用

    • 适合对底层控制要求较高的场景,如设备驱动程序、高性能文件处理等。

    • 对文件描述符的直接操作,灵活性更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南风与鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值