Linux文件编程详解

Linux文件编程详解

在Ubuntu(Linux)系统下进行文件操作涉及一系列的系统调用,这些调用是基于Unix风格的文件操作API。这些操作包括打开或创建文件、从文件中读取数据、向文件中写入数据、移动文件指针以及关闭文件。以下是这些函数的详细介绍和实际应用示例。

1. 创建和打开文件 (open)

open 函数简介

open 函数用于打开一个现有文件或创建一个新文件。当配合 O_CREAT 标志使用时,它可以创建一个新的文件。

函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags, ... /* mode_t mode */);
  • 参数说明

  • pathname: 要打开或创建的文件的路径。
  • flags: 控制文件打开或创建方式的标志,可以是:
    • O_RDONLY:只读打开。
    • O_WRONLY:只写打开。
    • O_RDWR:读写打开。
    • O_CREAT:如果文件不存在,则创建它。
    • O_EXCL:与 O_CREAT 一起使用时,如果文件已存在,则返回错误。
    • O_TRUNC:如果文件已存在并且是以写入方式打开,则清空文件。
  • mode (可选参数):指定新文件的权限。这个参数是在文件创建时设置的,通常与 umask 的默认设置一起使用,例如 06440755 等。
 示例代码:创建文件
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

int main() {
    int fd;  // 文件描述符

    // 创建文件,如果文件不存在。设置文件权限为 0644 (rw-r--r--)
    fd = open("newfile.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("创建文件失败");
        exit(EXIT_FAILURE);
    }

    printf("文件 'newfile.txt' 已成功创建\n");

    // 对文件进行写操作等
    // ...

    // 完成操作后,关闭文件
    close(fd);
    return 0;
}

2. 写入文件 (write)

write 函数将数据写入文件。

函数原型
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • fd:文件描述符,由 open 返回。
  • buf:指向数据缓冲区的指针。
  • count:要写入的字节数。
 示例代码:写入数据
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    int fd;
    fd = open("testfile.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if (fd == -1) {
        perror("打开文件失败");
        exit(EXIT_FAILURE);
    }

    char *data = "Hello, Ubuntu 文件编程!";
    // 将字符串数据写入文件
    if (write(fd, data, strlen(data)) == -1) {
        perror("写入文件失败");
        close(fd);
        exit(EXIT_FAILURE);
    }

    printf("数据写入成功\n");

    // 写入完毕,关闭文件
    close(fd);
    return 0;
}

 3. 读取文件(read)

参数说明

  • fd:文件描述符,表示要读取数据的文件。这个文件描述符通常是通过 open 系统调用获取的。
  • buf:指向数据缓冲区的指针,用于存储从文件中读取的数据。
  • count:指定要读取的最大字节数。实际读取的字节数可能少于这个值,比如文件剩余内容不足 count 字节时。

返回值

  • 返回读取的字节数,如果文件已到达末尾,则返回 0。
  • 如果发生错误,则返回 -1,并设置 errno 以指示错误类型。
函数原型:
#include <unistd.h>

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

示例代码: 

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd;  // 文件描述符
    ssize_t bytes_read;  // 实际读取的字节数
    char buffer[1024];  // 数据缓冲区

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("打开文件失败");
        exit(EXIT_FAILURE);
    }

    // 从文件中读取数据
    bytes_read = read(fd, buffer, sizeof(buffer) - 1);  // 保留一个位置用于放置字符串终止符'\0'
    if (bytes_read == -1) {
        perror("读取文件失败");
        close(fd);
        exit(EXIT_FAILURE);
    }

    buffer[bytes_read] = '\0';  // 确保读取的内容被正确终止以便作为字符串处理

    // 打印读取的内容
    printf("读取到的内容:\n%s\n", buffer);

    // 关闭文件
    close(fd);
    return 0;
}

4. 关闭文件 (close)

close 函数用于关闭一个打开的文件描述符,释放系统资源。

函数原型
#include <unistd.h>

