Linux C 以read()读取文件并提取字符串

目录

相关函数解析

 代码示例


相关函数解析

下列函数均属于文件I/O操作系统调用函数

#include <unistd.h>

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

功能描述:读取文件中的内容。当文件是文本模式(非二进制模式),则函数会逐个字符进行读取;反之,如果文件以二进制模式打开,则会逐个字节进行读取。

参数解析:①fd:指文件描述符

                  ②buf:是读出数据的一段内存空间

                  ③nbytes:每次读取的字节数,不得超过nbytes字节,这里的nbytes一般是buf剩余的空间大小

返回值:成功则返回读到的字节数(>0),失败则返回-1,并且设置相应的errno,若读到文件尾,则返回0

ssize_t类型是表示有符号的size_t,这样既可以返回正的字节数、0和负的数值

PS:read()读取数据的时候,将数据保存在buf缓冲区中,同时文件的当前读写位置向后移动。此外,read()在读取数据时会将最后的回车(\n)同时读入到buf中,但是不会在后面加上字符串结束符(\0)。

#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);

功能描述:open()系统调用用来打开一个文件。并返回一个文件描述符(file description), 并且该文件描述符是当前进程最小、未使用的文件描述符数值。

返回值:成功则返回文件描述符,失败则返回-1,并设置errno

参数解析:①path: 要打开的文件、设备的路径

                  ②oflag: 由多个选项进行“或”运算构造oflag参数 。

                  必选: O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)

                  可选: O_APPEND 每次写时都追加到文件的尾端。

                        O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode

                        O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0,相当于清空文件

                        O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作设置非阻塞模式方式。

                        O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY....

                        ③mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如0666。 否则不需要.

如:

int fd;

fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);

fd = open(“text.txt”, O_WRONLY|O_APPEND);

#include <sys/types.h>    

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

功能描述:调整文件偏移量的地址,一般在我们读写文件内容的时候,都会使文件偏移量后移

返回值:通常成功则返回最终文件的起始位置的偏移地址,失败则返回-1,并设置相应的errno

返回值另一种情况

参数解析:①fd:文件描述符

                  ②offset:使相对于whence的偏移量

                  ③whence:有三个特定的选项,其值如下:

                                SEEK_SET表示在文件头

                                SEEK_CUR 表示在文件当前位置,允许offset有负值出现

                                SEEK_END 表示在文件尾,允许offset有负值出现

lseek(fd, 0, SEEK_SET); 将文件偏移量设置到了文件开始的第一个字节上;

lseek(fd, 0, SEEK_END); 将文件偏移量设置到文件最后一个字节上;

lseek(fd, -1, SEEK_END); 将文件偏移量设置到文件最后的倒数第一个字节上;

#include <unistd.h>

int close(int fd)

功能描述:关闭打开的文件,释放该文件所占用的资源。若不关闭打开的文件,会导致内存泄漏(程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果)

参数解析:fd:文件描述符

返回值:成功则返回0,失败则返回-1


 代码示例

下面用一个程序进行读取文件(rpi1.txt)内容,并且从其中提取出字符串“RPI0001”。

rpi1.txt中的内容如下:(注意RPI0001后面没有回车也没有空格)

SN=RPI0001

iot12@raspberrypi:~/lyt/apue $ vim demo.c

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
 
#define PATH          "rpi1.txt"
 
int get_id(char *rpi_id, int size);
int main(int argc, char **argv)
{
	char        rpi_id[16];
	
	get_id(rpi_id, sizeof(rpi_id));
	printf("%s\n", rpi_id);
 
    return 0;
 
}
 
int get_id(char *rpi_id, int size)
{
	int        fd = -1;
	char       buf[16];
	char      *ptr;

	fd = open(PATH, O_RDONLY);
 
	memset(buf, 0, sizeof(buf));
	read(fd, buf, sizeof(buf));
 
	ptr = strstr(buf, "SN=");
	ptr += strlen("SN=");

	memset(rpi_id, 0, size);
	memcpy(rpi_id, ptr, size);

    close(fd);
    return 0;
}


