C语言的文件操作(一)

好久没发文章了,这次就讲讲C语言的文件操作吧。

C语言的文件操作主要有两种方式,一种是通过open(2)和close(2)进行的,还有一种是通过fopen(3)和fclose(3)进行的。今天我们就来讲讲用open(2)和close(2)的文件操作,虽然这个用法不常用

目录

open(2)里面的2是什么意思?

文件写入

示例代码

open(2)函数

write(2)函数

close(2)函数

perror(3)函数

读取文件

示例代码

read(2)函数

总结


open(2)里面的2是什么意思?

有些人可能就迷糊了,open(2)里面的2是什么意思?

这里面的2是在man指令查看帮助时在"open"之前输入的,即

man 2 open

我之前说过,man指令可以查看帮助,当我们输入man man时,就可以看到man的使用方法,我们不妨从这里找到答案

首先我们可以看到这句话

man - format and display the on-line manual pages

意思是说:man命令可以格式化和显示在线帮助页面

在简介一栏里,我们可以看到man的参数

man  [-acdfFhkKtwW]  [--path]  [-m  system]  [-p string] [-C con-
       fig_file] [-M pathlist] [-P pager] [-B  browser]  [-H  htmlpager]
       [-S section_list] [section] name ...

在描述一栏里,我们可以看到man的粗略使用方法

man  formats and displays the on-line manual pages.
If you specify section, man only looks in that section of the manual.   
name is  normally  the name of the manual page, which is typically the name of a command, function, or file.  
However, if name  contains  a  slash  (/)  then man interprets it as a file specification, so that you can do man ./foo.5 or even man /cd/foo/bar.1.gz.

意思是:man格式化并显示在线手册页面。如果您指定section参数,man只查看手册的该章节。name参数通常是手册页面的名称,通常是命令、函数或文件的名称。然而,如果名称包含斜杠(/),则man将其解释为文件规范,以便您可以执行man /foo.5甚至是man /cd/foo/bar.1.gz。

综上,我们可以知道,“2”是section参数,“open”是name参数

那么,section参数怎么用呢?

section参数中,我最常使用的是1(系统命令)、2(系统函数)、3(库函数)

open(2)函数属于系统函数,而fopen(3)属于库函数

扯了这么多,还没讲文件读写呢

文件写入

示例代码

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

int main(void){
        // 创建文件
        // 文件名:test
        // 读取方式:只写。如果没有文件就新建一个
        // 权限:有且只有用户读写权限
        int des = open("test", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
        // 判断异常
        if(des == -1){
                perror("open");
                return -1;
        }
        char data[] = "Hello World"; // 定义字符串
        // 写入数据
        int err = write(des, data, (strlen(data) + 1));
        if(err == -1){
                perror("write");
                return -1;
        }
        // 关闭文件
        err = close(des);
        if(err == -1){
                perror("close");
                return -1;
        }
        return 0;
}

接下来我们来解释一下这段代码

由于我英语水平有限,man文档的有些地方看不懂,讲的有误的望指正 

open(2)函数

首先我们来看open(2)函数的原形

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

没错,open(2)函数有两个原形,难道C语言也可以函数重载了吗?

其实,这并不是真正的函数重载。我们可以通过好几种方法实现假的函数重载,主要原理是使用可变参数个数

这里面主要有3个参数,我们全部使用了

第一个参数pathname,是文件名

第二个参数flags,规定了读写方式。必须包括O_RDONLY(只读)或O_WRONLY(只写)或O_RDWR(读或写)。这个参数比较奇怪,可以通过"|"相连。系统函数真是高深啊!

这个参数我写的是     O_WRONLY|O_CREAT     ,O_CREAT表示如果没有文件就创建一个新的

第三个参数mode,规定了权限。文件权限有:

当前用户权限、当前用户组权限、其他用户的权限。每个权限又有读(r)、写(w)、执行(x),我们可以通过ls -l 查看权限

-rw-------

这表示当前用户可读写

这个参数可以有

S_IRWXU    当前用户可读、可写、可执行

S_IRUSR    当前用户可读

S_IWUSR    当前用户可写

S_IXUSR    当前用户可执行

S_IRWXG    当前用户组可读、可写、可执行

S_IRGRP    当前用户组可读

S_IWGRP    当前用户组可写

S_IXGRP    当前用户组可执行

S_IRWXO    其他用户可读、可写、可执行

S_IROTH     其他用户可读

S_IWOTH     其他用户可写

S_IXOTH     其他用户可执行

同样,这个参数也可以用"|"连接

注意,如果文件已存在,mode参数不会有作用,而且,mode参数必须和O_CREAT一起用。

讲完参数,该将返回值了。如果成功,这个返回值是一个描述符(descriptor),也就是一个供系统调用的非负整数。并且,函数运行时会产生一个描述(description),也就是一个打开的文件的条目,存储在系统范围表(system-wide table)中。

write(2)函数

先看原形

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

第一个参数fd,是描述符(descriptor)

第二个参数buf,是一个指针类型的变量,从这个指针存(指向)的地址开始,取第三个参数count长度

如果函数返回-1,就说明出错了。否则程序返回写入的长度

close(2)函数

先看原形

int close(int fd);

参数fd就是描述符(descriptor)

如果成功,返回0,否则返回-1

perror(3)函数

这个函数我就简单讲讲

perror(3)函数接收一个参数,是函数名,它会输出这个函数报的错。前提是这个函数得先出错,而且在man文档里提到了出错会改变errno的值

读取文件

示例代码

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

int main(void){
        // 创建文件
        // 文件名:test
        // 读取方式:只读
        int des = open("test", O_RDONLY);
        // 判断异常
        if(des == -1){
                perror("open");
                return -1;
        }
        char data[12]; // 定义字符串
        // 读取数据
        int err = read(des, data, 12);
        if(err == -1){
                perror("read");
                return -1;
        }
        printf("%s\n", data);
        // 关闭文件
        err = close(des);
        if(err == -1){
                perror("close");
                return -1;
        }
        return 0;
}

read(2)函数

这个函数的原形是这样的

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

跟write(2)很向,只不过是从fd这个描述符(descriptor)读取count长度的数据,并存入buf指定(指向)的地址里。当然,这个地址要流出足够的空间。可以采用malloc(3)动态分配,或者直接采用数组。

总结

这个操作总体来看比较繁琐,但这确是Linux文件的最基础操作,也是网络编程的重要一环。Windows也是可以使用的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值