OK, so I know that I can search binary records in C, by entering the number and returning the corresponding data, however I need to search a binary file using text. In my opinion I would need to load this file into a buffer and search the buffer for the required output. My problem is, if that idea is correct, I have no idea what I am doing. Can someone help please?

Recommended Answers

All 30 Replies

Yes, I would load the file into a buffer and search the buffer for the string. When searching for the string, I would loop through each character of the buffer and compare each character to the first character of the string you are looking for. Whenever you find the first character, just check to see if the rest of the string is there.

Do you know if there is Code Snippet on DaniWeb to do demonstrate this?

If you'll post up a small example of the file, as an attachment, we can show it.

I'm not sure what is included in Code Snippets.

Post up an example of what? I don't know how to load a binary file into a buffer and search it.

Show us at least what you have attempted so far.

Using strchr() or strstr(), along with a smart search logic to keep it fast, is what I'd recommend. Boyer-Moore algorithm is tops, but may be much more than what you need.

Your compiler has a BUFSIZE that will be a good value to start with for your buffer array size.

OK. I've got a few different ideas.

Here is the code that I managed to put together so far:

void record_search(const char *filename)
{
  FILE  *file = fopen(filename, "rb");
  char  *buffer;
  int   i;
  unsigned long fileLen;
  
  struct record data;
  
  if(!file) {
    fprintf(stderr, "Unable to open file [%s]", filename);
    return;
  }
  
  /* Get file length */
  fseek(file, 0, SEEK_END);
  fileLen = ftell(file);
  fseek(file, 0, SEEK_SET);
  
  /* Allocate memory */
  buffer = (char *) malloc(fileLen + 1);
  if(!buffer) {
    fprintf(stderr, "Memory error!");
    fclose(file);
    return;
  }
  
  /* Read the file contents into buffer */
  fread(buffer, fileLen, 1, file);
  fclose(file);
  
    for(i = 0;i < *buffer;++i)
     printf("%d\n", ((char *)buffer)[i]);
}

And it outputs junk (mainly numbers like -147, 70, 8, 10), etc.

Change the %d print format to the correct %c, and see how it looks. ;)

Can you give some of the details of what you're trying to find in the text?

OK, now it prints out some random junk such as

B
u
i
l
d
i
n
g


☺
☼
♫

Basically, what it is is that I've stored some information in a binary file. Such as 3 bits of data, and I want to search for these and display them if found. They are all characters.

>>And it outputs junk (mainly numbers like -147, 70, 8, 10), etc.

Exactly -- binary files can not always be read, which is why they are called binary files. You have to know how the binary file is formatted before you can make any sense out of them. For example, if the file were written like this

FILE* fp = fopen(filename, "wb");
int x = 123;
fwrite((char *)&x, sizeof(int), fp);

Then the only way to read the file is like this:

FILE* fp = fopen(filename, "rb");
int x;
fread((char *)&x, sizeof(int), fp);

or something like this

FILE* fp = fopen(filename, "rb");
int x;
char buffer[255];
int bufsize;
fseek(0, SEEK_END);
bufsize = fp.ftell();
fseek(0, SEEK_SET);

fread((char *)buffer,bufsize , fp);
x = *(int *)buffer;

Most binary files are a hell of a lot more complicated than the above. Show us how the file was written and we can show you how to read it.

Ah, Ancient, you are a genius! I never thought of that!

OK, so I'm writing it like so:

void record_write(const char *filename)
{
  FILE *file = fopen(filename, "ab");
  if(file != NULL) {
    struct record data;

    printf("\n   Enter book ISBN: ");
    fflush(stdout);
    getline(data.isbn, sizeof data.isbn);

    printf("\n   Enter book author: ");
    fflush(stdout);
    getline(data.author, sizeof data.author);

    printf("\n   Enter book title: ");
    fflush(stdout);
    getline(data.title, sizeof data.title);


    fwrite(&data, sizeof data, 1, file);
    fclose(file);
  }
}

All you have to do is replace fwrite() with fread(). I assume data is a struure with fixed-length character arrays instead of pointers.