int close(int fd);

fd:要关闭的文件描述符。

关闭文件的重要性 

关闭文件是必要的,因为打开的文件描述符是有限的资源。每个进程能打开的文件数量是有限的,未及时关闭文件可能导致资源泄漏,影响程序性能或导致程序异常。

5. 移动文件 (lseek)

lseek 函数用于移动文件的读/写指针到指定位置。

函数原型
#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
  • fd:文件描述符。
  • offset:偏移量,可为负值。
  • whence:起始位置(SEEK_SET 从文件开始,SEEK_CUR 从当前位置,SEEK_END 从文件末尾)。
 移动文件光标使用 lseek 系统调用。下面是一个示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define FILENAME "example.txt"

int main() {
    // 以只读模式打开文件 example.txt
    int fd = open(FILENAME, O_RDONLY);
    if (fd == -1) {
        // 打开文件失败,输出错误信息并退出程序
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 将文件光标移动到文件末尾,并获取文件大小
    off_t offset = lseek(fd, 0, SEEK_END);
    if (offset == -1) {
        // lseek操作失败,输出错误信息并关闭文件描述符
        perror("lseek");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 打印文件大小
    printf("文件大小: %ld 字节\n", offset);

    // 将文件光标移动回文件开头
    if (lseek(fd, 0, SEEK_SET) == -1) {
        // lseek操作失败,输出错误信息并关闭文件描述符
        perror("lseek");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 关闭文件描述符
    close(fd);
    return 0;
}

6. 计算文件大小(lseek)

计算文件大小可以使用 lseek 系统调用将文件光标移动到文件末尾,然后获取当前位置的偏移量。下面是一个示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define FILENAME "example.txt"

int main() {
    // 以只读模式打开文件 example.txt
    int fd = open(FILENAME, O_RDONLY);
    if (fd == -1) {
        // 打开文件失败,输出错误信息并退出程序
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 将文件光标移动到文件末尾,并获取文件大小
    off_t file_size = lseek(fd, 0, SEEK_END);
    if (file_size == -1) {
        // lseek操作失败,输出错误信息并关闭文件描述符
        perror("lseek");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 打印文件大小
    printf("文件大小: %ld 字节\n", file_size);

    // 关闭文件描述符
    close(fd);
    return 0;
}

7打开/创建文件打开/创建文件

7.cp文件的实现

mian函数参数的用法
#include <stdio.h>
 
int main(int argc,char **argv)
{
        printf("total params:%d\n",argc);
        printf("No.1 params :%s\n",argv[0]);
        printf("No.2 params :%s\n",argv[1]);
        printf("No.3 params :%s\n",argv[2]);
 
        return 0;
}

argc :代表的是 ./a.out argc argv 这三个参数的个数

argv[0] :代表第一个参数./a.out

argv[1] :代表第二个参数 argc

argv[2] :代表第二个参数 argv

由此可见argv是数组的数组。

思路:1.打开源文件src.c

​ 2.读src到buf

​ 3.打开/创建目标文件des.c

​ 4.将buf写入des.c

​ 5.close两个文件

#include <sys/types.h>   // 引入类型定义,如pid_t等
#include <sys/stat.h>    // 引入文件状态定义,如S_IRUSR等
#include <fcntl.h>       // 引入文件控制定义,如O_RDWR等
#include <stdio.h>       // 引入标准输入输出库,用于printf等函数
#include <unistd.h>      // 引入POSIX操作系统API,如read、write等
#include <string.h>      // 引入字符串操作库,用于strlen等函数
#include <stdlib.h>      // 引入标准库,用于malloc、exit等函数

int main(int argc, char **argv)
{
    int fdSrc;  // 源文件的文件描述符
    int fdDes;  // 目标文件的文件描述符

    char *readBuf=NULL;  // 用于存储从源文件读取的数据

    if(argc != 3){  // 检查命令行参数数量是否正确
        printf("pararm error\n");  // 参数错误时打印错误信息
        exit(-1);  // 错误退出程序
    }

    fdSrc = open(argv[1], O_RDWR);  // 以读写方式打开源文件
    int size = lseek(fdSrc, 0, SEEK_END);  // 定位到源文件的末尾,获取文件大小
    lseek(fdSrc, 0, SEEK_SET);  // 重新定位到文件开头,准备读取数据

    readBuf = (char *)malloc(sizeof(char) * size + 8);  // 分配足够的内存以存储文件数据,额外加8字节防止溢出

    int n_read = read(fdSrc, readBuf, size);  // 从源文件读取数据到缓冲区

    fdDes = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0600);  // 以读写方式打开或创建目标文件,若文件存在则长度截为0

    int n_write = write(fdDes, readBuf, strlen(readBuf));  // 将读取的数据写入目标文件,使用strlen确保只写入有效字符串长度

    close(fdSrc);  // 关闭源文件
    close(fdDes);  // 关闭目标文件

    return 0;  // 程序正常结束
}

 8.文件编程修改程序的配置文件demo

#include <sys/types.h>  // 引入用于系统调用的基本数据类型
#include <sys/stat.h>   // 引入用于文件属性操作的定义
#include <fcntl.h>      // 引入用于文件控制的函数定义
#include <stdio.h>      // 引入标准输入输出库
#include <unistd.h>     // 引入POSIX操作系统API
#include <string.h>     // 引入字符串操作函数
#include <stdlib.h>     // 引入标准库函数

int main(int argc, char **argv)
{
    int fdSrc;  // 定义源文件的文件描述符

    char *readBuf = NULL;  // 定义读取数据的缓冲区指针

    if(argc != 2){  // 检查输入参数是否为2个,不正确则报错
        printf("parameter error\n");  // 打印参数错误信息
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }
    
    // 以读写模式打开源文件,文件描述符保存在fdSrc中
    fdSrc = open(argv[1], O_RDWR);
    if (fdSrc == -1) {  // 检查文件是否成功打开
        perror("Error opening file");  // 打印错误信息
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 使用lseek获取文件大小
    int size = lseek(fdSrc, 0, SEEK_END);
    if (size == -1) {  // 检查是否成功获取文件大小
        perror("Error seeking file");  // 打印错误信息
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 将文件指针重新定位到文件开始
    if (lseek(fdSrc, 0, SEEK_SET) == -1) {
        perror("Error re-seeking file");  // 打印错误信息
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 分配内存以存储文件数据,多分配8字节防止溢出
    readBuf = (char *)malloc(sizeof(char) * size + 8);
    if (readBuf == NULL) {  // 检查内存分配是否成功
        perror("Memory allocation failed");  // 打印错误信息
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 从文件中读取数据到缓冲区
    int n_read = read(fdSrc, readBuf, size);
    if (n_read == -1) {  // 检查读取是否成功
        perror("Error reading file");  // 打印错误信息
        free(readBuf);  // 释放内存
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 查找特定的字符串"LENG=",准备修改其后的值
    char *p = strstr(readBuf, "LENG=");
    if (p == NULL) {  // 检查是否找到指定字符串
        printf("not found\n");  // 打印未找到信息
        free(readBuf);  // 释放内存
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 修改找到字符串后的值
    p += strlen("LENG=");
    *p = '5';  // 设置新的值为'5'

    // 将文件指针重新定位到文件开始
    if (lseek(fdSrc, 0, SEEK_SET) == -1) {
        perror("Error re-seeking file");  // 打印错误信息
        free(readBuf);  // 释放内存
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 将修改后的缓冲区内容写回文件
    int n_write = write(fdSrc, readBuf, strlen(readBuf));
    if (n_write == -1) {  // 检查写入是否成功
        perror("Error writing file");  // 打印错误信息
        free(readBuf);  // 释放内存
        close(fdSrc);  // 关闭文件
        exit(EXIT_FAILURE);  // 退出程序,返回失败标志
    }

    // 释放内存并关闭文件描述符
    free(readByf);
    close(fdSrc);

    return 0;  // 返回成功
}

9.写一个整数到文件和写结构体数组到文件

示例程序 1: 写入和读取单个整数
#include <sys/types.h>  // 引入用于系统调用的基本数据类型
#include <sys/stat.h>   // 引入用于文件属性操作的定义
#include <fcntl.h>      // 引入用于文件控制的函数定义
#include <stdio.h>      // 引入标准输入输出库
#include <unistd.h>     // 引入POSIX操作系统API
#include <string.h>     // 引入字符串操作函数
#include <stdlib.h>     // 引入标准库函数

int main()
{
	int fd;  // 文件描述符
	
	int data = 100;  // 要写入文件的整数
	int data2 = 0;  // 用于读取文件数据的整数

	fd = open("./file1",O_RDWR);  // 打开文件以读写方式

	int n_write = write(fd,&data,sizeof(int));  // 将整数data写入文件

	lseek(fd,0,SEEK_SET);  // 重置文件指针到文件开始处

	int n_read = read(fd, &data2, sizeof(int));  // 从文件读取整数到data2
	
	printf("read %d \n",data2);  // 打印读取的整数
	close(fd);  // 关闭文件描述符

	return 0;  // 程序正常退出
}
示例程序 2: 写入和读取单个结构体
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

struct Test  // 定义一个结构体,包含一个整数和一个字符
{
	int a;
	char c;
};

int main()
{
	int fd;  // 文件描述符
	
	struct Test data = {100,'a'};  // 初始化结构体变量data
	struct Hest data2;  // 用于读取文件数据的结构体变量

	fd = open("./file1",O_RDWR);  // 打开文件以读写方式

	int n_write = write(fd,&data,sizeof(struct Test));  // 将结构体data写入文件

	lseek(fd,0,SEEK_SET);  // 重置文件指针到文件开始处

	int n_read = read(fd, &data2, sizeof(struct Test));  // 从文件读取结构体到data2
	
	printf("read %d,%c \n",data2.a,data2.c);  // 打印读取的结构体内容
	close(fd);  // 关闭文件描述符

	return 0;  // 程序正常退出
}
示例程序 3: 写入和读取结构体数组
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

struct Test  // 定义一个结构体,包含一个整数和一个字符
{
	int a;
	char c;
};

int main()
{
	int fd;  // 文件描述符
	
	struct Test data[2] = {{100,'a'},{101,'b'}};  // 初始化结构体数组
	struct Test data2[2];  // 用于读取文件数据的结构体数组

	fd = open("./file1",O_RDWR);  // 打开文件以读写方式

	int n_write = write(fd,&data,sizeof(struct Test)*2);  // 将结构体数组data写入文件

	lseek(fd,0,SEEK_SET);  // 重置文件指针到文件开始处

	int n_read = read(fd, &data2, sizeof(struct Test)*2);  // 从文件读取结构体数组到data2
	
	printf("read %d,%c \n",data2[0].a,data2[0].c);  // 打印读取的第一个结构体内容
	printf("read %d,%c \n",data2[1].a,data2[1].c);  // 打印读取的第二个结构体内容
	close(fd);  // 关闭文件描述符

	return 0;  // 程序正常退出
}

10.open和fopen区别

openfopen 是用于文件操作的两个常见函数,它们存在一些关键差异,主要体现在它们所属的库和API风格、功能、以及使用场景上。

 1. 来源

从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:

  • open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
  • fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。 
     PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。
2. 移植性

这一点从上面的来源就可以推断出来,`fopen`是C标准函数,因此拥有良好的移植性;而`open`是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数`CreateFile`。

3. 适用范围
  • open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
  • fopen是用来操纵普通正规文件(Regular File)的。
4. 文件IO层次

如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。

5. 缓冲
  1. 缓冲文件系统 
    缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
  2. 非缓冲文件系统 
    缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。

一句话总结一下,就是open无缓冲,fopen有缓冲。前者与readwrite等配合使用, 后者与fread,fwrite等配合使用。

使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:readwrite);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。

这样一总结梳理,相信大家对于两个函数及系列函数有了一个更全面清晰的认识,也应该知道在什么场合下使用什么样的函数更合适,效率更高。

 使用 open 示例:
#include <fcntl.h>    // 引入文件控制的头文件
#include <unistd.h>   // 引入POSIX操作系统API
#include <sys/stat.h> // 引入文件状态的头文件
#include <stdio.h>    // 引入标准输入输出库
#include <stdlib.h>   // 引入标准库,用于使用exit等函数

int main() {
    // 以写入、创建、截断方式打开文件,文件权限为用户读写
    int fd = open("example.dat", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("Failed to open file");  // 打开文件失败时输出错误信息
        exit(EXIT_FAILURE);             // 退出程序
    }

    const char *text = "Hello, world!";  // 定义要写入的字符串
    if (write(fd, text, 13) != 13) {     // 写入字符串到文件
        perror("Failed to write");       // 写入失败时输出错误信息
        close(fd);                       // 关闭文件描述符
        exit(EXIT_FAILURE);              // 退出程序
    }

    close(fd);  // 成功写入后关闭文件描述符
    return 0;
}
使用 fopen 示例:
#include <stdio.h>   // 引入标准输入输出库
#include <stdlib.h>  // 引入标准库,用于使用exit等函数

int main() {
    // 以写入模式打开文件
    FILE *fp = fopen("example.txt", "w");
    if (fp == NULL) {
        perror("Failed to open file");  // 打开文件失败时输出错误信息
        exit(EXIT_FAILURE);             // 退出程序
    }

    const char *integer = "Hello, world!"; // 定义要写入的字符串
    if (fprintf(fp, "%s", integer) < 0) {  // 使用fprintf将字符串写入文件
        perror("Failed to write");         // 写入失败时输出错误信息
        fclose(fp);                        // 关闭文件流
        exit(EXIT_FAILURE);                // 退出程序
    }

    fclose(fp);  // 成功写入后关闭文件流
    return 0;
}

11.标准C库打开C库打开创建文件读写文件光标移动

#include <stdio.h>   // 引入标准输入输出库,用于文件操作和基本的输入输出功能
#include <string.h>  // 引入字符串处理库,用于处理字符串,如计算字符串长度等

int main()
{
    FILE *fp;  // 声明一个 FILE 类型的指针,用于表示文件流
    char *str = "hello world";  // 声明并初始化一个字符串常量,将用于写入文件
    char readBuf[128] = {0};  // 声明一个字符数组作为读取缓冲区,并初始化所有元素为 0

    fp = fopen("./hello.txt","w+");  // 使用 fopen 函数以读写模式打开(如果不存在则创建)一个名为 chen.txt 的文件

    // 使用 fwrite 函数将字符串 str 写入文件
    // str: 要写入的数据的指针
    // sizeof(char)*strlen(str): 每个数据单元的大小乘以要写入的数据单元的数量,这里计算整个字符串的总大小
    // 1: 写入的数据块数量,这里写入一次整个字符串
    // fp: 目标文件流的指针
    fwrite(str, sizeof(char)*strlen(str), 1, fp);

    fseek(fp, 0, SEEK_SET);  // 使用 fseek 函数将文件内的位置指针重新定位到文件开头

    // 使用 fread 函数从文件中读取数据
    // readBuf: 用于接收数据的缓冲区的指针
    // sizeof(char)*strlen(str): 每个数据单元的大小乘以数据单元的数量,这里计算整个字符串的总大小
    // 1: 读取的数据块数量,这里读取一次整个字符串
    // fp: 源文件流的指针
    fread(readModule, sizeof(char)*strlen(str), 1, fp);
    
    printf("read data: %s\n", readBuf);  // 使用 printf 函数打印读取到的数据

    return 0;  // 程序正常结束,返回 0
}

 12.第一个程序:写入并读取字符串  第二个程序:写入并读取结构体

#include <stdio.h>  // 引入标准输入输出库
#include <string.h> // 引入字符串处理库

int main() {
    FILE *fp;  // 文件指针
    char *str = "hello world";  // 要写入文件的字符串
    char readBuf[128] = {0};  // 读取数据的缓冲区,初始化为0

    fp = fopen("./hello.txt", "w+");  // 以读写模式打开文件,如果文件不存在则创建
    if (fp == NULL) {  // 文件打开失败的处理
        perror("Failed to open file");
        return -1;
    }

    int nwrite = fwrite(str, sizeof(char) * strlen(str), 1, fp);  // 将字符串写入文件
    fseek(fp, 0, SEEK_SET);  // 重置文件指针到文件开头
    int nread = fread(readBuf, sizeof(char) * strlen(str), 100, fp);  // 从文件读取数据到缓冲区

    printf("read data: %s\n", readBuf);  // 打印读取的数据
    printf("read=%d, write = %d\n", nread, nwrite);  // 打印读取和写入的数据数量

    return 0;  // 程序结束
}
#include <stdio.h>    // 引入标准输入输出库
#include <sys/types.h> // 引入系统类型定义
#include <sys/stat.h>  // 引入文件状态控制库
#include <fcntl.h>     // 引入文件控制函数库
#include <unistd.h>    // 引入POSIX操作系统API
#include <string.h>    // 引入字符串处理库
#include <stdlib.h>    // 引入标准库函数

struct Test {
    int a;   // 结构体的整型成员
    char c;  // 结构体的字符成员
};

int main() {
    FILE *fp;  // 文件指针
    struct Test data = {100, 'a'};  // 初始化结构体实例
    struct Test data2;  // 用于存储从文件读取的结构体数据

    fp = fopen("./file1", "w+");  // 以读写模式打开文件
    if (fp == NULL) {  // 文件打开失败的处理
        perror("Failed to open file");
        return -1;
    }

    int n_write = fwrite(&data, sizeof(struct Test), 1, fp);  // 将结构体写入文件
    fseek(fp, 0, SEEK_SET);  // 重置文件指针到文件开头
    int n_read = fread(&data2, sizeof(struct Test), 1, fp);  // 从文件读取结构体数据

    printf("read %d,%c \n", data2.a, data2.c);  // 打印读取的结构体成员
    fclose(fp);  // 关闭文件

    return 0;  // 程序结束
}
第一个程序:向文件中写入字符串
#include <stdio.h>  // 引入标净输入输出库
#include <string.h> // 引入字符串处理库

int main()
{
    FILE *fp;  // 文件指针
    int i;  // 循环计数器
    char *str = "zlb hen shuai o!";  // 要写入文件的字符串
    int len = strlen(str);  // 计算字符串的长度

    fp = fopen("./test.txt", "w+");  // 以读写模式打开文件,如果文件不存在则创建
    if (fp == NULL) {  // 文件打开失败的处理
        perror("Failed to open file");
        return -1;
    }

    for (i = 0; i < len; i++) {  // 遍历字符串中的每个字符
        fputc(*str, fp);  // 将当前字符写入文件
        str++;  // 移动到字符串的下一个字符
    }
    fclose(fp);  // 关闭文件
    return 0;
}
第二个程序:从文件中读取字符串
#include <stdio.h>  // 引入标准输入输出库
#include <string.h> // 引入字符串处理库

int main()
{
    FILE *fp;  // 文件指针
    int i;  // 循环计数器
    char c;  // 用于存储读取的字符

    fp = fopen("./test.txt", "r");  // 以只读模式打开文件
    if (fp == NULL) {  // 文件打开失败的处理
        perror("Failed to open file");
        return -1;
    }

    while (!feof(fp)) {  // 判断文件是否结束
        c = fgetc(fp);  // 从文件中读取一个字符
        printf("%c", c);  // 打印读取的字符
    }
    fclose(fp);  // 关闭文件
    return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/746650.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

std::enable_if和std::is_base_of

std::enable_if,其主要为了完成模板特偏化&#xff0c;有两个参数&#xff0c;第一个为布尔值类型&#xff0c;第二个如果布尔值为true&#xff0c;其为默认空值&#xff0c;如果已经赋值&#xff0c;则为对应的类型。 std::is_base_of&#xff0c;其一共存在两个参数&#xff…

ora-15025 ora-27041问题处理

这个问题先排查 [oracleracdg2-2 ~]$ cd $ORACLE_HOME/bin [oracleracdg2-2 bin]$ ls -ld oracle -rwsr-s--x 1 oracle oinstall 239626641 Jun 25 19:09 oracle 正常的属组是 [gridracdg2-1 ~]$ setasmgidwrap -o /u01/app/oracle/product/11.2.0.4/dbhome_1/bin/oracle […

玩转AI之四个免费热门的AI工具

2023年&#xff0c;可以说称之为人工智能元年&#xff0c;随着 AI 人工智能、机器学习技术的不断发展&#xff0c;各种 AI 算法的应用也越来越广泛&#xff0c;在AI这一领域中&#xff0c;软件、工具和网站如雨后春笋般涌现。下半年&#xff0c;预计会有更多王炸级别的产品问世…

windows10/win11截图快捷键 和 剪贴板历史记录 快捷键

后知后觉的我今天又学了两招&#xff1a; windows10/win11截图快捷键 按 Windows 徽标键‌ Shift S。 选择屏幕截图的区域时&#xff0c;桌面将变暗。 默认情况下&#xff0c;选择“矩形模式”。 可以通过在工具栏中选择以下选项之一来更改截图的形状&#xff1a;“矩形模式”…

线性代数基础概念:行列式

目录 线性代数基础概念&#xff1a;行列式 1. 行列式的定义 1.1 递归定义 1.2 代数余子式定义 1.3 几何定义 2. 行列式的性质 2.1 行列式等于其转置的行列式 2.2 交换两行或两列&#xff0c;行列式变号 2.3 将一行或一列乘以一个数 k&#xff0c;行列式乘以 k 2.4 将…

植物大战僵尸杂交版技巧大全(附下载攻略)

《植物大战僵尸杂交版》为策略游戏爱好者带来了全新的挑战和乐趣。如果你是新手玩家&#xff0c;可能会对游戏中的植物和僵尸感到困惑。以下是一些实用的技巧&#xff0c;帮助你快速掌握游戏并享受其中的乐趣。 技巧一&#xff1a;熟悉基本玩法 游戏的基本玩法与原版相似&…

Android 11.0 修改系统显示大小导航栏消失

Android 11.0 修改系统显示大小导航栏消失 1.显示大小设置为大时,导航栏图标不显示。 设置为大,较大,最大时,导航栏图标不显示。 2.开始怀疑是导航栏被隐藏了,各种折腾无效。 3.发现: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/Edg…

OpenCV cv::Mat到 Eigen 的正确转换——cv2eigen

在进行计算机视觉项目时&#xff0c;我们经常需要处理相机位姿的变换。最近&#xff0c;我在项目中遇到了一个看似简单但实际上颇具挑战性的问题&#xff1a;从 OpenCV 的 cv::Mat 格式转换到 Eigen 库的格式。这个过程中遇到了一些问题&#xff0c;但最终找到了一个稳健的解决…

高考成绩加分,西藏学生推荐使用的《藏文翻译词典》APP,藏文作文高考大纲,初中高中学习内容与考试同步更新!

2024年高考成绩出炉啦&#xff01;在这个特别的时刻&#xff0c;我想向大家表达最真挚的祝贺。高考不仅是一场考试&#xff0c;更是你多年学习旅程的一次总结。当你的成绩揭晓&#xff0c;无论结果如何&#xff0c;你都应该为自己感到骄傲。 在高原&#xff0c;藏语如同雪山上…

从官方源码精简出第1个FreeRTOS程序

一、下载官方源码 1、打开百度搜索freerots&#xff0c;找到官网:FreeRTOS官网 2、将源码解压到没有中文目录的路径下 二、删减目录 1、删除FreeRTOS-Plus和tools 2、删除FreeRTOS/Demo下除CORTEX_STM32F103_Keil外的所有文件 3、删除FreeRTOS\Source\portable下除RVDS和MemM…

字符串匹配 --- BF算法 KMP算法

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 算法Journey 本篇博客我们将介绍关于字符串匹配的BF算法以及KMP算法&#xff0c;请放心食用~ &#x1f3e0; 字符串匹配 假设有一个字符串为主串str&#x…

算法07 深度优先搜索及相关问题详解

深搜与广搜是搜索算法中最常用的两种算法&#xff0c;通过深度优先搜索解决问题还会用到回溯和剪枝&#xff0c;让我们一起进入本章&#xff0c;了解深搜的基本概念和模板&#xff0c;并学会解决一些常见问题。 目录 问题导入 走迷宫问题 如何走&#xff1f; 问题建模 如何…

(2024,频域 LoRA,DFT,DCT,自适应门控,基于适配器组合的图像编辑)FouRA:傅里叶 LoRA

FouRA: Fourier Low Rank Adaptation 公和众与号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 3. 提出的方法 3.1 低秩适应的公式 3.2 频域中的低秩适应 3.3 频率变换 …

【个人博客搭建】(26)发布后端webapi项目

1、选择启动的webapi&#xff0c;右击发布 2、选择左下角的“显示所有设置” 在上一页按钮那边是发布文件夹的目录 地址&#xff0c; 现在界面的就是配置的信息&#xff0c; 配置&#xff1a;Debug、Release 目标框架&#xff1a;我们用的net8.0&#xff0c;就是他&#xff…

2.移植freertos到stm32f103c8t6

目录 1.步骤 2.freertos配置时常见的选项卡意思 1.步骤 2.freertos配置时常见的选项卡意思

Michael.W基于Foundry精读Openzeppelin第60期——Clones.sol

Michael.W基于Foundry精读Openzeppelin第60期——Clones.sol 0. 版本0.1 Clones.sol 1. 目标合约2. 代码精读2.1 clone(address implementation) internal2.2 cloneDeterministic(address implementation, bytes32 salt)2.3 predictDeterministicAddress(address implementatio…

Upload-Labs-Linux1 使用 一句话木马

解题步骤&#xff1a; 1.新建一个php文件&#xff0c;编写内容&#xff1a; <?php eval($_REQUEST[123]) ?> 2.将编写好的php文件上传&#xff0c;但是发现被阻止&#xff0c;网站只能上传图片文件。 3.解决方法&#xff1a; 将php文件改为图片文件&#xff08;例…

小程序开发平台源码系统——社区团购小程序功能 前后端分离 带完整的安装代码包以及搭建教程

系统概述 在当今数字化时代&#xff0c;社区团购已经成为一种热门的购物模式。为了满足市场需求&#xff0c;拥有一个功能强大的社区团购小程序是至关重要的。本文将深入探讨一款具备前后端分离特性的小程序开发平台源码系统&#xff0c;着重介绍其社区团购小程序功能&#xf…

CleanMyMac2024免费版下载!轻松清理垃圾文件、优化系统性能

亲爱的小伙伴们&#xff5e;&#x1f44b;今天我要给大家分享一款神奇的软件&#xff0c;它就是 CleanMyMac 2024 免费版&#xff01;这款软件不仅能帮你轻松清理垃圾文件、优化系统性能&#xff0c;还有更多惊喜功能等你来探索哦&#xff01;&#x1f38a; CleanMyMac绿色免费…

第三十二篇——大数据2:大数据思维的四个层次

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 我们生活在这个时代&#xff0c;我们是否按照这个时代需要的思维方式去思…