简体   繁体   English

将制表符分隔文件读取到C中的结构

[英]Read tab delimited file to Structure in C

I have a file with tab delimited data. 我有一个带制表符分隔数据的文件。 I want to read the every line into a Structure. 我想把每一行都读成一个结构。 I have a code to read the data to char buffer. 我有一个代码来读取数据到char缓冲区。 But I want to load the data into a Structure. 但我想将数据加载到Structure中。

This is My sample data. 这是我的样本数据。

empname1\\t001\\t35\\tcity1 empname1 \\ T001 \\ T35 \\ tcity1

empname2\\t002\\t35\\tcity2 empname2 \\ T002 \\ T35 \\ tcity2

My Structure definition . 我的结构定义。

struct employee
{
  char *empname;
  char *empid;
  int age;
  char *addr;

};

My sample program to read data to a char array buffer 我的示例程序将数据读取到char数组buffer

char buffer[BUF_SIZE];      /* Character buffer */
    input_fd = open (fSource, O_RDONLY);
    if (input_fd == -1) {
       perror ("open");
        return 2;
    }

    while((ret_in = read (input_fd, &buffer, BUF_SIZE)) > 0){

         // Do Some Process 
    }

Here I want to load the content to a structure variable instead of the character buffer. 在这里,我想将内容加载到结构变量而不是字符缓冲区。 How I can achieve that? 我怎么能做到这一点?

Well, a possible solution could be 那么,一个可能的解决方案是

  1. Read a complete line from the file using fgets() . 使用fgets()从文件中读取完整的一行。

  2. tokenize the input buffer based on the required delimiter [ tab in your case] using strtok() . 使用strtok()基于所需的分隔符[在您的情况下使用tab ]标记输入缓冲区。

  3. allocate memory ( malloc() / realloc() ) to a pointer variable of your structure. 将内存( malloc() / realloc() )分配给结构的指针变量。

  4. copy the tokenized inputs into the member variables. 将标记化输入复制到成员变量中。

Note: 1. fgets() reads and stores the trailing \\n . 注意: fgets()读取并存储尾随\\n 2. Please check carefully how to use strtok() . 2.请仔细检查如何使用strtok() The input string should be mutable. 输入字符串应该是可变的。 3. Allocate memory to pointers before using them. 3.在使用之前将内存分配给指针。 IMO, use statically allocated array as struct employee member variables. IMO,使用静态分配的数组作为struct employee成员变量。

You can use the fscanf function. 您可以使用fscanf函数。 Open a file as a stream then use the fscanf to get a input from the file. 以流形式打开文件,然后使用fscanf从文件中获取输入。

int fscanf(FILE *stream, const char *format, ...);
FILE *fp=fopen(fsource,"r+");
struct employee detail;
fscanf(fp,"%s %s %d %s",detail.empname,detail.empid,&detail.age,detail.addr);

Make sure that allocation of memory to the variables. 确保为变量分配内存。

Or else you can use the strtok function. 否则你可以使用strtok函数。 That time you have to use the sscanf function. 那个时候你必须使用sscanf函数。

You can use fscanf to read each line from file, strtok to tokenize the line read. 您可以使用fscanf从文件读取每一行, strtok来标记读取的
Since your structure members are pointers, allocate memory appropriately. 由于您的结构成员是指针,因此请适当地分配内存。

The following minimal code does exactly what you want. 以下最小代码完全符合您的要求。

#define SIZE 50 
FILE *fp = NULL;                                                            
int i = 0;                                                                  
struct employee var = {NULL, NULL, 0, NULL};                                
char line[SIZE] = {0}, *ptr = NULL;   

/* 1. Open file for Reading */                                                 
if (NULL == (fp = fopen("file.txt","r")))                                   
{                                                                           
    perror("Error while opening the file.\n");                              
    exit(EXIT_FAILURE);                                                     
}

/* 2. Allocate Memory */                                                       
var.empname = malloc(SIZE);                                                 
var.empid = malloc(SIZE);                                                   
var.addr = malloc(SIZE); 

/* 3. Read each line from the file */   
while (EOF != fscanf(fp, "%s", line))                                       
{                                                                           
    /* 4. Tokenise the read line, using "\" delimiter*/                     
    ptr = strtok(line, "\\");                                                                                   
    var.empname = ptr;                                                      

    while (NULL != (ptr = strtok(NULL, "\\")))                              
    {                                                                       
        i++;                                                                

        /* 5. Store the tokens as per structure members , where (i==0) is first member and so on.. */
        if(i == 1)                                                          
            var.empid = ptr;                                                
        else if(i == 2)                                                     
            var.age = atoi(ptr);                                            
        else if (i == 3)                                                    
            var.addr = ptr;                                                 
    }                                                                       

    i = 0;        /* Reset value of i */                                                          
    printf("After Reading: Name:[%s] Id:[%s] Age:[%d] Addr:[%s]\n", var.empname, var.empid, var.age, var.addr);
}                                                                           

