0

a follow up to my previous question (Reading an entire file in binary mode using C++)

After reading a jpg file in binary mode, the result of the read operation is always 4 bytes. The code is:

FILE *fd = fopen("c:\\Temp\\img.jpg", "rb");
if(fd == NULL) {
    cerr << "Error opening file\n";
    return;
}
fseek(fd, 0, SEEK_END);
long fileSize = ftell(fd);
int *stream = (int *)malloc(fileSize);
fseek(fd, 0, SEEK_SET);
int bytes_read = fread(stream, fileSize, 1, fd);
printf("%x\n", *stream);
fclose(fd);

The second last printf statement is always printing the first 4 bytes and not the entire file contents. How can I print the entire content of the jpg file?

Thanks.

Community
  • 1
  • 1
pokiman
  • 956
  • 2
  • 12
  • 20
  • 1
    How do you want it formatted? You asked `printf` to display a single integer in hex, which is what it did. You could just do that in a `for` loop, but it'll be unreadable, so what's the output for? – Useless Feb 09 '12 at 18:12
  • well, i just want to dump the entire content of the file in hex... – pokiman Feb 09 '12 at 18:14
  • This is C, you should type `man fread` somewhere. You already got an answer for this question. – sinsedrix Feb 09 '12 at 18:16
  • C is a subset of C++. As such, this is just as much C++ as anything more object-oriented and modern. However, it makes sense to use simpler and safer techniques if you have the opportunity. – Amish Programmer Feb 09 '12 at 18:25
  • 1
    @JoshG: C is *no longer* a subset of C++. C99 is no longer compatible with C++. – Griwes Feb 09 '12 at 18:27
  • 1
    @JoshG C and C++ have a common subset. C is not a subset of C++ (not even C89). – R. Martinho Fernandes Feb 09 '12 at 18:27
  • @Griwes: C89 wasn't either. See that `(int*)` cast on the result of malloc? You don't need it in C. C++ code doesn't compile without it. (This code however, won't compile as C because it uses `cerr`) – R. Martinho Fernandes Feb 09 '12 at 18:29
  • @ Griwes & R. Martinho Fernandes - Thanks, I learned something today. At the same time, this is still valid C++ – Amish Programmer Feb 09 '12 at 18:31
  • @R.MartinhoFernandes, hmm, right. Forgot about how such casts are unnecessary in C... – Griwes Feb 09 '12 at 19:28

3 Answers3

3

You want it in C++? This opens a file, reads the entire contents into an array and prints the output to the screen:

#include <fstream>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

void hexdump(void *ptr, int buflen)
{
   unsigned char *buf = (unsigned char*)ptr;
   int i, j;
   for (i=0; i<buflen; i+=16) {
      printf("%06x: ", i);
      for (j=0; j<16; j++) { 
         if (i+j < buflen)
            printf("%02x ", buf[i+j]);
         else
            printf("   ");
      }
      printf(" ");
      for (j=0; j<16; j++) {
         if (i+j < buflen)
            printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
      }
      printf("\n");
   }
}

int main()
{
   ifstream in;

   in.open("C:\\ISO\\ITCHOUT.txt", ios::in | ios::binary);

   if(in.is_open())
   {
      // get the starting position
      streampos start = in.tellg();

      // go to the end
      in.seekg(0, std::ios::end);

      // get the ending position
      streampos end = in.tellg();

      // go back to the start
      in.seekg(0, std::ios::beg);

      // create a vector to hold the data that
      // is resized to the total size of the file    
      std::vector<char> contents;
      contents.resize(static_cast<size_t>(end - start));

      // read it in
      in.read(&contents[0], contents.size());

      // print it out (for clarity)
      hexdump(contents.data(), contents.size());
   }
}
Sriram Murali
  • 5,804
  • 2
  • 26
  • 32
Chad
  • 18,706
  • 4
  • 46
  • 63
  • Since you were using C++11 anyway (lambdas), I changed it to use a range-based for loop. Hope you don't mind :) – R. Martinho Fernandes Feb 09 '12 at 18:24
  • 1
    If you're just going to print out the contents of the file, `std::cout << in.rdbuf()` is a lot easier (and probably faster) than copying to memory and then printing. – André Caron Feb 09 '12 at 18:32
  • @R.MartinhoFernandes not at all. – Chad Feb 09 '12 at 18:49
  • @AndréCaron Sure, but the printing was just for brevity, because obviously the submitter is not looking to print the contents (of a JPEG) to the standard output. – Chad Feb 09 '12 at 18:49
0

stream is a pointer to an int (the first element of the array you allocated1). *stream dereferences that pointer and gives you the first int.

A pointer is not an array. A pointer is not a buffer. Therefore, it carries no information about the size of the array it points to. There is no way you can print the entire array by providing only a pointer to the first element.

Whatever method you use to print that out, you'll need to provide the size information along with the pointer.

C++ happens to have a pointer + size package in its standard library: std::vector. I would recommend using that. Alternatively, you can just loop through the array yourself (which means using the size information) and print all its elements.

1Make sure the size of the file is a multiple of sizeof(int)!

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
0

Something like the following should do it. bytes_read() gives you the number of blocks read, in your case the block size is the file size so only one block can be read.

You should use a for loop to print the whole file. You're only printing one pointer address.

            char *stream = (char *)malloc(fileSize);
            fseek(fd, 0, SEEK_SET);
            int bytes_read = fread(stream, fileSize, 1, fd);
            for(int i=0; i<fileSize; i++){
                    printf("%d ", stream[i]);
            }

I print the chars as numbers as binary data is not readable in the console. I don't know how you wanted the data to be formatted.

This is just meant as reference to your sample. You should really consider using Chad's sample. This is a far worse solution (as mixing C/C++ far too much) just for sake of completeness.

user1034081
  • 618
  • 5
  • 21