<文件编程>

本文详细介绍了在Linux系统中如何进行文件的打开、创建、写入、读取和光标移动操作,包括使用`open`、`creat`函数创建和打开文件,以及`write`、`read`函数进行数据的读写。此外,还讨论了权限控制和文件描述符的概念,并对比了标准C库中的文件操作方法。
摘要由CSDN通过智能技术生成

文件的打开及创建

打开文件

#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_CREAT 若文件不存在则创建它。同时必须在mode参数附加文件存取许可权限。
  • O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。
  • O_APPEND 每次写时都加到文件的尾端。
  • O_TRUNC 打开文件时,如果这个文件中本来是有内容的,而且为只读或者只写成功打开,则将其长度揭短为0

mode:一定是在flag中使用了O_CREAT标志,mode主要记录待创建文件的访问权限
返回值: 返回的是一个文件描述符,一个小的非负整数
权限简介:

  • Linux系统上对文件的权限有着严格的控制,如果想对某个文件执行某种操作,必须具有对应的权限方可执行成功。
  • Linux下文件的权限类型一般包括读,写,执行。对应字母为 r、w、x。
  • Linux下权限的粒度有 拥有者 、群组 、其它组 三种。每个文件都可以针对三个粒度,设置不同的rwx(读写执行)权限。通常情况下,一个文件只能归属于一个用户和组, 如果其它的用户想有这个文件的权限,则可以将该用户加入具备权限的群组,一个用户可以同时归属于多个组;r 4;w 2;x 1;模式的参数必须按这样写才能起到对三个粒度的权限控制
    参数为00400为仅可读
    参数为00200为仅可写
    参数为00100为可执行
    可读可写可执行为00700

    demo1
    可读可写方式打开文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd;
    fd = open("./file",O_RDWR);  //打开文件
    printf("fd = %d\n",fd);	    //输出文件描述符
    return 0;
}

demo2
打开文件,如果文件不存在,创建该文件

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

int main()
{
    int fd;
    fd = open("./file",O_RDWR);  //打开文件
    if(fd==-1){
        printf("open file failed\n");
        fd  = open("./file",O_RDWR|O_CREAT,0600);   //创建文件
        if(fd>0){
                 printf("Create file success\n");
        }
    }

    return 0;
}

创建文件

一般不用该函数,一般为open

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

int creat(const char *pathname, mode_t mode);

pathname  :要打开的文件名
mode:一定是在flag中使用了O_CREAT标志,mode主要记录待创建文件的访问权限

  • S_IRUSR 4 可读
  • S_IWUSR 2 可写
  • S_IXUSR 1 可执行
  • S_IRWXU 7 可读可写可执行
    这里mode的参数也可以使用上面open中的mode参数
    demo
    创建一个文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//创建文件
int main()
{
    int fd;
    fd = creat("./file2temp",S_IRWXU);  //创建一个文件,权限为可读可写可执行
    printf("%d\n",fd);
    return 0;
}

