0

I have a text file in this format:

#Name                #Company             #ID
Name1                Brand1               1234
Name2                Brand2               5678

And a struct:

struct MyStruct{
  char name[TEXT_LEN];
  char company[TEXT_LEN];
  char ID[TEXT_LEN];
};
typedef struct MyStruct Data_t;

What I want... is to load the data from text file in appropriate variables. It should ignore first line because those are headers...

This is what I've been trying so far but without success:

int loadDataFromFile(Data_t *items, long len, char *inputFile)
{
  FILE *fp;

  if ((fp = fopen(inputFile, "r")))
  {
    for (long i = 0; i < len; i++)
    {
      /*fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);*/
     //this is commented part was not working part... More about this in EDIT
     fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);
     printf("Name: %s", items[i].name); // For first item it prints:
                                        // Name: #Name

    }
  }

  return 0;
}

What is wrong here?

EDIT

I've replaced the code but now it reads first line as well. Is there a way to ignore header of file (first line)?

harunB10
  • 4,823
  • 15
  • 63
  • 107
  • No, there shouldn't be space... While saving in file I use this: `fprintf(fp, "%-20s %-20s %-20s\n", "#Name", "#Company", "#ID");` for header and then for content - `fprintf(fp, "%-20s %-20s %-20s\n", items[i].name, items[i].company, items[i].ID);` – harunB10 Jun 03 '20 at 10:23
  • `printf` does not show anything. It seems that variables are not set... – harunB10 Jun 03 '20 at 10:30
  • 1
    (Previous comment deleted. I did not carefully read the question.) Check the return value of `fscanf`. It should be the expected number of input fields, i.e. 3 in this case. Anything else indicates an error or EOF. Then you can use `feof` and/or `ferror` to check the error indicator or EOF indicator. You can also check `errno` (or use `perror`) to find out what error occurred. In general you should check the return value of all functions and handle errors. Your function should probybly return something else than 0 if an error occurred. – Bodo Jun 03 '20 at 10:52
  • It works now - `fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);` but the problem is it reads first line too. When I output the name it has `#Name` ... Is there a way to skip first line of file? I'll have to Google that though. – harunB10 Jun 03 '20 at 10:55
  • 1
    @harunB10 You should [edit] your question and add all information there. What did you change to get your program work? – Bodo Jun 03 '20 at 10:58
  • Do you really know in advance how many lines you can read from the input file? To make your program more flexible I suggest to use `len` as the maximum number to read and return either the actual number of lines read or a negative number if an error occurred. – Bodo Jun 03 '20 at 11:08
  • @Bodo `len` will be max no. of lines. – harunB10 Jun 03 '20 at 11:11
  • I don't see any difference between the commented non-working `fscanf` and the working `fscanf`. Does the added `printf` make the program work? – Bodo Jun 03 '20 at 12:49

3 Answers3

1

Try This,

#include <stdio.h>

#define TEXT_LEN 100

typedef struct 
{

  char name[TEXT_LEN];
  char company[TEXT_LEN];
  char ID[TEXT_LEN];

}Data_t;

int loadDataFromFile(Data_t *items, long len, char *inputFile)  // change len as unsigned
{
  FILE *fp;
  char ch;
  long i;

  if ( ( fp = fopen(inputFile, "r") ) )
  {

    while( ( ch = getc(fp) != '\n') && ch!=EOF );   //To ignore first line
    printf("Reading...\n");

    for (i = 0; i < len && (fscanf(fp, "%s %s %s", items[i].name, items[i].company, items[i].ID) == 3); i++)
    {
        printf("\n#Name: %s #Company: %s #ID: %s", items[i].name, items[i].company, items[i].ID);
    }

  }
  else
  {
      printf("File Error");
      return 0;
  }


  return i;
}

int main()
{
    Data_t data[2];
    int n;

    if(n=loadDataFromFile(data,2,"Txt"))   //2 is number of line
    {
        printf("\n\nReaded !\n");

        for(int i=0;i<n;i++)
            printf("\n#Name: %s #Company: %s #ID: %s",data[i].name,data[i].company,data[i].ID);

    }

    return 0;
}

