2014-12-16 2 views
3

У меня есть файл с данными с разделителями табуляции. Я хочу прочитать каждую строку в Структуре. У меня есть код для чтения данных в буфере символов. Но я хочу загрузить данные в структуру.Прочитать файл с разделителями табуляции в Структуре в C

Это мои данные образца.

empname1 \ T001 \ T35 \ tcity1

empname2 \ T002 \ T35 \ tcity2

Мое определение структуры.

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

}; 

Моя типовая программа для чтения данных в массиве charbuffer

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 
    } 

Здесь я хочу, чтобы загрузить содержимое в структуру переменной вместо буфера символов. Как я могу это достичь?

ответ

7

Ну, возможным решением может быть

  1. прочитать полную строку из файла с помощью fgets().

  2. tokenize входной буфер на основе требуемого разделителя [tab в вашем случае] с использованием strtok().

  3. выделить память (malloc()/ realloc()) переменной указателя вашей структуры.

  4. копировать токенизированные входы в переменные-члены.

Примечание: 1. fgets() считывает и сохраняет заднюю \n. 2. Пожалуйста, внимательно прочитайте, как использовать strtok(). Вход строка должна быть изменчивой. 3. Выделите память указателями перед их использованием. IMO, используйте статически выделенный массив как переменные-члены struct employee.

+0

Было бы легко удалить завершающую 'новую строку' с помощью' strtok (buffer, "\ t \ n") '. –

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.

+0

Использование любой функции 'scanf()' будет сложным. Единственный способ заставить их уважать вкладки как границы полей с помощью спецификации преобразования%% [...] ', которую этот ответ в настоящее время не использует. –

+0

Ваш 'fscanf' будет читать ** все ** каждой строки в первый'% s', т. Е. 'detail.empname', его не будет tokenise на себе, использование' fscanf' является инстантом. Демо: http://ideone.com/3zKWI6. Sidenote: 'detail.age' должен быть' & detail.age' в 'fscanf'. –

+0

На вашем входе мы должны указать пространство табуляции не \ t. Я взял \ t из вопроса как спецификатор табуляции. –

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; 
} 
+2

В общем, вы должны предположить, что имена, начинающиеся с подчеркивания, зарезервированы для реализации. Детали немного более тонкие, чем это, но недостаточно, чтобы было разумно использовать такие имена в вашем собственном коде. –

+0

Извините, дурная привычка. Починил это. Спасибо. –

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. Это гарантированно работать, до тех пор, как вы r (и порядок членов) остается неизменным (см. манипулирование значением i).
  2. strtok(line, "\\");, Второй аргумент просто ускользает (первый \) фактический символ \.

Разъяснение от OP:

В вашем определении структуры, третьего член является int, однако вы пытаетесь читать t35 в него (который является строкой).
Так var.age = atoi(ptr); даст вам 0,

Вы можете изменить определение структуры, что делает третий член в char * и выделении памяти, как и другие члены.

Или измените содержимое файла, убедившись, что в качестве третьего значения присутствует int.

Смежные вопросы