Thread: Reading and Writing certain amounts

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

    Reading and Writing certain amounts

    Hello all!

    I'm having a problem with my code. The purpose is that it will archive multiple files in a single or multi volume archive. However, it only writes a volume that is 1.10mb instead of the full 11.1mb. Here is my code.

    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, 0);
    
          else
             sprintf(volumeName, "%s", archiveName);
    
          if (!(fArchive = fopen(volumeName, "wb"))) Error("No file handle\n");
    
          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;
    }

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    Turn the warnings up on your compiler. The following two lines are incorrect
    Code:
    printf("Filename: %s\tSize: %i\tFilename Length: %i\n", &fileNames[i], fileSizes[i], fileNameLen);
    ...
    printf("Wrote file %i: %s\n\n", i + 1, &fileNames[i]);
    %s expects a string (a char *). fileNames is an array of char *, so fileNames[i] is a char * and &fileNames[i] is a pointer to a char *. Just drop the &.

    Then, take a closer look here:
    Code:
          if (volume > 0)
              sprintf(volumeName, "%s-%d", archiveName, 0);

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Why would the 0 be the problem, since the first archive needs to be called "name-0"?

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    The first time you call OpenVolumeFile, volume is 1 and volumeName is "ArchiveName.bin-0".
    The second time you call OpenVolumeFile, volume is 2. What is volumeName?

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Well, I have the volume size specified as 5 mb, so it stopping at 1.1 mb does not make sense. I'll check the OpenVolumeFile function and get back to you.

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    It doesn't "stop" at 1.1mb. You're misinterpreting the symptom, and coming up with a faulty diagnosis. You need more information than "when my program is finished, I have only one file, suffixed with a 0, that is smaller than I expect". You need

    Either step through this in a debugger, and examine all the relevant data at each possible failure point in your code, or put in lots of printf statements. I'm guessing you would debug this yourself if you knew how -- learn how to use your debugger sooner rather than later.

    Going the printf route, print out a line every time you open/close a new input file, so it would say:
    Code:
    opening 'Test1.zip' for reading
    closing 'Test1.zip'
    opening 'Test2.rar' for reading
    closing 'Test2.rar'
    Add printf statements that tell you how many bytes you have processed so far, perhaps output "wrote 1234 bytes to the archive".

    Add code that outputs the volume number every time it changes, and output the name of the file it is writing to for that volume. In particular, put the following piece of code at line 48, just before the fopen call in OpenVolumeFile:
    Code:
    printf("volume = %d, creating archive file %s\n", volume, volumeName);

  7. #7
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Ok, so with this modified OpenVolumeFile function, it now splits it into correct volumes successfully. BUT, now it stops at 6.10mb (before it was 1.1, now it's 5 + 1.1mb) So, should I be assuming it's a reading and writing error from the correct file, or is that correct, and I should be assuming it's an unrelated bug?

    Code:
    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;
    
    }

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    What do you expect it to be? How do you know 5mb + 1.1mb is wrong?

    EDIT: And instead of assuming it's doing anything, find out for sure! I already told you, either learn to use a debugger, or put lots of printf statements in your program so you know exactly what it is doing.

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    So, I tried using lots of printf statements, but I still have no clue. The program is doing what it's suppose to, but I can't find the mistake that is making it not do what I want it to.

    EDIT: Nevermind, found the problem! (it was quite silly actually)
    Last edited by binks; 06-08-2012 at 05:20 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 9
    Last Post: 07-07-2008, 03:04 PM
  2. reading and writing xml using c
    By cnu_sree in forum C Programming
    Replies: 3
    Last Post: 04-20-2007, 05:25 AM
  3. Reading and Writing
    By niroopan in forum C++ Programming
    Replies: 2
    Last Post: 10-16-2002, 02:17 PM
  4. Reading and Writing
    By niroopan in forum C++ Programming
    Replies: 5
    Last Post: 10-06-2002, 08:58 PM
  5. Reading and Writing in C++
    By niroopan in forum C++ Programming
    Replies: 3
    Last Post: 10-03-2002, 03:47 PM