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

时间:2014-12-16 11:45:15

标签: c file input struct tab-delimited-text

我有一个带制表符分隔数据的文件。我想把每一行都读成一个结构。我有一个代码来读取数据到char缓冲区。但我想将数据加载到Structure中。

这是我的样本数据。

  

empname1 \ t001 \ t35 \ tcity1

     

empname2 \ T002 \ T35 \ tcity2

我的结构定义。

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

};

我的示例程序,用于将数据读取到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 
    }

这里我想将内容加载到结构变量而不是字符缓冲区。我怎么能做到这一点?

4 个答案:

答案 0 :(得分:7)

嗯,一个可能的解决方案可能是

  1. 使用fgets()从文件中读取完整的一行。

  2. 使用strtok()根据您所需的分隔符[tab}对输入缓冲区进行标记。

  3. 将内存(malloc()/ realloc())分配给结构的指针变量。

  4. 将标记化输入复制到成员变量中。

  5. 注意: 1. fgets()读取并存储尾随\n。 2.请仔细检查如何使用strtok()。输入字符串应该是可变的。 3.在使用之前将内存分配给指针。 IMO,使用静态分配的数组作为struct employee成员变量。 功能

答案 1 :(得分:2)

您可以使用fscanf功能。以流形式打开文件,然后使用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);

确保为变量分配内存。

否则您可以使用strtok功能。那个时候你必须使用sscanf函数。

答案 2 :(得分:2)

您可以使用fscanf来读取文件中的每一行strtok以标记读取。
由于您的结构成员是指针,因此请适当地分配内存。

以下最小代码完全符合您的要求。

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

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

这里有几点需要注意:

  1. 只要您的结构定义(和成员的顺序)保持不变(参见值i的操作),这就可以保证有效。
  2. strtok(line, "\\");,第二个参数只是转义(第一个\)实际的\字符。

  3. OP的澄清:

    在您的结构定义中,第三个​​成员是int,但是您尝试将t35读入其中(这是一个字符串< / em>的)。
    因此var.age = atoi(ptr);将为您提供0

    您可以更改结构定义,将第三个成员设为char *并像其他成员一样分配内存。

    或更改文件内容,确保int作为第三个值。

答案 3 :(得分:1)

我认为这可能就是你要找的东西

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