简体   繁体   中英

C - read specific line from file

I'm trying to read a specific line from a file and I can get the line number but I'm not sure how to go about doing it, this is what I have so far:

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

int main(int argc, char **argv)
{
  FILE *file;
  file = fopen("temp.txt","r");
  char tmp[256]={0x0};
  char *tmpline;
  int numline = 1;
  while(file != NULL && fgets(tmp, sizeof(tmp),file) !=NULL)
  {
    tmpline = strstr(tmp,"status:green");

    if(tmpline) {
      printf("%d - %s", numline, tmpline);
    }

    numline++;
  }
  if (file != NULL) fclose(file);

  return 0;
}

The test file looks like:

s1.server.com
127.0.0.1 
status:green

s2.server.com
127.0.0.1 
status:red

s3.server.com
127.0.0.1 
status:red

s4.server.com
127.0.0.1 
status:green

The output that I have is:

3 - status:green 
15 - status:green

But what I really want it to show is:

s1.server.com
s4.server.com

I want it to search for "status:green" then go back a few lines to show which server it belongs to

It sounds as if you need to do one of two things.

Simpler option : keep a little circular buffer of lines. Read into line 0, line 1, line 2, ..., line n-1, line 0, line 1, etc. Then, when you see the text you want, look in entry (current_index - 2) mod buffer_size. (Here it sounds as if a buffer size of 3 will suffice.)

More sophisticated option : actually parse the input so that for each block you work out the server name, its IP address and its status, and then display the information you need using that.

The "more sophisticated option" would be substantially more work, but more robust if the syntax of your input ever changes (eg, with optional extra lines with more information about the server -- multiple IP addresses or multiple names, perhaps).

There are some other things you could do that I think are worse. (1) Call ftell on each line and put the results of that in a circular buffer, and then use fseek when you see "status:green". (2) Read the whole file using code like you currently have, building up a list of "good" servers' line numbers. Then go through the file again and report the good ones. I think these are both uglier and less efficient than the approaches I listed above. There's one possible advantage: you can adapt them to count in "stanzas" separated by blank lines, without needing to parse things properly. That would get you part of the flexibility of the "more sophisticated" approach I mentioned, without needing a proper parser.

And here's a hybrid possibility: don't use a circular buffer, but one whose size can increase if need be. Start at the first entry in the buffer each time you see a blank line. Let the buffer grow if there are "long" stanzas. Then when you see "status:green", do whatever processing you need to on the (presumably complete) stanza now held in your buffer.

None of the above is necessary, of course, if you're sure that the file format will never change.

If the test file (and production file) is well-formed then you can do something like the following (error checking left out for brevity!):

typedef struct _SERVERSTATUS
{
    char* name;
    char* ip;
    char* status;
} SERVERSTATUS;


SERVERSTATUS ss;

ss.name = calloc(256);
ss.ip = calloc(256);
ss.status = calloc(256);

while (!feof(file))
{
    fgets(ss.name, file);
    fgets(ss.ip, file);
    fgets(ss.status, file);

    if (!strcmp(ss.status, "status:green"))
       printf("%s\n", ss.name);
}

free(ss.name);
free(ss.ip);
free(ss.status);

Edit: You also have to handle the whitespace between the file entries! That's, um, left as an exercise for the questioner

Read the first and third lines in each group. Search for status:green and, if found, print the server name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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