Thread: Changing writing code to reading code

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    216

    Changing writing code to reading code

    Hi, I have a program that writes out a list of files to a single or multi volume archive. It works very well. I need to write code that can extract the files though. Can most of the work be done by changing the fwrite's to fread's and vice versa?

    I know that it won't work 100% just by changing function calls, but I need to first understand the difficulty of this before I can tackle it.

    I can post my source code for archiving if needed.

    Thanks

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by binks View Post
    Hi, I have a program that writes out a list of files to a single or multi volume archive. It works very well. I need to write code that can extract the files though. Can most of the work be done by changing the fwrite's to fread's and vice versa?
    Yep! by changing fwrite() to fread() you can read all the data that's been written to the output file.
    Quote Originally Posted by binks View Post
    I know that it won't work 100% just by changing function calls, but I need to first understand the difficulty of this before I can tackle it.

    I can post my source code for archiving if needed.

    Thanks
    It'd be good to post the code, but in a nutshell it is doable by simply changing fwrite() to fread().

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Quote Originally Posted by itCbitC View Post
    Yep! by changing fwrite() to fread() you can read all the data that's been written to the output file.

    It'd be good to post the code, but in a nutshell it is doable by simply changing fwrite() to fread().
    And, Changing the fopen command.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    It may be that simple, or there may be much more to it.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Be aware that if the data file is moved to a different platform, you might run into endianness issues unless you're writing/reading 1 byte at a time.
    If you understand what you're doing, you're not learning anything.

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Ok, here is the code archive the files. This code works great.

    Code:
    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define BUFFER_SIZE 4096
    
    // Error function for outputting error
    void Error(char *output)
    {
        MessageBox(NULL, output, "Error", MB_OK);
        //PostQuitMessage(1);
        exit(1);
    }
    
    // Functions to obtain file information
    long int GetFileSize(char *fileName)
    {
        long int fileSize;
    
        FILE *fp = fopen(fileName, "rb");
    
        fseek(fp, 0, SEEK_END);
        fileSize = ftell(fp);
        fclose(fp);
        return fileSize;
    }
    
    int min3(size_t a, size_t b, size_t c)
    {
          if (a < b)
             return a < c ? a : c;
          else
             return b < c ? b : c;
    }
    
    FILE *OpenVolumeFile(char *archiveName, int volume)
    {
          char volumeName[256];
    
          FILE *fArchive;
    
          if (volume > 0)
              sprintf(volumeName, "%s-%d", archiveName, volume);
    
          else
             sprintf(volumeName, "%s", archiveName);
    
          if (!(fArchive = fopen(volumeName, "wb"))) Error("No file handle\n");
    
          printf("Volume = %d, creating archive file %s\n", volume, volumeName);
    
          return fArchive;
    
    }
    
    size_t ReadBuffer(FILE *fin, char *buffer, size_t bytesToRead)
    {
          size_t bytesRead;
    
          bytesRead = fread(buffer, 1, bytesToRead, fin);
          if(bytesRead < bytesToRead) Error("fread failure");
    
          return bytesRead;
    
    }
    
    // Write file header
    void WriteArchiveHeaderRecord(FILE* out, char fileName[][256], int fileNameLen, int fileSize)
    {
         // write filesize to bin
         if( fwrite(&fileSize, sizeof(fileSize), 1, out) != 1) Error("Could not write filesize header\n");
    
         // write filename length to bin
         if( fwrite(&fileNameLen, sizeof(fileNameLen), 1, out) != 1) Error("Could not write filename length to header\n");
    
         // write filename to header
         if( fwrite(fileName, 1, fileNameLen, out) != fileNameLen) Error("Could not write filename to header\n");
    
    }
    
    size_t WriteArchiveHeader(FILE *fArchive, size_t volSize, int numFiles,
                              char fileNames[][256], size_t *fileSizes)
    {
          size_t headerSize = sizeof numFiles + sizeof volSize +
                              numFiles * (sizeof *fileSizes + sizeof (size_t));
          int i;
    
          if( fwrite(&numFiles, sizeof(numFiles), 1, fArchive) != 1) Error("Error writing number of files to bin\n");
    
          if( fwrite(&volSize, sizeof(volSize), 1, fArchive) != 1) Error("Error writing volume size to bin\n");
    
          for(i = 0; i < numFiles; i++)
          {
                    size_t fileNameLen = strlen(fileNames[i]);
    
                    WriteArchiveHeaderRecord(fArchive, &fileNames[i], fileNameLen, fileSizes[i]);
    
                    printf("Filename: %s\tSize: %i\tFilename Length: %i\n", fileNames[i], fileSizes[i], fileNameLen);
    
                    headerSize += fileNameLen;
    
          }
    
          printf("Wrote file header -> Size: %d\n\n", headerSize);
    
          return headerSize;
    }
    
    // Write file to bin
    void WriteBuffer(FILE* out, char *buffer, size_t size)
    {
        // write data to outfile
        if( fwrite(buffer, 1, size, out) != size)  Error("Error writing file to bin\n");
    
    }
    
    void CreateArchive(char *archiveName, size_t  volSize, int numFiles, char fileNames[][256])
    {
          FILE   *fArchive;
    
          size_t  volBytesLeft;
          size_t  headerSize;
          size_t  fileSizes[numFiles]; // I got rid of the "file" struct
    
          int     i;
          int     volume = 0;
    
          for(i = 0; i < numFiles; i++)
                fileSizes[i] = GetFileSize(fileNames[i]);
    
          fArchive = OpenVolumeFile(archiveName, volSize>0 ? ++volume : 0);
    
          headerSize = WriteArchiveHeader(fArchive, volSize, numFiles, fileNames, fileSizes);
    
          if (volSize > 0)
             volBytesLeft = volSize - headerSize;
    
          else
             volBytesLeft = BUFFER_SIZE + 1; // ensure that it's greater than buffer size
    
          //volume = 0;
    
          for(i = 0; i < numFiles; i++)
          {
                    size_t fileBytesLeft = fileSizes[i];
    
                    FILE *fData = fopen(fileNames[i], "rb");
                    if(fData == NULL)  Error("Error opening file\n");
    
                    printf("File %i: %.2f MB\n", i + 1, (double)fileSizes[i] / 1024 / 1024);
    
                    do
                    {
                                  char buffer[BUFFER_SIZE];
                                  size_t bytesToRead, bytesRead;
    
                                  if(volBytesLeft == 0)
                                  {
                                                    fclose(fArchive);
    
                                                    volume++;
    
                                                    fArchive = OpenVolumeFile(archiveName, volume);
    
                                                    volBytesLeft = volSize;
                                  }
    
                                  bytesToRead = min3(sizeof buffer, fileBytesLeft, volBytesLeft);
    
                                  bytesRead = ReadBuffer(fData, buffer, bytesToRead);
    
                                  WriteBuffer(fArchive, buffer, bytesRead);
    
                                  fileBytesLeft -= bytesRead;
    
                                  volBytesLeft -= bytesRead;
    
                    }
                    while(fileBytesLeft > 0);
    
                    fclose(fData);
    
                    printf("Wrote file %i: %s\n\n", i + 1, &fileNames[i]);
    
          }
    
          fclose(fArchive);
          printf("Success!");
    }
    
    
    int main()
    {
        char fileNames[][256] = {"Test1.zip", "Test2.rar"};
        int volSize = 5;
        int numFiles = 2;
    
        //CreateArchive(char *archiveName, size_t  volSize, int numFiles, char *fileNames);
        CreateArchive("ArchiveName.bin", (size_t)volSize*1024*1024, numFiles, fileNames);
    
        return 0;
    }
    Here is what I have done so far to change it for extracting the files. Help is appreciated!

    Code:
    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define BUFFER_SIZE 4096
    
    // Error function for outputting error
    void Error(char *output)
    {
        MessageBox(NULL, output, "Error", MB_OK);
        //PostQuitMessage(1);
        exit(1);
    }
    
    int min3(size_t a, size_t b, size_t c)
    {
          if (a < b)
             return a < c ? a : c;
          else
             return b < c ? b : c;
    }
    
    FILE *OpenVolumeToExtract(char *archiveName)
    {
          char volumeName[256];
    
          FILE *fArchive;
    
          if (!(fArchive = fopen(archiveName, "wb"))) Error("No file handle\n");
    
          printf("Volume = %d, creating archive file %s\n", volume, volumeName);
    
          return fArchive;
    
    }
    
    size_t ReadBuffer(FILE *fin, char *buffer, size_t bytesToRead)
    {
          size_t bytesRead;
    
          bytesRead = fread(buffer, 1, bytesToRead, fin);
          if(bytesRead < bytesToRead) Error("fread failure");
    
          return bytesRead;
    
    }
    
    // Write file header
    void ReadArchiveHeaderRecord(FILE* out, char fileName[][256], int fileNameLen, int fileSize)
    {
         // write filesize to bin
         if( fread(&fileSize, sizeof(fileSize), 1, out) != 1) Error("Could not read filesize header\n");
    
         // write filename length to bin
         if( fread(&fileNameLen, sizeof(fileNameLen), 1, out) != 1) Error("Could not read filename length from header\n");
    
         // write filename to header
         if( fread(fileName, 1, fileNameLen, out) != fileNameLen) Error("Could not read filename from header\n");
    
    }
    
    size_t ReadArchiveHeader(FILE *fArchive, size_t volSize, int numFiles,
                              char fileNames[][256], size_t *fileSizes)
    {
          size_t headerSize = sizeof numFiles + sizeof volSize + numFiles * (sizeof *fileSizes + sizeof (size_t));
          int i;
    
          if( fread(&numFiles, sizeof(numFiles), 1, fArchive) != 1) Error("Error reading number of files from bin\n");
    
          if( fread(&volSize, sizeof(volSize), 1, fArchive) != 1) Error("Error reading volume size from bin\n");
    
          for(i = 0; i < numFiles; i++)
          {
                    size_t fileNameLen = strlen(fileNames[i]);
    
                    ReadArchiveHeaderRecord(fArchive, &fileNames[i], fileNameLen, fileSizes[i]);
    
                    printf("Filename: %s\tSize: %i\tFilename Length: %i\n", fileNames[i], fileSizes[i], fileNameLen);
    
                    headerSize += fileNameLen;
    
          }
    
          printf("Read file header -> Size: %d\n\n", headerSize);
    
          return headerSize;
    }
    
    // Write file to bin
    void WriteBuffer(FILE* out, char *buffer, size_t size)
    {
        // write data to outfile
        if( fwrite(buffer, 1, size, out) != size)  Error("Error writing file to bin\n");
    
    }
    
    void ExtractArchive(char *archiveName)
    {
          FILE   *fArchive;
    
          size_t  volBytesLeft;
          size_t  headerSize;
          size_t  fileSizes[numFiles]; // I got rid of the "file" struct
    
          int     i;
          int     volume = 0;
    
          fArchive = OpenVolumeFile(archiveName, volSize>0 ? ++volume : 0);
    
          headerSize = WriteArchiveHeader(fArchive, volSize, numFiles, fileNames, fileSizes);
    
          if (volSize > 0)
             volBytesLeft = volSize - headerSize;
    
          else
             volBytesLeft = BUFFER_SIZE + 1; // ensure that it's greater than buffer size
    
          //volume = 0;
    
          for(i = 0; i < numFiles; i++)
          {
                    size_t fileBytesLeft = fileSizes[i];
    
                    FILE *fData = fopen(fileNames[i], "rb");
                    if(fData == NULL)  Error("Error opening file\n");
    
                    printf("File %i: %.2f MB\n", i + 1, (double)fileSizes[i] / 1024 / 1024);
    
                    do
                    {
                                  char buffer[BUFFER_SIZE];
                                  size_t bytesToRead, bytesRead;
    
                                  if(volBytesLeft == 0)
                                  {
                                                    fclose(fArchive);
    
                                                    volume++;
    
                                                    fArchive = OpenVolumeFile(archiveName, volume);
    
                                                    volBytesLeft = volSize;
                                  }
    
                                  bytesToRead = min3(sizeof buffer, fileBytesLeft, volBytesLeft);
    
                                  bytesRead = ReadBuffer(fData, buffer, bytesToRead);
    
                                  WriteBuffer(fArchive, buffer, bytesRead);
    
                                  fileBytesLeft -= bytesRead;
    
                                  volBytesLeft -= bytesRead;
    
                    }
                    while(fileBytesLeft > 0);
    
                    fclose(fData);
    
                    printf("Wrote file %i: %s\n\n", i + 1, &fileNames[i]);
    
          }
    
          fclose(fArchive);
          printf("Success!");
    }
    
    
    int main()
    {
        char fileNames[][256] = {"Test1.zip", "Test2.rar"};
        int volSize = 5;
        int numFiles = 2;
    
        //CreateArchive(char *archiveName, size_t  volSize, int numFiles, char *fileNames);
        CreateArchive("ArchiveName.bin", (size_t)volSize*1024*1024, numFiles, fileNames);
    
        return 0;
    }

  7. #7
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    And, Changing the fopen command.
    Quoted for truth.

  8. #8
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Ok, so I have a problem. For the archiver, when I write the filenames, I write the full path. But if your extracting the files, the full path might not exist so it will fail. How can I remove the path upto the filename? Can I use strrchr to find the last '\' and only copy the letters after that? How?

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Oh, and I have changed some of the function parameters because they weren't necessary for the way of extraction.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. writing good code is like writing an artistic expression
    By renzokuken01 in forum C Programming
    Replies: 5
    Last Post: 02-03-2011, 08:48 PM
  2. anyone know a C++ api for reading/writing object code?
    By abkrino in forum C++ Programming
    Replies: 3
    Last Post: 11-16-2006, 06:19 AM
  3. changing default code in dev c++?
    By 7stud in forum C++ Programming
    Replies: 1
    Last Post: 12-15-2005, 05:06 PM
  4. Replies: 6
    Last Post: 05-12-2005, 03:39 AM
  5. changing code to something else
    By killdragon in forum C++ Programming
    Replies: 5
    Last Post: 08-30-2004, 06:00 PM