Linux文件编程(open read write close函数)


前言

本篇文章我们来讲解Linux中的文件编程,这篇文章会先介绍open read write函数。

一、open函数

open 函数是一个在 POSIX 标准中定义的函数,用于打开文件或者创建新文件。它是文件操作中很常用的一个函数,主要用于在程序中访问文件系统。

下面是 open 函数的原型:

#include <fcntl.h>

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

参数说明:

pathname:要打开或创建的文件路径名。

flags:文件打开的标志,用来指定打开方式和操作权限。

mode:新创建文件的权限(仅在创建新文件时有效)。

open 函数返回一个非负整数,称为文件描述符,它是用于标识打开文件的唯一值。如果函数执行失败,则返回 -1,表示出错。

下面是一些常用的 flags 参数的取值:

O_RDONLY:只读方式打开文件。
O_WRONLY:只写方式打开文件。
O_RDWR:读写方式打开文件。
O_CREAT:如果文件不存在,则创建文件。
O_APPEND:追加方式打开文件,写入内容会追加到文件末尾。
O_TRUNC:如果文件存在,将其内容截断为0,即清空文件。

下面是一些常用的 mode 参数的取值:

S_IRUSR:用户具有读权限。
S_IWUSR:用户具有写权限。
S_IXUSR:用户具有执行权限。
S_IRGRP:用户组具有读权限。
S_IWGRP:用户组具有写权限。
S_IXGRP:用户组具有执行权限。
S_IROTH:其他用户具有读权限。
S_IWOTH:其他用户具有写权限。
S_IXOTH:其他用户具有执行权限。

当前目录下不存在1.txt文件,我们使用open函数来创建并打开一个1.txt文件:
在这里插入图片描述

示例代码:

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

int main(void)
{
    int fd = 0;

    fd = open("1.txt", O_RDWR | O_CREAT);

    if(fd == -1)
    {
        printf("open 1.txt is err\n");
        return -1;
    }

    return 0;
}


运行结果:
在这里插入图片描述
在这里我们可以看到整个文件是红色的,因为我们在创建时没有给任何权限,那么这里我们在创建文件时给这个文件一些权限:

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