Txt:

#Name                #Company             #ID
Name1                Brand1               1234
Name2                Brand2               5678

Output:

Reading...

#Name: Name1 #Company: Brand1 #ID: 1234
#Name: Name2 #Company: Brand2 #ID: 5678

Readed !

#Name: Name1 #Company: Brand1 #ID: 1234
#Name: Name2 #Company: Brand2 #ID: 5678
[Done] exited with code=0 in 1.227 seconds
srilakshmikanthanp
  • 2,231
  • 1
  • 8
  • 25
  • 1
    Instead of `fscanf(...)!=EOF` I suggest to use `fscanf(...) == 3` because anything else means that not all 3 values were correctly parsed. If EOF occurs after at least one successful conversion, `fscanf` will not return EOF but the number of converted values. e.g. 1 or 2. – Bodo Jun 03 '20 at 12:34
  • @ Bodo thanks for your suggestion i updated that :) – srilakshmikanthanp Jun 03 '20 at 14:05
1

the following proposed code:

  1. cleanly compiles
  2. performs the desired functionality
  3. properly discards the first line of the input file (the column headers)
  4. properly checks for errors
  5. properly checks that the data array is not overflowed
  6. assures the fields in the data array are not overflowed when calling sscanf()
  7. properly assures the input file can be read

and now, the proposed code:

#include <stdio.h>
#include <stdlib.h>

#define TEXT_LEN 21

struct MyStruct
{
    char name[TEXT_LEN];
    char company[TEXT_LEN];
    char ID[TEXT_LEN];
};
typedef struct MyStruct Data_t;


long loadDataFromFile( Data_t *items, long len, char *inputFile )
{
    FILE *fp = fopen(inputFile, "r");
    if( ! fp )
    {
        perror( "fopen to read file failed" );
        exit( EXIT_FAILURE );
    }

    // read/discard first line:
    char buffer[1024];
    if( ! fgets( buffer, sizeof( buffer ), fp ) )   // column header line
    {
        perror( "fgets failed to read column headers from input file" );
        exit( EXIT_FAILURE );
    }

    long i = 0;
    while( i < len && fgets( buffer, sizeof( buffer ), fp ) )
    {   
        if( sscanf(buffer, "%20s %20s %20s", items[i].name, items[i].company, items[i].ID) != 3 )
        {
            break;
        }

        printf("Name: %s", items[i].name); 
        i++;
    }

    return i;
}
user3629249
  • 16,402
  • 1
  • 16
  • 17
0

you coult try changin

fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);

to

fscanf(fp, "%s\t%s\t%s\n", items[i].name, items[i].company, items[i].ID);

and also iterating on the file lines could be done better by using something like this

while (!EOF) {/*Code*/}
Massaynus
  • 322
  • 2
  • 9
  • 1
    What is `EOF` in `while(!EOF)`? If you mean something like `while(!feof(fp)){fscanf(fp,...);}`, this would be **wrong**. `feof` can be used to distinguish between EOF and other conditions **after** a file operation was performed. You have to check the return value of `fscanf`. If it is the expected number of fields, the input was successfully parsed. If it is something else, the reason might be unexpected input or EOF or an error. See https://stackoverflow.com/q/5431941/10622916 – Bodo Jun 03 '20 at 10:26
  • i took a look to that link, and i get the point.. actually thank you for letting me know – Massaynus Jun 03 '20 at 10:30
  • but i don't think for your use case it'll cause a problem, you only need to read the file lines until you reach the end, the the test will simply fail and you'll exit the loop... also i would like to know if the first part of my answer was helpful – Massaynus Jun 03 '20 at 10:31
  • `fscanf` can also fail if an error occurred. I don't know if it will also set the EOF indication in this case. – Bodo Jun 03 '20 at 10:55
  • A comment to the question shows the `fprintf` call used to write the data to the file. It uses a space to separate the fields, not a TAB (`\t`), and the fields are filled with spaces. That's why I think your proposed change won't help. – Bodo Jun 03 '20 at 11:14
  • if only you could use regular expressions in C – Massaynus Jun 03 '20 at 11:36