iot12@raspberrypi:~/lyt/apue $ gcc demo.c -o demo
iot12@raspberrypi:~/lyt/apue $ ./demo

RPI0001
          

从输出的结果我们可以看到RPI0001下面还多出了一行,这也就是说在buf中输入了回车。根据前面说到read()在读取文件时,在结束时会将最后的回车读到buf中,所以导致输出的结果出现换行的情况。所以我们在memset()中不可以将数据长度的字节数直接设为rpi_id大小,这样会把回车也读出来。

下面通过首尾指针确定读取的数据长度进行修改上面代码:
 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
 
#define PATH          "rpi1.txt"
 
int get_id(char *rpi_id, int size);
int main(int argc, char **argv)
{
	char        rpi_id[16];
	
	get_id(rpi_id, sizeof(rpi_id));
	printf("%s\n", rpi_id);
 
    return 0;
 
}
 
int get_id(char *rpi_id, int size)
{
	int        fd = -1;
	char       buf[16];
	char      *ptr;
	char      *id_start;
	char      *id_end;

	fd = open(PATH, O_RDONLY);
 
	memset(buf, 0, sizeof(buf));
	read(fd, buf, sizeof(buf));
 
	ptr = strstr(buf, "SN=");
	ptr += strlen("SN=");
	id_start = ptr;
	while( (*ptr) != '\n' ) //因为buf的最后有一个回车,所以把id_end指向回车前一位,也就是字符串最后一位
		ptr++;
	id_end = ptr;

	memset(rpi_id, 0, size);
	memcpy(rpi_id, id_start, id_end-id_start);

    close(fd);
    return 0;
}

iot12@raspberrypi:~/lyt/apue $ gcc demo.c -o demo
iot12@raspberrypi:~/lyt/apue $ ./demo

RPI0001

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,可以参考下面的代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 定义链表节点 typedef struct node { char *data; // 数据 struct node *next; // 指向下一个节点的指针 } Node; // 读取文件内容 char *read_file(const char *filename) { FILE *fp = fopen(filename, "r"); if (fp == NULL) { printf("Failed to open file: %s\n", filename); exit(1); } // 获取文件大小 fseek(fp, 0L, SEEK_END); long size = ftell(fp); fseek(fp, 0L, SEEK_SET); // 读取文件内容 char *content = (char *)malloc(size + 1); memset(content, 0, size + 1); fread(content, 1, size, fp); fclose(fp); return content; } // 分割字符串 Node *split_string(char *str, const char *delimiter) { Node *head = NULL; Node *tail = NULL; char *token = strtok(str, delimiter); while (token != NULL) { Node *node = (Node *)malloc(sizeof(Node)); node->data = (char *)malloc(strlen(token) + 1); strcpy(node->data, token); node->next = NULL; if (head == NULL) { head = node; tail = node; } else { tail->next = node; tail = node; } token = strtok(NULL, delimiter); } return head; } // 保存链表内容到文件 void save_list(Node *head, const char *filename) { FILE *fp = fopen(filename, "w"); if (fp == NULL) { printf("Failed to open file: %s\n", filename); exit(1); } Node *node = head; while (node != NULL) { fprintf(fp, "%s\n", node->data); node = node->next; } fclose(fp); } int main() { // 读取文件内容 char *content = read_file("input.txt"); // 分割字符串 Node *head = split_string(content, " \n"); // 保存链表内容到文件 save_list(head, "output.txt"); // 释放内存 Node *node = head; while (node != NULL) { Node *next = node->next; free(node->data); free(node); node = next; } free(content); return 0; } ``` 其中,`read_file`函数用于读取文件内容,`split_string`函数用于分割字符串并保存到链表中,`save_list`函数用于将链表内容保存到文件中。在`main`函数中,我们首先调用`read_file`函数读取文件内容,然后调用`split_string`函数将字符串分割成单词并保存到链表中,最后调用`save_list`函数将链表内容保存到文件中。最后别忘了释放内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值