一些文件的打开及创建的测试demo

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//判断文件是否存在,如果不存在则会创建文件
int main()
{
    int fd;
    fd = open("./file",O_RDWR|O_CREAT|O_EXCL,0600);

    if(fd==-1){
        printf("file exist\n");
    }

    return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//每次写为在文件末尾出增加
int main()
{
    int fd;
    char *buf = "写测试。。";
    fd = open("./file",O_RDWR|O_APPEND);

    write(fd,buf,strlen(buf));
    return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//清除原来文本内容重新写
int main()
{
    int fd;
    char *buf = "写测试。。";
    fd = open("./file",O_RDWR|O_TRUNC);

    write(fd,buf,strlen(buf));
    return 0;
}

文件写入操作

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

fd:文件描述符
buf:需要写的内容
count:待写入的字节个数
返回:读取到的个数,一般0为失败

demo

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main()
{
    int fd;
    char *buf = "写测试。。";
    fd = open("./file",O_RDWR);
    if(fd==-1){
        printf("open file failed\n");
        fd  = open("./file",O_RDWR|O_CREAT,0600);
        if(fd>0){
                 printf("Create file success\n");
        }
    }

    printf("open success : fd = %d\n",fd);
    int n_wrte =  write(fd,buf,strlen(buf));
    if(n_wrte>0){
        printf("write %d byte success",n_wrte);
    }
    else
        perror("write");
    close(fd);
    return 0;
}

文件读取操作

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

fd:文件描述符
buf:待读取缓冲区
count:读取个数
返回:读取到的个数,一般0为失败

demo
从文件中读取

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

int main()
{
    int fd;
    char *buf = "写测试。。";
    fd = open("./file",O_RDWR);
    if(fd==-1){
        printf("open file failed\n");
        fd  = open("./file",O_RDWR|O_CREAT,0600);
        if(fd>0){
                 printf("Create file success\n");
        }
    }

    printf("open success : fd = %d\n",fd);
    int n_write = write(fd,buf,strlen(buf));

    if(n_write!=-1){
        printf("write %d byte to file\n",n_write);
    }
    close(fd);

//这里必须重新打开或者重置光标
    fd = open("./file",O_RDWR);
    char *readbuf;
    readbuf = (char *)malloc(sizeof(char)*n_write+1);
    int n_read = read(fd,readbuf,n_write);
    printf("read %d,context:%s\n",n_read,readbuf);
    close(fd);
    return 0;
}

文件光标移动操作

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

fd:文件描述符
offset:偏移量
whence:从何处写

  • SEEK_SET:要偏移的个数等于offset
  • SEEK_CUR:当前位置加上offset
  • SEEK_END:文件大小加上偏移字节

返回:成功偏移的字节数

demo
测试文件大小

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

//计算文件大小
int main()
{
    int fd;
    fd = open("./file",O_RDWR);

    int filesize = lseek(fd,0,SEEK_END); 
    printf("fize size is %d\n",filesize);
    close(fd);
    return 0;
}

文件操作原理简述

虚拟空间地址/PCB进程控制块/文件描述符表
对于每一个进程,系统都会为其分配一个0-4G的虚拟空间地址,0-3G为用户空间,用户可操作部分。3~4G为内核,其中PCB控制块也存在内核中(补充:每一个进程都有一个PCB)PCB结构体包括文件标识符表以及其他很多信息。

文件描述符表,结构体 PCB 的成员变量 file_struct *file 指向文件描述符表。从应用程序使用角度,该指针可理解记忆成一个字符指针数组,下标 0/1/2/3/4…找到文件结构体。本质是一个键值对 0、1、2…都分别对应具体地址。但键值对使用的特性是自动映射,我们只操作键不直接使用值。新打开文件返回文件描述符表中未使用的最小文件描述符。

在这里插入图片描述
在这里插入图片描述

与标准C库的区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

补充-linux man 1 2 3的作用

1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9 其他(Linux特定的), 用来存放内核例行程序的文档。

例如
man 1 ls
man 2 open
man 3 printf

标准c库实现linux内核态的读写操作

打开文件函数

 #include <stdio.h>
 FILE *fopen(const char *pathname, const char *mode);

pathname:文件路径
mode:模式

  • r 只读方式打开一个文本文件
  • r+ 可读可写方式打开一个文本文件
  • w 只写方式打开一个文本文件 (w没有就创建)
  • w+ 可读可写方式创建一个文本文件
  • wb 只写方式打开一个二进制文件
  • a 追加方式打开一个文本文件
  • ab 追加方式打开一个二进制文件
  • rb 只读方式打开一个二进制文件
  • rb+ 可读可写方式打开一个二进制文件
  • wb+ 可读可写方式生成一个二进制文件
  • a+ 可读可写追加方式打开一个文本文件
  • b+ 可读可写方式追加一个二进制文件

返回值:返回一个文件指针

写文件函数

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

ptr:写入内容的指针
size:一次写多少个字符
nmemb:字符个数
stream:which file
返回值:返回写入的个数

读文件函数

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

ptr:读入内容的指针
size:一次读多少个字符
nmemb:字符个数
stream:which file
返回值:返回读入的个数

光标移动函数

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

stream:which file
offset:偏移量
whence:从何处写

  • SEEK_SET:要偏移的个数等于offset
  • SEEK_CUR:当前位置加上offset
  • SEEK_END:文件大小加上偏移字节
    返回值:返回偏移的个数

读写测试

#include <stdio.h>
#include <string.h>
// FILE *fopen(const char *pathname, const char *mode);
int main()
{
    FILE *fp;
    char *str = "write read testing";
    char readbuf[128]={0};
    fp = fopen("./file3","w+");

    fwrite(str,sizeof(char),strlen(str),fp);
    fseek(fp,0,SEEK_SET);
    int n_read = fread(readbuf,sizeof(char),strlen(str),fp);

    printf("read %d byte,context:%s\n",n_read,readbuf);
    fclose(fp);

}

写入一个字符

#include <stdio.h>
int fputc(int c, FILE *stream);

c:待写入的字符
stream:which file
返回值:返回写入成功字符

读出一个字符

#include <stdio.h>
int fgetc(FILE *stream);

FILE :which file
返回值:返回读出成功字符

检查光标是否到达文件末尾

#include <stdio.h>
int feof(FILE *stream);

FILE :which file
返回值:是为大于0的数,否为0
demo
读取字符串

#include <stdio.h>
#include <string.h>
// FILE *fopen(const char *pathname, const char *mode);
int main()
{
    FILE *fp;
    char readbuf[128]={0};
    char dat = 0;
    fp = fopen("./file3","a+");

    fseek(fp,0,SEEK_SET);
    while(!feof(fp))
    {
           dat =  fgetc(fp);
           printf("%c",dat);
    }
    printf("\nread ok\n");
    fclose(fp);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值