在C中逐行读取txt文件
Read txt file line by line in C
我想逐行读取一个 txt 文件,每行存储在不同的变量中:
这是我要阅读的txt文件
Jenny
Woodbridge Ave
Amber
Exeter street
Michael
Main Street
David
Plainfield ave
我确实喜欢
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
typedef struct info
{
char name[20];
char add[50];
}INFO;
int main(void){
const char *fileName = "test.txt";
FILE *file = fopen(fileName, "r");
INFO* list = (INFO*)malloc(20*sizeof(INFO));
readFromFile(file,list);
fclose(file);
free(list);
return 0;
}
void readFromFile(FILE *file,INFO* list){
int i = 0;
while(!feof(file)){
fscanf(file,"%s %s\n ",(list+i)->name,(list+i)->adds);
i++;
}
}
但我得到
Name: Jenny
Addr: Woodbridge
------------------------------
Name: Ave
Addr: Amber
------------------------------
Name: Exeter
Addr: street
------------------------------
Name: Michael
Addr: Main
------------------------------
Name: Street
Addr: David
------------------------------
Name: Plainfield
Addr: ave
我只是编辑了一点
所以我需要使用 fgets 逐行读取而不是 fscanf() 对吗?
%s
说明符读取输入流,直到找到一个空白字符,在您的情况下,每个地址有 2 个字,一旦您尝试读取它,它就会变得不平衡,第二个字地址被下一个周期读入name
,也存在潜在的缓冲区溢出问题
你应该使用 %49[^\n]
,这个说明符会读取所有内容,直到找到换行符,包括 spaces。 49
是为了限制读取行的大小以避免提到的缓冲区溢出,在你的情况下你有 space 用于 50
个字符,最后一个字符将用于 null终结者。
feof
也不是在这种例程中发出文件结束信号的最佳方式,更多信息在 Why is “while ( !feof (file) )” always wrong?.
我在对以下工作示例的评论中解决了一些其他问题:
int main()
{
//casting malloc may make you program fail, it hides the lack of #include <stdlib.h>
INFO* list = malloc(20 * sizeof *list); //using the the dereferenced variable
//is safer regarding future code refactoring
const char *fileName = "test.txt";
FILE *f = fopen(fileName, "r"); //dont forget to verify the return of fopen
int i = read(f, list);
for (int j = 0; j < i; j++) //test print
{
printf("Name: %s Address: %s\n", list[j].name, list[j].add);
}
}
int read(FILE *file, INFO *list)
{
int i = 0;
//use scanf as stop condition, [] notation is easier to read
//limiting the size in scanf specifiers avoids buffer overflow
while (fscanf(file, "%19s %49[^\n]", list[i].name, list[i].add) == 2)
{
i++;
}
//return i so that you know how many structs were read
return i;
}
输出:
Name: Jenny Address: Woodbridge Ave
Name: Amber Address: Exeter street
Name: Michael Address: Main Street
Name: David Address: Plainfield ave
so I need to use fgets to read line by line instead of fscanf() right?
fscanf(file,"%s %s\n ",....
失败,因为 %s
没有根据 "Woodbridge Ave"
的需要将空格读入字符串,并且无法防止缓冲区溢出。
有很多方法可以解决这个任务。 fgets()
最清楚
考虑一个辅助函数来读取一行并处理 fgets()
行输入的特性。根据需要进行调整。
// return 1 on success
// return EOF on end-of-file/input error
// else return 0
int read_line(FILE *file, int sz, char *line) {
if (fgets(line, sz, file) == NULL) {
return EOF; // EOF or rare input error
}
int len = strlen(line);
if (len > 0 && line[len - 1] == '\n') {
line[--len] = '[=10=]'; // lop off potential \n
} else if (len + 1 == sz) { // no \n read, `line` full, so look for rest of input
int ch;
int extra = 0;
while ((ch = fgetc(file)) != '\n' && ch != EOF) {
extra = 1;
}
if (extra) {
return 0; // input too long
}
}
return 1;
}
现在将文件以行对的形式读入INFO
int read_INFO(FILE *file, int n, INFO *list) {
int i = 0;
while (i < n
&& read_line(file, sizeof list->name, list[i].name) == 1
&& read_line(file, sizeof list->add, list[i].add) == 1) {
i++;
}
return i;
}
用法
int n = 20;
INFO *list = malloc(sizeof *list * n);
if (list) {
int number_read = read_INFO(file, n, list);
if (number_read > 0) {
// The happy path
}
}
我想逐行读取一个 txt 文件,每行存储在不同的变量中: 这是我要阅读的txt文件
Jenny
Woodbridge Ave
Amber
Exeter street
Michael
Main Street
David
Plainfield ave
我确实喜欢
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
typedef struct info
{
char name[20];
char add[50];
}INFO;
int main(void){
const char *fileName = "test.txt";
FILE *file = fopen(fileName, "r");
INFO* list = (INFO*)malloc(20*sizeof(INFO));
readFromFile(file,list);
fclose(file);
free(list);
return 0;
}
void readFromFile(FILE *file,INFO* list){
int i = 0;
while(!feof(file)){
fscanf(file,"%s %s\n ",(list+i)->name,(list+i)->adds);
i++;
}
}
但我得到
Name: Jenny
Addr: Woodbridge
------------------------------
Name: Ave
Addr: Amber
------------------------------
Name: Exeter
Addr: street
------------------------------
Name: Michael
Addr: Main
------------------------------
Name: Street
Addr: David
------------------------------
Name: Plainfield
Addr: ave
我只是编辑了一点 所以我需要使用 fgets 逐行读取而不是 fscanf() 对吗?
%s
说明符读取输入流,直到找到一个空白字符,在您的情况下,每个地址有 2 个字,一旦您尝试读取它,它就会变得不平衡,第二个字地址被下一个周期读入name
,也存在潜在的缓冲区溢出问题
你应该使用 %49[^\n]
,这个说明符会读取所有内容,直到找到换行符,包括 spaces。 49
是为了限制读取行的大小以避免提到的缓冲区溢出,在你的情况下你有 space 用于 50
个字符,最后一个字符将用于 null终结者。
feof
也不是在这种例程中发出文件结束信号的最佳方式,更多信息在 Why is “while ( !feof (file) )” always wrong?.
我在对以下工作示例的评论中解决了一些其他问题:
int main()
{
//casting malloc may make you program fail, it hides the lack of #include <stdlib.h>
INFO* list = malloc(20 * sizeof *list); //using the the dereferenced variable
//is safer regarding future code refactoring
const char *fileName = "test.txt";
FILE *f = fopen(fileName, "r"); //dont forget to verify the return of fopen
int i = read(f, list);
for (int j = 0; j < i; j++) //test print
{
printf("Name: %s Address: %s\n", list[j].name, list[j].add);
}
}
int read(FILE *file, INFO *list)
{
int i = 0;
//use scanf as stop condition, [] notation is easier to read
//limiting the size in scanf specifiers avoids buffer overflow
while (fscanf(file, "%19s %49[^\n]", list[i].name, list[i].add) == 2)
{
i++;
}
//return i so that you know how many structs were read
return i;
}
输出:
Name: Jenny Address: Woodbridge Ave
Name: Amber Address: Exeter street
Name: Michael Address: Main Street
Name: David Address: Plainfield ave
so I need to use fgets to read line by line instead of fscanf() right?
fscanf(file,"%s %s\n ",....
失败,因为 %s
没有根据 "Woodbridge Ave"
的需要将空格读入字符串,并且无法防止缓冲区溢出。
有很多方法可以解决这个任务。 fgets()
最清楚
考虑一个辅助函数来读取一行并处理 fgets()
行输入的特性。根据需要进行调整。
// return 1 on success
// return EOF on end-of-file/input error
// else return 0
int read_line(FILE *file, int sz, char *line) {
if (fgets(line, sz, file) == NULL) {
return EOF; // EOF or rare input error
}
int len = strlen(line);
if (len > 0 && line[len - 1] == '\n') {
line[--len] = '[=10=]'; // lop off potential \n
} else if (len + 1 == sz) { // no \n read, `line` full, so look for rest of input
int ch;
int extra = 0;
while ((ch = fgetc(file)) != '\n' && ch != EOF) {
extra = 1;
}
if (extra) {
return 0; // input too long
}
}
return 1;
}
现在将文件以行对的形式读入INFO
int read_INFO(FILE *file, int n, INFO *list) {
int i = 0;
while (i < n
&& read_line(file, sizeof list->name, list[i].name) == 1
&& read_line(file, sizeof list->add, list[i].add) == 1) {
i++;
}
return i;
}
用法
int n = 20;
INFO *list = malloc(sizeof *list * n);
if (list) {
int number_read = read_INFO(file, n, list);
if (number_read > 0) {
// The happy path
}
}