Home > database >  Scan a particular line in a text-file with fscanf in C?
Scan a particular line in a text-file with fscanf in C?

Time:12-10

I want to do a search in a textfile with fscanf. It's a number that I'm searching for, and the numbers are in order by value. Therefore, I want to do a binary search, starting from the middle and so on. My idea was to first count the number of lines, divided by two to find the middle. But how to tell fscanf to look at that line?

int seach_textfile(struct data *ean13, unsigned long long int *input)
{
    FILE *fp_read = fopen("data.tex", "r");
    unsigned long long int read, n_lines;

    // count lines
    n_lines = 0;
    while (fscanf(fp_read,"\n") == 1)
    {
        n_lines  ;
    }

    int n_line_low = 0;
    int n_line_mid;
    int n_line_high =n_lines;

    while(n_line_high>n_line_low)
    {
        n_line_mid; = (n_line_low   n_line_high)/2;
        fscanf(fp_read,"%lld \n", read).... at n_line_mid  // <----here!! (only to read first entr on line)
        if(*input > read)
        {
            n_line_low = n_line_mid  1;
        }
        else
        {
            n_line_high = n_line_mid;
        }
    } 
    if(*input == read)
    {
        fscanf(fp_read,"%lld %s %s %s",*ean13->ean,*ean13->country,*ean13->manufacture,*ean13->product).... at n_line_mid  // <----here!!
        return 1;
    }
    else return 0;
}

CodePudding user response:

OP's code fails to find the line count as fscanf(fp_read,"\n") only reads leading white-space and block on first on-white-space.

Line count is not that useful anyways as it only search to find an approximate location to seek. File length would afford the same.


Alternative

  1. Open the text file in binary mode.

  2. Quickly determine its length. (e.g. sum of repeated fread()s, or fstat() if available).)

  3. left = 0; right = length-1

  4. mid = (left right)/2 Use fseek(mid).

  5. fgetc() or fgets() to line end: e.g. Look for '\n' or EOF.

  6. Read number. If match, we are done.

  7. If too big, right = mid - 1. If too small, left = ftell().

  8. If right >= left, loop back to step 4.

  9. Fail - number not found.

Check I/O function return values along the way.

If code needs to look for another number, omit step 2 as the file length is already known.

CodePudding user response:

I would read all the lines first and store them in the linked list. Then you can do whatever you want. You can add prev pointer as well if you going backwards.

typedef struct line
{
    struct line *next;
    char line[];
}line;


#define MAXLINE (8*1024)


line *readFile(FILE *fi, int removeLF)
{
    char *workbuff = malloc(MAXLINE);
    line *head = NULL, **current = &head;
    if(fi && workbuff)
    {
        while(fgets(workbuff, MAXLINE, fi))
        {
            size_t len = strlen(workbuff);
            *current = malloc(sizeof(**current)   len   1);
            if(current)
            {
                memcpy(current[0] -> line, workbuff, len   1);
                if(removeLF && current[0] -> line[len - 1] == '\n') current[0] -> line[len - 1] = 0;
                current = &current[0] -> next;
            }
        }
    }
    *current = NULL;
    return head;
}

void print(line *lines)
{
    size_t cline = 0;
    do
    {
        printf("line no %zu = `%s`\n",   cline, lines -> line);
        lines = lines -> next;
    }while(lines);
}

  
int main(void)
{
    line *file = readFile(stdin, 1);
    print(file);
}
  • Related