int main(void)
{
    int fd = 0;

    fd = open("1.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);

    if(fd == -1)
    {
        printf("open 1.txt is err\n");
        return -1;
    }

    return 0;
}


在这里插入图片描述

二、read函数

read 函数是一个系统调用,用于从已打开文件的文件描述符中读取数据。它的原型如下:

#include <unistd.h>

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

参数解释:

fd 是文件描述符,指定要读取数据的文件或设备。

buffer 是一个指针,指向用于存储读取数据的缓冲区。

count 是要读取的字节数,指定要从文件中读取的数据量。

read 函数从文件描述符指定的文件位置开始读取数据,并将其存储到提供的缓冲区中。它返回实际读取的字节数。如果 read 函数返回0,表示已到达文件末尾。如果返回负值,表示读取出错,具体的错误码会存储在全局变量 errno 中供用户程序查询。

使用 read 函数时,需要注意以下几点:

1.在调用 read 之前,应确保文件已经被成功打开并获得有效的文件描述符。

2.缓冲区的大小应足够大,以容纳要读取的数据。

3.返回的字节数可能小于请求的字节数 count,特别是在读取非阻塞文件描述符时,这是正常的情况。

4.多次调用 read 函数可以连续读取更多的数据,直到返回值为0,表示已读取完文件。

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

int main(void)
{
    int fd = 0;
    char buf[1024];
    int len = 0;

    fd = open("1.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); //打开文件,如果不存在则创建文件为可读可写

    if(fd == -1)
    {
        printf("open 1.txt is err\n");
        return -1;
    }

    len = read(fd, buf, 1024);

    if(len != -1)
    {
        printf("read buf : %s len : %d\n", buf, len);
    }

    return 0;
}


先在vi编辑器中修改文件中的内容:
在这里插入图片描述
运行结果:
在这里插入图片描述

三、write函数

write 函数是一个系统调用,用于将数据写入已打开文件的文件描述符中。它的原型如下:

#include <unistd.h>

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

参数解释:

fd 是文件描述符,指定要写入数据的文件或设备。
buffer 是一个指针,指向包含要写入的数据的缓冲区。
count 是要写入的字节数,指定要写入的数据量。
write 函数将 count 字节的数据从 buffer 中写入到文件描述符指定的文件中。它返回实际写入的字节数。如果返回负值,表示写入出错,具体的错误码会存储在全局变量 errno 中供用户程序查询。

使用 write 函数时,需要注意以下几点:

1.在调用 write 之前,应确保文件已经被成功打开并获得有效的文件描述符。

2.缓冲区中至少包含 count 字节的数据。

3.返回的字节数可能小于请求的字节数 count,特别是在写入非阻塞文件描述符时,这是正常的情况。

4.可以多次调用 write 函数来连续写入更多的数据。

示例代码:

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

int main(void)
{
    int fd = 0;
    char buf[1024];
    int len = 0;

    fd = open("1.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); //打开文件,如果不存在则创建文件为可读可写,并且将文件内容全部清除

    if(fd == -1)
    {
        printf("open 1.txt is err\n");
        return -1;
    }

    len = write(fd, "Hello", 6);
    if(len == -1)
    {
        printf("write err\n");
    }

    lseek(fd, 0, SEEK_SET);

    len = read(fd, buf, 1024);

    if(len != -1)
    {
        printf("read buf : %s len : %d\n", buf, len);
    }

    return 0;
}


运行结果:
在这里插入图片描述

四、open read write函数本质

当调用 open、read、write 等文件相关的函数时,通常会触发系统调用(syscall),进入操作系统内核执行相应的操作。系统调用是用户程序与操作系统之间的接口,允许用户程序请求操作系统提供的服务和资源。

在执行系统调用时,用户程序通过特殊的指令(例如 x86 架构上的 int 0x80 或 syscall 指令)将控制权转移到操作系统内核。操作系统根据系统调用号识别用户请求的具体服务,并执行相应的操作。

系统调用的执行通常会引起特权转换(从用户模式切换到内核模式),因为内核需要访问受保护的资源和执行特权指令。在这个过程中,会触发一个异常(如 ARM 架构中的 SVC 异常),将控制权转移到内核中的异常处理程序。

异常处理程序在内核中执行所需的操作,例如打开文件、读写文件等。一旦操作完成,控制权将返回到用户程序,继续执行后续的指令。

因此,当调用 open、read、write 等文件相关函数时,通常会触发 SVC 异常,并进入内核执行相应的文件操作。

五、close函数

close 函数用于关闭打开的文件描述符。在使用完文件后,应该调用 close 函数来释放系统资源并确保数据的完整性。

函数原型如下:

#include <unistd.h>

int close(int fd);

其中,fd 是需要关闭的文件描述符。如果关闭成功,返回值为0;如果发生错误,返回值为-1。

close 函数的主要作用如下:

1.释放文件描述符:调用 close 函数会释放文件描述符,并使其可供其他程序使用。这是一种良好的资源管理实践,避免文件描述符的浪费。

2.刷新缓冲区:在关闭文件之前,close 函数会自动刷新文件的缓冲区,确保所有的数据都被写入到磁盘中。这样可以避免数据的丢失或不一致。

3.断开与文件的连接:通过关闭文件描述符,close 函数会断开程序与文件之间的连接,不再对文件进行读写操作。这是确保文件的安全性以及其他进程能够访问文件的重要步骤。

总结

本篇文章就讲解到这里,下篇文章继续讲解Linux文件编程。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
LINUX C函数库API 1.字符测试篇 15 1.1 15 isalnum(测试字符是否为英文或数字) 15 1.2 15 isalpha (测试字符是否为英文字母) 15 1.3 16 isascii(测试字符是否为ASCII 码字符) 16 1.4 17 iscntrl(测试字符是否为ASCII 码的控制字符) 17 1.5 17 isdigit(测试字符是否为阿拉伯数字) 17 1.6 17 isgraphis(测试字符是否为可打印字符) 17 1.7 18 islower(测试字符是否为小写字母) 18 1.8 18 isprint(测试字符是(否为可打印字符) 18 1.9 19 isspace(测试字符是否为空格字符) 19 1.10 20 ispunct(测试字符是否为标点符号或特殊符号) 20 1.11 20 isupper(测试字符是否为大写英文字母) 20 1.12 21 isxdigit(测试字符是否为16进制数字) 21 2.字符串转换篇 21 2.1 21 atof(将字符串转换成浮点型数) 21 2.2 22 atoi(将字符串转换成整型数) 22 2.3 22 atol(将字符串转换成长整型数) 22 2.4 23 gcvt(将浮点型数转换为字符串,取四舍五入) 23 2.5 24 strtod(将字符串转换成浮点数) 24 2.6 24 strtol(将字符串转换成长整型数) 24 2.7 25 strtoul(将字符串转换成无符号长整型数) 25 2.8 25 toascii(将整型数转换成合法的ASCII 码字符) 25 2.9 26 tolower(将大写字母转换成小写字母) 26 2.10 26 toupper(将小写字母转换成大写字母) 26 3.内存控制篇 27 3.1 27 calloc(配置内存空间) 27 3.2 28 free(释放原先配置的内存) 28 3.3 28 getpagesize(取得内存分页大小) 28 3.4 28 malloc(配置内存空间) 28 3.5 28 mmap(建立内存映射) 28 3.6 30 munmap(解除内存映射) 30 4.日期时间篇 31 4.1 31 asctime(将时间和日期以字符串格式表示) 31 4.2 31 ctime(将时间和日期以字符串格式表示) 31 4.3 32 gettimeofday(取得目前的时间) 32 4.4 33 gmtime(取得目前时间和日期) 33 4.5 34 localtime(取得当地目前时间和日期) 34 4.6 34 mktime(将时间结构数据转换成经过的秒数) 34 4.7 35 settimeofday(设置目前时间) 35 4.8 35 time(取得目前的时间) 35 5.内存及字符串操作篇 36 5.1 36 bcmp(比较内存内容) 36 5.2 36 bcopy(拷贝内存内容) 36 5.3 37 bzero(将一段内存内容全清为零) 37 5.4 37 index(查找字符串中第一个出现的指定字符) 37 5.5. 37 memccpy(拷贝内存内容) 37 5.6 38 memchr(在某一内存范围中查找一特定字符) 38 5.7 38 memcmp(比较内存内容) 38 5.8 39 memcpy(拷贝内存内容) 39 5.9 40 memmove(拷贝内存内容) 40 5.10 40 memset(将一段内存空间填入某值) 40 5.11 40 rindex(查找字符串中最后一个出现的指定字符) 40 5.12 41 strcasecmp(忽略大小写比较字符串) 41 5.13 41 strcat(连接两字符串) 41 5.14 42 strchr(查找字符串中第一个出现的指定字符) 42 5.15 42 strcmp(比较字符串) 42 5.16 43 strcoll(采用目前区域的字符排列次序来比较字符串) 43 5.17 43 strcpy(拷贝字符串) 43 5.18 44 strcspn(返回字符串中连续不含指定字符串内容的字符数) 44 5.19 44 strdup(复制字符串) 44 5.20 45 strlen(返回字符串长度) 45 5.21 45 strncasecmp(忽略大小写比较字符串) 45 5.22 46 strncat(连接两字符串) 46 5.23 46 strncpy(拷贝字符串) 46 5.24 47 strpbrk(查找字符串中第一个出现的指定字符) 47 5.25 47 strrchr(查找字符串中最后出现的指定字符) 47 5.26 47 strspn(返回字符串中连续不含指定字符串内容的字符数) 47 5.27 48 strstr(在一字符串中查找指定的字符串) 48 5.28 48 strtok(分割字符串) 48 6. 常用数学函数篇 49 6.1 49 abs(计算整型数的绝对值) 49 6.2 49 acos(取反余弦函数数值) 49 6.3 50 asin(取反正弦函数值) 50 6.4 50 atan(取反正切函数值) 50 6.5 51 atan2(取得反正切函数值) 51 6.6 51 ceil(取不小于参数的最小整型数) 51 6.7 52 cos(取余玄函数值) 52 6.8 52 cosh(取双曲线余玄函数值) 52 6.9 53 exp(计算指数) 53 6.10 53 frexp(将浮点型数分为底数与指数) 53 6.11 54 ldexp(计算2的次方值) 54 6.12 54 log(计算以e 为底的对数值) 54 6.13 55 log10(计算以10 为底的对数值) 55 6.14 55 pow(计算次方值) 55 6.15 56 sin(取正玄函数值) 56 6.16 56 sinh(取双曲线正玄函数值) 56 6.17 56 sqrt(计算平方根值) 56 6.18 57 tan(取正切函数值) 57 6.19 57 tanh(取双曲线正切函数值) 57 7.用户组篇 58 7.1 58 endgrent(关闭组文件) 58 7.2 58 endpwent(关闭密码文件) 58 7.3 58 endutent(关闭utmp 文件) 58 7.4 59 fgetgrent(从指定的文件来读取组格式) 59 7.5 60 fgetpwent(从指定的文件来读取密码格式) 60 7.6 61 getegid(取得有效的组识别码) 61 7.7 61 geteuid(取得有效的用户识别码) 61 7.8 62 getgid(取得真实的组识别码) 62 7.9 62 getgrent(从组文件中取得账号的数据) 62 7.10 63 getgrgid(从组文件中取得指定gid 的数据) 63 7.11 64 getgrnam(从组文件中取得指定组的数据) 64 7.12 64 getgroups(取得组代码) 64 7.13 65 getpw(取得指定用户的密码文件数据) 65 7.14 66 getpwent(从密码文件中取得账号的数据) 66 7.15 67 getpwnam(从密码文件中取得指定账号的数据) 67 7.16 68 getpwuid(从密码文件中取得指定uid 的数据) 68 7.17 68 getuid(取得真实的用户识别码) 68 7.18 69 getutent(从utmp 文件中取得账号登录数据) 69 7.19 70 getutid(从utmp 文件中查找特定的记录) 70 7.20 71 getutline(从utmp 文件中查找特定的记录) 71 7.21 71 initgroups(初始化组清单) 71 7.22 71 pututline(将utmp 记录写入文件) 71 7.23 72 seteuid(设置有效的用户识别码) 72 7.24 72 setfsgid(设置文件系统的组识别码) 72 7.25 73 setfsuid(设置文件系统的用户识别码) 73 7.26 73 setgid(设置真实的组识别码) 73 7.27 73 setgrent(从头读取组文件中的组数据) 73 7.28 74 setgroups(设置组代码) 74 7.29 74 setpwent(从头读取密码文件中的账号数据) 74 7.30 75 setregid(设置真实及有效的组识别码) 75 7.31 75 setreuid(设置真实及有效的用户识别码) 75 7.32 75 setuid(设置真实的用户识别码) 75 7.33 76 setutent(从头读取utmp 文件中的登录数据) 76 7.34 76 utmpname(设置utmp 文件路径) 76 8.数据结构和算法篇 76 8.1 76 crypt(将密码或数据编码) 76 8.2 77 bsearch(二元搜索) 77 8.3 78 lfind(线性搜索) 78 8.4 79 lsearch(线性搜索) 79 8.5 80 qsort(利用快速排序法排列数组) 80 8.6 81 rand(产生随机数) 81 8.7 81 srand(设置随机数种子) 81 9 文件操作篇 82 9.1 82 close(关闭文件) 82 9.2 82 creat(建立文件) 82 9.3 83 dup(复制文件描述词) 83 9.4 83 dup2(复制文件描述词) 83 9.5 84 fcntl(文件描述词操作) 84 9.6 85 flock(锁定文件或解除锁定) 85 9.7 85 fsync(将缓冲区数据写回磁盘) 85 9.8 85 lseek(移动文件的读写位置) 85 9.9 86 mkstemp(建立唯一的临时文件) 86 9.10 86 open(打开文件) 86 9.11 88 read(由已打开的文件读取数据) 88 9.12 89 sync(将缓冲区数据写回磁盘) 89 9.13 89 write(将数据写入已打开的文件内) 89 10 文件内容操作篇 89 10.1 89 clearerr(清除文件流的错误旗标) 89 10.2 90 fclose(关闭文件) 90 10.3 90 fdopen(将文件描述词转为文件指针) 90 10.4 90 feof(检查文件流是否读到了文件尾) 90 10.5 91 fflush(更新缓冲区) 91 10.6 91 fgetc(由文件中读取一个字符) 91 10.7 91 fgets(由文件中读取一字符串) 91 10.8 92 fileno(返回文件流所使用的文件描述词) 92 10.9 92 fopen(打开文件) 92 10.10 93 fputc(将一指定字符写入文件流中) 93 10.11 94 fputs(将一指定的字符串写入文件内) 94 10.12 94 fread(从文件流读取数据) 94 10.13 95 freopen(打开文件) 95 10.14 95 fseek(移动文件流的读写位置) 95 10.15 96 ftell(取得文件流的读取位置) 96 10.16 96 fwrite(将数据写至文件流) 96 10.17 97 getc(由文件中读取一个字符) 97 10.18 97 getchar(由标准输入设备内读进一字符) 97 10.19 98 gets(由标准输入设备内读进一字符串) 98 10.20 98 mktemp(产生唯一的临时文件名) 98 10.21 99 putc(将一指定字符写入文件中) 99 10.22 99 putchar(将指定的字符写到标准输出设备) 99 10.23 99 rewind(重设文件流的读写位置为文件开头) 99 10.24 99 setbuf(设置文件流的缓冲区) 99 10.25 100 setbuffer(设置文件流的缓冲区) 100 10.26 100 setlinebuf(设置文件流为线性缓冲区) 100 10.27 100 setvbuf(设置文件流的缓冲区) 100 10.28 101 ungetc(将指定字符写回文件流中) 101 11 进程操作篇 101 11.1 101 atexit(设置程序正常结束前调用的函数) 101 11.2 101 execl(执行文件) 101 11.3 102 execlp(从PATH 环境变量中查找文件并执行) 102 11.4 102 execv(执行文件) 102 11.5 103 execve(执行文件) 103 11.6 104 execvp(执行文件) 104 11.7 104 exit(正常结束进程) 104 11.8 104 _exit(结束进程执行) 104 11.9 105 vfork(建立一个新的进程) 105 11.10 105 getpgid(取得进程组识别码) 105 11.11 106 getpgrp(取得进程组识别码) 106 11.12 106 getpid(取得进程识别码) 106 11.13 107 getppid(取得父进程的进程识别码) 107 11.14 107 getpriority(取得程序进程执行优先权) 107 11.15 108 nice(改变进程优先顺序) 108 11.16 108 on_exit(设置程序正常结束前调用的函数) 108 11.17 109 setpgid(设置进程组识别码) 109 11.18 109 setpgrp(设置进程组识别码) 109 11.19 109 setpriority(设置程序进程执行优先权) 109 11.20 110 system(执行shell 命令) 110 11.21 110 wait(等待子进程中断或结束) 110 11.22 111 waitpid(等待子进程中断或结束) 111 11.23 112 fprintf(格式化输出数据至文件) 112 11.24 112 fscanf(格式化字符串输入) 112 ... ... ... ...
这些函数都是Linux系统调用,用于在用户空间程序和内核空间之间进行数据传输、设备控制等操作。 1. open(): 打开一个文件或设备,返回该文件或设备的文件描述符,该描述符用于后续的读、写、控制和关闭操作。语法如下: ``` #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); ``` 2. close(): 关闭一个文件或设备,释放该文件或设备占用的系统资源。语法如下: ``` #include <unistd.h> int close(int fd); ``` 3. read(): 从一个文件或设备中读取数据到指定的缓冲区中,返回实际读取的字节数。语法如下: ``` #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ``` 4. write(): 将数据从指定的缓冲区中写入到一个文件或设备中,返回实际写入的字节数。语法如下: ``` #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); ``` 5. lseek(): 在一个文件或设备中定位到指定的位置,返回新的位置偏移量。语法如下: ``` #include <unistd.h> off_t lseek(int fd, off_t offset, int whence); ``` 6. ioctl(): 对一个设备进行控制和定位操作,需要使用特定的命令码,并可携带相应的参数。语法如下: ``` #include <sys/ioctl.h> int ioctl(int fd, unsigned long request, ...); ``` 这些函数Linux系统编程中非常常用,尤其是在设备驱动开发中。熟练掌握这些函数的使用方式和原理,对于开发高质量的Linux应用程序和驱动非常有帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

花落已飘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值