Linux文件编程——读写结构体、链表等其他类型的数据
在 Linux 文件编程中, open
、read
、write
、close等函数,本质上的读写内容是一个无类型的指针,所以其
也可以读写整型、数组、结构体、链表等不同类型的数据。
SYNOPSIS
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
SYNOPSIS
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
我们可以看到读写的buf的类型都是void *,即他只是一个无类型的指针,本质上就是一个地址,和数据类型没关系,因此我们可以读写其他类型的数据。
1. 整型数据
写入整型数据
在 Linux 文件编程中,使用低级文件 I/O 函数写入整型数据时,需要先打开文件,然后将整型变量的地址和大小传递给 write
函数。write
函数会将整型数据以二进制形式写入文件。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("data.bin", O_WRONLY | O_CREAT | O_TRUNC, 0644); // 打开文件用于写入if (fd == -1) {perror("Error opening file");return 1;}int num = 42;if (write(fd, &num, sizeof(num)) != sizeof(num)) { // 写入整型数据perror("Error writing to file");}close(fd); // 关闭文件return 0;
}
-
open
函数用于打开文件,O_WRONLY
表示以写入模式打开文件,O_CREAT
表示如果文件不存在则创建文件,O_TRUNC
表示如果文件已存在则清空文件内容。 -
write
函数的第一个参数是文件描述符,第二个参数是指向要写入的数据的指针(这里是整型变量num
的地址),第三个参数是要写入的字节数(这里是sizeof(num)
)。 -
如果
write
函数返回的值不等于要写入的字节数,说明写入操作失败。
读取整型数据
读取整型数据时,同样需要先打开文件,然后使用 read
函数将数据读取到一个整型变量中。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("data.bin", O_RDONLY); // 打开文件用于读取if (fd == -1) {perror("Error opening file");return 1;}int num;if (read(fd, &num, sizeof(num)) != sizeof(num)) { // 读取整型数据perror("Error reading from file");} else {printf("Read number: %d\n", num); // 输出读取的整型数据}close(fd); // 关闭文件return 0;
}
-
open
函数使用O_RDONLY
参数以只读模式打开文件。 -
read
函数的第一个参数是文件描述符,第二个参数是指向存储读取数据的缓冲区的指针(这里是整型变量num
的地址),第三个参数是要读取的字节数(这里是sizeof(num)
)。 -
如果
read
函数返回的值不等于要读取的字节数,说明读取操作失败。
2. 数组数据
写入数组数据
写入数组数据时,需要将整个数组的内存地址和大小传递给 write
函数。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("array.bin", O_WRONLY | O_CREAT | O_TRUNC, 0644); // 打开文件用于写入if (fd == -1) {perror("Error opening file");return 1;}int arr[] = {1, 2, 3, 4, 5}; // 定义一个整型数组size_t size = sizeof(arr) / sizeof(arr[0]); // 计算数组大小if (write(fd, arr, sizeof(arr)) != sizeof(arr)) { // 写入数组perror("Error writing to file");}close(fd); // 关闭文件return 0;
}
-
sizeof(arr)
计算整个数组的大小(以字节为单位)。 -
write
函数将整个数组的内容写入文件。如果返回值不等于数组的大小,说明写入操作失败。
读取数组数据
读取数组数据时,需要将文件中的数据读取到一个数组中。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("array.bin", O_RDONLY); // 打开文件用于读取if (fd == -1) {perror("Error opening file");return 1;}int arr[5]; // 定义一个足够大的数组来存储读取的数据if (read(fd, arr, sizeof(arr)) != sizeof(arr)) { // 读取数组perror("Error reading from file");} else {for (int i = 0; i < 5; i++) {printf("arr[%d] = %d\n", i, arr[i]); // 输出读取的数组元素}}close(fd); // 关闭文件return 0;
}
-
read
函数将文件中的数据读取到数组arr
中。如果返回值不等于数组的大小,说明读取操作失败。 -
使用循环输出数组中的每个元素。
3. 结构体数据
定义结构体
typedef struct {int id;char name[50];float score;
} Student;
写入结构体数据
写入结构体数据时,需要将结构体变量的地址和大小传递给 write
函数。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("students.bin", O_WRONLY | O_CREAT | O_TRUNC, 0644); // 打开文件用于写入if (fd == -1) {perror("Error opening file");return 1;}Student s = {1, "Alice", 95.5}; // 定义一个结构体变量if (write(fd, &s, sizeof(Student)) != sizeof(Student)) { // 写入结构体perror("Error writing to file");}close(fd); // 关闭文件return 0;
}
-
sizeof(Student)
计算结构体的大小。 -
write
函数将整个结构体的内容写入文件。如果返回值不等于结构体的大小,说明写入操作失败。
读取结构体数据
读取结构体数据时,需要将文件中的数据读取到一个结构体变量中。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("students.bin", O_RDONLY); // 打开文件用于读取if (fd == -1) {perror("Error opening file");return 1;}Student s;if (read(fd, &s, sizeof(Student)) != sizeof(Student)) { // 读取结构体perror("Error reading from file");} else {printf("ID: %d, Name: %s, Score: %.2f\n", s.id, s.name, s.score); // 输出读取的结构体内容}close(fd); // 关闭文件return 0;
}
-
read
函数将文件中的数据读取到结构体变量s
中。如果返回值不等于结构体的大小,说明读取操作失败。 -
使用
printf
输出结构体的各个字段。
4. 链表数据
定义链表节点
typedef struct Node {int data;struct Node *next;
} Node;
写入链表数据
写入链表数据时,需要逐个节点将数据写入文件。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>void writeLinkedList(Node *head, const char *filename) {int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);if (fd == -1) {perror("Error opening file");return;}Node *current = head;while (current != NULL) {if (write(fd, ¤t->data, sizeof(int)) != sizeof(int)) { // 写入节点数据perror("Error writing to file");break;}current = current->next;}close(fd);
}
-
使用
open
打开文件,O_WRONLY
表示以写入模式打开文件,O_CREAT
表示如果文件不存在则创建文件,O_TRUNC
表示如果文件已存在则清空文件内容。 -
遍历链表,逐个节点将数据写入文件。每次写入一个
int
类型的数据。 -
如果
write
函数返回的值不等于sizeof(int)
,说明写入操作失败。
读取链表数据
读取链表数据时,需要逐个节点从文件中读取数据,并动态分配内存来构建链表。
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>Node* readLinkedList(const char *filename) {int fd = open(filename, O_RDONLY);if (fd == -1) {perror("Error opening file");return NULL;}Node *head = NULL, *tail = NULL;int data;while (read(fd, &data, sizeof(int)) == sizeof(int)) { // 读取节点数据Node *newNode = (Node *)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (head == NULL) {head = newNode;tail = newNode;} else {tail->next = newNode;tail = newNode;}}close(fd);return head;
}
-
使用
open
打开文件,O_RDONLY
表示以只读模式打开文件。 -
使用循环逐个读取文件中的数据。每次读取一个
int
类型的数据。 -
每次读取到一个数据后,动态分配一个新节点,并将其添加到链表中。
-
如果
read
函数返回的值不等于sizeof(int)
,说明读取操作失败,循环结束。
注意事项
-
文件描述符的管理:
使用低级文件 I/O 函数时,需要手动管理文件描述符的打开和关闭,确保不会出现资源泄漏。在程序结束时,务必调用close
函数关闭文件描述符。 -
错误处理:
低级文件 I/O 函数的错误处理通常依赖于errno
。在读写操作后,可以通过检查返回值是否为预期值来判断操作是否成功。如果返回值为-1
,可以通过perror
或strerror(errno)
获取错误信息。 -
链表的动态内存管理:
在读取链表时,需要动态分配内存来构建链表,并在使用完毕后释放内存,以避免内存泄漏。