Ah. By this logic I assume this is correct?

void record_search(const char *filename)
{
  fflush(stdin);
  FILE *file = fopen(filename, "ab");
  if(file != NULL) {
    struct record data;

    printf("\n   Enter book author: ");
    fflush(stdout);
    getline(data.author, sizeof data.author);

    fread(&data, sizeof data, 1, file);
    printf("%s\n", data.title);
    fclose(file);
  }
}

It accepts input but outputs junk... if I replace the $s with $d it outputs an integer.

Since you are reading the file you need to open it with "rb" instead of "ab"

Also check the return value of fread() to see how many bytes were actually read.

Ah. OK, now it outputs some legit data. However, no matter what I search for it always has the same output.

The file probably contains more than one record, so you have to use a loop to read each of the records until end-of-file is found.

while( fread(&data, sizeof data, 1, file) == sizeof(data) )
    printf("%s\n", data.title);

OK, so now it's no longer printing at all, Ancient:

void record_search(const char *filename)
{
  fflush(stdin);
  FILE *file = fopen(filename, "rb");
  if(file != NULL) {
    struct record data;

    printf("\n   Enter book author: ");
    fflush(stdout);
    getline(data.author, sizeof data.author);

    while(fread(&data, sizeof data, 1, file) == sizeof(data)) {
      printf("%s\n", data.title);
    }
    
    
    fclose(file);
  }
}

Oops! should have been while(fread(&data, sizeof data, 1, file) > 0)

Ah, this works. I reckon another way I could have done it would have been

while(fread(&data, sizeof data, 1, file) == 1)

Anyway. I need to compare some stuff. For example, type in the author's name and find the title associated with this? If you follow me?

Yes you will have to compare the author's name you type with the records found in that loop. Warning! do NOT use the same data item for both as you have posted on line 10. Use a different character array for that purpose so that its contents do not get destroy during the fread() loop.

Ancient, do you know if there is a code example of this on DaniWeb? I had the idea of trying to compare like if(data.title == data.author) , however this will obviously not work.

use strcmp() to compare the two.

BTW: C language does not have a getline() function. You have to call fgets() to do that.

But if I use strcmp() then the two values will be different (author and title). I'm really confused now. ☺

why would you want to compare a person's name with the title of a book?

Right. :) Let me explain the binary file. It is organised like so:

TITLE, AUTHOR, ISBN.

I would like to search the system for AUTHOR. If it finds AUTHOR I want it to display the TITLE and ISBN associated. Example could be:

THE ROAD AHEAD, BILL GATES, XX-XXXXXXXX-XXXXX

For example.

My statement still stands -- it makes no sense to compare author and title. You need to do something like this:

void record_search(const char *filename)
{
//  fflush(stdin); <<< non-standard
  char author[sizeof(data.author)+1];
  char *ptr;
  FILE *file = fopen(filename, "rb");
  if(file != NULL) {
    struct record data;

    printf("\n   Enter book author: ");
    fflush(stdout);
    fgets(author,sizeof(author),stdin);
    //getline(data.author, sizeof data.author); <<< no such function in C language
    // remove trailiing '\n' that fgets() inserts into the sttring
    ptr = strchr(author,'\n');
    if( ptr != NULL)
       *ptr = '\0';


    while(fread(&data, sizeof data, 1, file) == sizeof(data)) {
    if( strcmp(data.author, author) == 0)
      printf("%s,%s,%s\n", data.author,data.title,data.isbn);
    }
    
    
    fclose(file);
  }
}

Also, your example shows a comma separated text file. In that case you do not want to use binary file techniques so the above code won't work. Read each line using fgets() then split it into its individual parts by parsing that line to find each comma, such as strchr().

Ah, this is helping me to understand. I took the code, modified it slightly to fit what I required, however once I enter author's name, I get no printing whatsoever...?

Ancient! I solved this by changing while(fread(&data, sizeof data, 1, file) == sizeof(data)) to while(fread(&data, sizeof data, 1, file) > 0)

Just out of interest, how can I partially match this? Just as I was testing it, if I failed to enter the full string it returned no results found.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.