Working Demo: http://ideone.com/Kp9mzN 工作演示: http//ideone.com/Kp9mzN

Few things to Note here: 这里有几点需要注意:

  1. This is guaranteed to work, as long as your structure definition (and order of members) remains the same (see manipulation of value i ). 只要您的结构定义(和成员的顺序)保持不变(参见值i操作),这就可以保证有效。
  2. strtok(line, "\\\\"); , Second argument is just escaping (first \\ ) the actual \\ character. ,第二个参数是刚刚逃脱(第一\\ )的实际\\字符。

Clarification from the OP: OP的澄清:

In your structure definition, third member is an int , however you're trying to read t35 into it (which is a string ). 在你的结构定义中, 第三个成员是一个int ,但是你试图将t35读入它(这是一个字符串 )。
So var.age = atoi(ptr); 所以var.age = atoi(ptr); will give you 0 , 会给你0

You could change the structure definition, making third member as char * and allocating memory like other members. 您可以更改结构定义,将第三个成员设置为char *并像其他成员一样分配内存。

Or change file contents, making sure an int is present as the third value. 或者更改文件内容,确保int作为第三个值存在。

I think this may be what you are looking for 我想这可能就是你要找的东西

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

#include <sys/stat.h>

struct employee
{
char *empname;
char *empid;
int age;
char *addr;

};

int readEmploee(char *line, struct employee *employee)
{
    char *token;
    char *saveptr;
    char *endptr;

    if ((employee == NULL) || (line == NULL))
        return 0;

    token = strtok_r(line, "\t", &saveptr);
    if (token == NULL)
        return 0;
    employee->empname = strdup(token);

    token = strtok_r(NULL, "\t", &saveptr);
    if (token == NULL)
        return 0;
    employee->empid = strdup(token);

    token = strtok_r(NULL, "\t", &saveptr);
    if (token == NULL)
        return 0;
    employee->age = strtol(token, &endptr, 10);
    if (*endptr != '\0')
        return 0;

    token = strtok_r(NULL, "\t", &saveptr);
    if (token == NULL)
        return 0;
    employee->addr = strdup(token);

    return 1;
}

char *mygetline(int fd)
{
    char  *line;
    size_t length;
    size_t count;
    char   character;

    line = malloc(128);
    if (line == NULL)
        return NULL;
    length = 0;
    count  = 1;
    do
    {
        if (read(fd, &character, 1) != 1) /* end of file probably reached */
        {
            free(line);
            return NULL;
        }
        else if (character != '\n')
        {
            if (length > 128 * count)
            {
                char *temp;
                temp = realloc(line, 128 * count);
                if (temp == NULL)
                {
                    free(line);
                    return NULL;
                }
                line   = temp;
                count += 1;
            }
            line[length++] = character;
        }
    } while (character != '\n');
    line[length] = 0;

    return line;
}

struct employee *readFile(const char *const fSource, size_t *count)
{
    struct employee *employees;
    int              employeeCount;
    int              input_fd;
    char            *line;

    if ((count == NULL) || (fSource == NULL))
        return NULL;

    *count        = 0;
    employees     = NULL;
    employeeCount = 0;
    input_fd      = open (fSource, O_RDONLY);
    if (input_fd == -1)
    {
        perror ("open");
        return NULL;
    }

    while ((line = mygetline(input_fd)) != NULL)
    {
        struct employee employee;
        if (readEmploee(line, &employee) != 0)
        {
            struct employee *temp;

            temp = realloc(employees, (1 + employeeCount) * sizeof(struct employee));
            if (temp != NULL)
                employees = temp;
            employees[employeeCount++] = employee;
        }
        free(line);
    }
    *count = employeeCount;

    return employees;
}

int
main()
{
    size_t           count;
    size_t           index;
    struct employee *employees;

    employees = readFile("somesamplefile.txt", &count);
    if (employees == NULL)
        return 1;
    for (index = 0 ; index < count ; index++)
    {
        struct employee current;

        current = employees[index];

        fprintf(stderr, "%s, %s, %d, %s\n", current.empname, current.empid, current.age, current.addr);
        if (current.empname != NULL)
            free(current.empname);
        if (current.empid != NULL)
            free(current.empid);
        if (current.addr != NULL)
            free(current.addr);
    }
    free(employees);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM