Linux C语言文件操作:从标准IO到文件IO的全面解析

一、Linux文件操作概述

在Linux系统编程中,文件操作是核心技能之一。理解文件操作的本质,需要先明确内存与外存的区别:

  • 内存(变量、数组、数据结构)
    • 读写数据速度快
    • 程序执行结束、掉电后数据丢失
    • 空间小,价格昂贵
  • 文件(外存/硬盘)
    • 读写速度比内存慢
    • 掉电后数据不丢失
    • 空间大,相对内存价格便宜

文件的主要作用有两个:一是长期保存掉电不丢失的数据;二是作为Linux提供给应用层的硬件操作接口,体现了“一切皆文件”的设计哲学。

二、Linux下的文件类型

Linux系统将一切资源都抽象为文件,通过ls -l 文件名命令可以查看文件的详细信息。文件类型由输出行首的第一个字符标识:

  • -:普通文件(regular file),如main.c、xxx.txt、a.out
  • d:目录文件(directory),如文件夹
  • l:软连接文件(link),相当于快捷方式(符号链接)
  • b:块设备文件(block),如硬盘等存储设备
  • c:字符设备文件(character),如鼠标、键盘、显示器
  • s:套接字文件(socket),用于网络编程
  • p:管道文件(pipe),用于进程间通信

三、Linux文件操作方法

Linux下的文件操作主要分为两类:

  1. 标准IO:标准C库提供的文件操作接口,属于库函数
  2. 文件IO:Linux内核提供的文件操作接口,属于系统调用

无论使用哪种方法,文件操作的基本思想都是相同的:

  1. 打开文件
  2. 读文件、写文件
  3. 关闭文件

四、标准IO操作详解

4.1 打开文件:fopen()

#include <stdio.h>

FILE *fopen(const char *pathname, const char *mode);

功能:打开一个文件,并获得一个文件流指针

参数

  • pathname:要打开的文件的文件名
  • mode:打开方式
    • "r":以只读方式打开,文件必须要存在
    • "r+":以读写方式打开,文件必须要存在
    • "w":以只写方式打开,文件不存在则创建,文件存在则清空
    • "w+":以读写方式打开,文件不存在则创建,文件存在则清空
    • "a":以只写方式打开,文件不存在则创建,写时追加写
    • "a+":以读写方式打开,文件不存在则创建,读从开头读,写从末尾写

返回值

  • 成功:FILE*(文件流指针)
  • 失败:NULL

4.2 关闭文件:fclose()

int fclose(FILE *stream);

功能:关闭文件

参数stream:已打开的文件的文件流指针

返回值

  • 成功:0
  • 失败:EOF(-1)

注意只打开文件而使用完不关闭文件,会造成文件描述符泄露。只有 fclose(或 fflush)之后,数据才会从“用户态缓冲区”强制输出到“内核缓冲区”(即操作系统管理的页缓存),从而让其他打开的文件流能够看到它。

4.3 标准流

操作系统默认已打开的三个标准流:

  • stdin:标准输入流,对应标准输入设备(键盘)
  • stdout:标准输出流,对应标准输出设备(显示屏/终端)
  • stderr:标准出错流,对应标准出错设备(显示屏/终端)

4.4 字符读写:fputc()和fgetc()

int fputc(int c, FILE *stream);
int fgetc(FILE *stream);

fputc()功能:向文件中写入一个字符

fgetc()功能:从文件中读取一个字符

注意putchar('a')等价于fputc('a', stdout)

4.5 字符串读写:fputs()和fgets()

int fputs(const char *s, FILE *stream);
char *fgets(char *s, int size, FILE *stream);

fputs()功能:将一个字符串写入到文件,不包括'\0'字符

fgets()功能:从文件中读取一行,遇到新行结束

五、实战示例

5.1 使用fgetc读取文件内容

#include <stdio.h>

int main(int argc, const char *argv[])
{
    if (argc < 2)
    {
        printf("Usage : ./a.out <filename>\n");
        return -1;
    }
    
    FILE *fp = fopen(argv[1], "r");
    if (NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }
    
    int ch;
    while ((ch = fgetc(fp)) != EOF)
    {
        putchar(ch);
    }
    
    fclose(fp);
    return 0;
}

5.2 实现cp命令功能

#include <stdio.h>

int main(int argc, const char *argv[])
{
    if (argc < 3)
    {
        printf("Usage: ./a.out srcfile dstfile\n");
        return -1;
    }
    
    FILE *fpsrc = fopen(argv[1], "r");
    FILE *fpdst = fopen(argv[2], "w");
    
    if (NULL == fpsrc || NULL == fpdst)
    {
        printf("fopen error\n");
        return -1;
    }
    
    int ret = 0;
    while (1)
    {
        ret = fgetc(fpsrc);
        if (EOF == ret)
        {
            break;
        }
        fputc(ret, fpdst);
    }
    
    fclose(fpsrc);
    fclose(fpdst);
    return 0;
}

六、主函数传参

可以在程序运行时,利用命令行参数向主函数传参:

int main(int argc, const char *argv[])
{
    // argc:命令行传递的参数个数
    // argv:保存多个char*类型指针的数组
    // argv[0] ----> "./mycat"
    // argv[1] ----> "1.txt"
    // argv[2] ----> "aaa"
    // ...
}

示例:执行./mycat 1.txt aaa bbb ccc时:

  • argc = 4
  • argv[0] = "./mycat"
  • argv[1] = "1.txt"
  • argv[2] = "aaa"
  • argv[3] = "bbb"
  • argv[4] = "ccc"

七、man手册使用

Linux提供了完善的man手册系统,帮助开发者查阅文档:

  • Linux命令man lsman 1 ls
  • 系统调用man openman 2 open
  • 库函数man fopenman freadman fclose
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值