Thread: Read Bytes From File Into Integer

  1. #1
    Chad Johnson
    Join Date
    May 2004
    Posts
    154

    Read Bytes From File Into Integer

    I'm sure this question has been asked here before, but I've searched and haven't found the answer I'm looking for.

    In C, NOT C++ (using stdio), suppose I write a value to a file:

    Code:
    FILE *fp = fopen ("data.txt", "wb");
    int myValue = 1500;
    
    fwrite (&myValue, 2, 1, fp);
    Now, how do I read this integer value from the file, since it's stored across two bytes, and get 1500 as an integer again?

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Would you believe, with fread? Seems kind of unbelievable, doesn't it?

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    ~viaxd() viaxd's Avatar
    Join Date
    Aug 2003
    Posts
    246
    since it's stored across two bytes, and get 1500 as an integer again?
    i don't think you can, b/c you're writing only 2 bytes of the 4 byte integer.

    [edit]
    oh, wait, yes you can.
    Code:
    n = getc(fp);
    n |= getc(fp) << 8;
    that's little endian, so if your machine is big endian that would be
    Code:
    n = getc(fp) << 8;
    n |= getc(fp);
    [/edit]
    Last edited by viaxd; 08-13-2004 at 10:15 AM.
    :wq

  4. #4
    Chad Johnson
    Join Date
    May 2004
    Posts
    154
    Well when I use fread,

    Code:
    int byteVal;
    
    fread (&byteVal, 2, 1, fp)
    It doesn't work and I get a really big number (4195804 -apparently an address). It even does this when I try to input four bytes.

    Here's my full program:

    Code:
    #include <stdio.h>
    
    int main ()
    {
        FILE *fp;
    	int number = 1500;
        int inpNumber;
    	
    	fp = fopen ("test.txt", "wb");
    	fwrite (&number, 2, 1, fp);
    	fclose (fp);
    
    	fp = fopen ("test.txt", "rb");
    	fread (&inpNumber, 2, 1, fp);
    	fclose (fp);
        
        printf ("%i", inpNumber);
    
        return 0;
    }

  5. #5
    Registered User glUser3f's Avatar
    Join Date
    Aug 2003
    Posts
    345
    Do NOT hard-code sizes, use the sizeof operator:

    Code:
    FILE *fp = fopen ("data.txt", "wb");
    int myValue = 1500;
    fwrite(&myValue, sizeof(myValue), 1, fp);
    Code:
    FILE *fp = fopen ("data.txt", "rb");
    int myValue;
    fread(&myValue, sizeof(myValue), 1, fp);

  6. #6
    ~viaxd() viaxd's Avatar
    Join Date
    Aug 2003
    Posts
    246
    Do NOT hard-code sizes, use the sizeof operator:
    i think he wants it to be 2 bytes, that's why he doesn't use sizeof
    :wq

  7. #7
    Chad Johnson
    Join Date
    May 2004
    Posts
    154
    Yes, I created a file of my own format, and I have different [integer] data items that span two or more bytes. I just need to know how to read one of these variables, whether it is two, three, or four bytes in length and store it in an integer so my program can work with it. Therefore, sizeof() wil not work.

  8. #8
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    What are you talking about exactly? If you write an int to the file, read an int to the file and use sizeof(int). If you write a short to the file then read a short to the file and use sizeof(short). If you have an int (and int is 4 bytes on your system) then writing 2 bytes of the integer isn't always going to work. Different machines with different endianness store the bytes in different orders. For example, if you have a 4-byte int that's set to 255, it might look in memory like 0x00FF0000 or 0x000000FF or probably even different combinations. Anyway, unless you really know what you're doing, write the entire variable to the file and read the entire variable back from the file. And also note that if you try to read the int in from the file it might not be the right number if the file was created on a different computer.
    If you understand what you're doing, you're not learning anything.

  9. #9
    Registered User glUser3f's Avatar
    Join Date
    Aug 2003
    Posts
    345
    Quote Originally Posted by ChadJohnson
    Yes, I created a file of my own format, and I have different [integer] data items that span two or more bytes. I just need to know how to read one of these variables, whether it is two, three, or four bytes in length and store it in an integer so my program can work with it. Therefore, sizeof() wil not work.
    Well, then viaxd's method should do the trick.

    You can also use unions to access individual bytes of an integer:

    Code:
    #include <stdio.h>
                                                                                    
    union MY_INT {
            int val;
            char arr[4];
    };
                                                                                    
    int main(void) {
            union MY_INT i;
            i.val = 1500;
            printf("%d, %d, %d, %d: %d\n", i.arr[0], i.arr[1], i.arr[2], i.arr[3]);
            return 0;
    }

  10. #10
    Chad Johnson
    Join Date
    May 2004
    Posts
    154
    OK cool, I'll look into unions.

    Here is the format of my file:

    Code:
    length of title in bytes	(1 byte)
    title
    length of copyright in bytes	(1 byte)
    copyright
    number of books		(2 bytes)
    locations of each book	(4 bytes each)
    length of book name in bytes	(1 byte)
    book name
    number of chapters in book	(2 bytes)
    locations of each chapter	(4 bytes each)
        [beginning of chapter]
    number of verses in chapter	(2 bytes)
    locations of each verse	(4 bytes each)
    length of each verse in bytes	(2 bytes)
    verse text
    Obviously, I am writing a Bible program. I also already have sucessfully created this file. Right now I am just writing a console C program to access the text for each chapter, and when I have that done, I want to make a wxWidgets program that will do this graphically. So the file needs to be compatible with Windows, Linux, Mac, and whatever else supports wxWidgets.

    Now that you know what I am doing, what would you suggest that I do about reading the data from my file? Should I structure it differently? Should I just do what you said and write an int to the file and read an int (and make the 2-byte variables be 4-bytes)?

    Or could/should I even do something with bit-shifting?
    Last edited by ChadJohnson; 08-13-2004 at 12:33 PM.

  11. #11
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Another way to see what is actually in the file is to cast the address of an int to the address of a char.

    Now, you can't just read two bytes into an int variable and expect to get something meaningful unless you know what's in the other bytes.

    Also, the order in which the bytes are stored is processor-dependent, since compilers usually store int data in the "natural mode" of the processor (big-endian vs little-endian).

    Try this on your machine to see if you get any insight into why you could get the results that you saw. I have left the fwrite() the way that you had it, and read the bytes back in with a corresponting fread().

    In any program that you intend to use or release for others to use, you should always have lots of error checking (I have left it as an exercise).

    On Intel machines (Windows as well as Linux), the file data.txt consisted of exactly two bytes: 0xdc and 0x05.



    Code:
    #include <stdio.h>
    
    int main()
    {
      FILE *fp;
      int i;
      int myValue;
      int inValue;
      unsigned char *ChPoint;
    
      myValue = 1500;
      ChPoint = (unsigned char *)&myValue;
    
      printf("sizeof(myValue) = %d\n", sizeof(myValue));
    
      printf("myValue = %d, (%08x hex)\n", myValue, myValue);
    
      for (i = 0; i < sizeof(myValue); i++) {
        printf("byte %d = %02X\n", i, *(ChPoint + i));
      }
    
    
      /* write the bytes */
      fp = fopen("data.txt", "wb"); /* should do error checking */
      fwrite (&myValue, 2, 1, fp);  /* should do error checking */
      fclose(fp);
    
      /* read two bytes into an integer */
      inValue = 0;
      printf("Before reading: inValue = %d (%08x hex)\n", inValue, inValue);
      fp = fopen("data.txt", "rb"); /* should do error checking */
      fread(&inValue, 2, 1, fp);    /* should do error checking */
      fclose(fp);
    
      printf("After  reading: inValue = %d (%08x hex)\n\n", inValue, inValue);
    
      /* read two bytes into an integer */
      inValue = -1;
      printf("Before reading: inValue = %d (%08x hex)\n", inValue, inValue);
      fp = fopen("data.txt", "rb"); /* should do error checking */
      fread(&inValue, 2, 1, fp);    /* should do error checking */
      fclose(fp);
    
      printf("After  reading: inValue = %d (%08x hex)\n", inValue, inValue);
    
      return 0;
    }
    Regards,

    Dave

  12. #12
    Chad Johnson
    Join Date
    May 2004
    Posts
    154
    wait a sec...how did setting inValue to 0 change the result?

  13. #13
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by ChadJohnson
    wait a sec...how did setting inValue to 0 change the result?
    The function fread() puts two bytes into the 4-byte variable. The upper two bytes were "something else", therefore giving different values. Look at the for(){} loop near the beginning of the program. Put copies of this loop before and after the fread() statements.

    Two observations:
    1. It makes sense once you get it.
    2. It's easier to do than it is to talk about it.

    This example also shows why you can't prove that a program works just by testing. In my case, the Borland compiler gave the "right" answer even when I didn't make any assignment to inValue (but gcc didn't). Bottom line: when you are reading (binary) bytes, make sure you know where they are going, and what else is there.

    Dave

  14. #14
    Chad Johnson
    Join Date
    May 2004
    Posts
    154
    So should it work if I just initialize the variable to 0?


    What if I just did a bit-shift and shifted everything x bits - would that work? (sorry this is my first time really working with bits)
    Last edited by ChadJohnson; 08-13-2004 at 02:39 PM.

  15. #15
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by ChadJohnson


    What if I just did a bit-shift and shifted everything 2 bits - would that work? (sorry this is my first time really working with bits)
    I'm not sure what you mean.

    The function fread() stores a certain number of bytes into memory locations starting at the (byte) address that you give it.

    If you want to read one byte at a time and use shift-store into an int, you could consider:

    1. Read the first byte into a variable of type unsigned char; suppose its name is byte1.

    2. Read the second byte into a variable of type unsigned char; suppose its name is byte2.

    Now calculate and store the integer value:

    Code:
      int_value = byte1 + 256*byte2;
    or, if you prefer logic:

    Code:
      int_value = byte1 | (byte2 << 8);
    where I have assumed that char data are one byte, and a byte is eight bits. (I have also assumed little-endianness of int storage.)

    The assignment statement takes care of all of the bits, whereas fread() just stores the bits in the bytes it gets.

    Dave

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. Link List math
    By t014y in forum C Programming
    Replies: 17
    Last Post: 02-20-2009, 06:55 PM
  3. Replies: 7
    Last Post: 02-06-2009, 12:27 PM
  4. Replies: 3
    Last Post: 03-02-2008, 12:33 PM
  5. load gif into program
    By willc0de4food in forum Windows Programming
    Replies: 14
    Last Post: 01-11-2006, 10:43 AM