Obtaining File Sizes... - Programmers Heaven

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

Obtaining File Sizes...

SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
I nee dto obtain the size of a number of files, in bytes. I have been trying to use "GetFileSize()", but it always returns -1. The file does exist and is opened using "fopen()", but for some reason, it won't give me the size! Isn't there an easier more standard function call I can make that works? I seem to remember one or two in DOS C/C++ that returned (I think) a "double" variable. If they work in XP I can use them. Thanks for the info.

-[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]
«1

Comments

  • veliusvelius Posts: 456Member
    The GetFileSize() function needs a handle to the file. fopen() does not return a handle to the file. You need to use CreateFile() to obtain a handle to each file.
    [hr]
    Oh my god
    I can't deny this
    I've been taught just to kill and fight this
    To bury it deeper where nobody can find it
    Like nobody wanted to know
    -- Oh My God - Guns N' Roses

  • pingpongpingpong Posts: 937Member
    in standard C, you do this:
    [code]
    unsigned long get_file_size(const char* filename)
    {
    FILE* fp;
    unsigned long size;

    // open the file
    fp = fopen(filename, "rb");
    if(fp != NULL)
    {
    // seek to the end
    fseek(fp, SEEK_END, 0);
    // get the current position (this is the length of the file)
    size = ftell(fp);
    fclose(fp);
    }
    else
    size = (unsigned long)-1; // error

    return size;
    }
    [/code]
    If you already have a FILE* to the file, use this instead:
    [code]
    unsigned long get_file_size_from_handle(FILE* fp)
    {
    unsigned long current;
    unsigned long size;

    // save current position
    current = ftell(fp);
    // seek to the end
    fseek(fp, SEEK_END, 0);
    // get the current position (this is the length of the file)
    size = ftell(fp);
    // go back to original position
    fseek(fp, SEEK_SET, current);

    return size;
    }
    [/code]
    Course, this is C, files that are larger than 4G in size will not work. In Windows, you can use the FindFirstFile API to get the size. First version ignores >4G files:
    [code]
    unsigned long get_file_size(const char* filename)
    {
    WIN32_FIND_DATA wfd;
    HANDLE hFind;
    unsigned long size;

    hFind = FindFirstFile(filename, &wfd);
    if(hFind != INVALID_HANDLE_VALUE)
    {
    size = wfd.nFileSizeLow;
    FindClose(hFind);
    }
    else
    size = (unsigned long)-1;

    return size;
    }
    [/code]
    Next version gets any file size, dont know if you need it and up to you to figure out what to do with the 2 dwords:
    [code]
    bool get_file_size(const char* filename, unsigned long* low, unsigned long* high)
    {
    WIN32_FIND_DATA wfd;
    HANDLE hFind;
    bool ret;

    hFind = FindFirstFile(filename, &wfd);
    if(hFind != INVALID_HANDLE_VALUE)
    {
    *low = wfd.nFileSizeLow;
    *high = wfd.nFileSizeHigh;
    FindClose(hFind);
    ret = true;
    }
    else
    ret = false;

    return ret;
    }
    [/code]

  • SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
    The "fseek" method will work just fine. Thanks, I couldn't remember the way I used to do it to save my life. The files are WAY less than 4gb, so I should be good. And I chose not to use the Win32 API for this in case an X-Win port is ever made. Easier to port fopen() and fseek() than Win32 stuff!

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
    Actually, ftell() sets my variable to "2". The size of the file in explorer is 25 or 26kb, I forget which. I am thinking that since the cursor location is at "SEEK_END", it's returning the define for that location, which is 2 if I remember correctly. I know there is SEEK_SET and one other.

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • pingpongpingpong Posts: 937Member
    : Actually, ftell() sets my variable to "2". The size of the file in explorer is 25 or 26kb, I forget which. I am thinking that since the cursor location is at "SEEK_END", it's returning the define for that location, which is 2 if I remember correctly. I know there is SEEK_SET and one other.
    :

    I think explorer shows the file size rounded up to the cluster size of the hard disk. So, even if your file is 1 byte long, it will physically take cluster-size KB in the HD.

    Right click the file and do properties, one of the fields should show the exact size in bytes.
  • pingpongpingpong Posts: 937Member
    This is funny.

    I was working on some project at work and I needed to load a file to memory, proceeded with the fopen/fseek/ftell/fclose stuff and what do you know... The size reported back is 2!!!! It looked familiar :)

    Course, in both codes I was passing the parameters to fseek in the wrong order, so change fseek(fp, SEEK_XXX, x) to fseek(fp, x, SEEK_XXX).

    Thats what you get when you work with C
  • SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
    Yeah I figured it out this morning. I opened Wordpad and loaded the source, and it screamed at me. Swapped the parms and it worked fine. And I know explorer rounds. Just have a file-format problem that maybe you can explain.

    I am trying to convert Daggerfall IMG files to 24bit bitmaps. The IMG file format is easy enough and consists of a header followed by a linear bitmap. However the bitmap references a palette of RGB data. I know the 24bit bitmap format is BGR, but it isn't comming out right. I want you to see my code and make sure I am going from RGB to BGR properly, or if it's something else. If my bitmap code is correct, then I can concentrate on the old format.
    [code]
    bool ConvertIMG(char *FileName)
    {
    //About 200 lines from start to here, but left out
    //because they deal with reading the old IMG file

    BMFH.bfType = 0x4d42;
    BMFH.bfSize = ((sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)) + (((sizeof(char) * IMGHeader.Width) * IMGHeader.Height) * 3));
    BMFH.bfReserved1 = 0;
    BMFH.bfReserved2 = 0;
    BMFH.bfOffBits = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

    BMIH.biSize = sizeof(BITMAPINFOHEADER);
    BMIH.biWidth = IMGHeader.Width;
    BMIH.biHeight = -IMGHeader.Height;
    BMIH.biPlanes = 1;
    BMIH.biBitCount = 24;
    BMIH.biCompression = BI_RGB;
    BMIH.biSizeImage = 0;
    BMIH.biXPelsPerMeter = IMGHeader.Width;
    BMIH.biYPelsPerMeter = IMGHeader.Height;
    BMIH.biClrUsed = 0;
    BMIH.biClrImportant = 0;

    fwrite(&BMFH, sizeof(BITMAPFILEHEADER), 1, pImageFile);
    fwrite(&BMIH, sizeof(BITMAPINFOHEADER), 1, pImageFile);
    for(int Loop = 0; Loop < (IMGHeader.Width * IMGHeader.Height); Loop++)
    {
    fwrite(&(IMGHeader.Palette[pImage[Loop] + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop] + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop]]), sizeof(char), 1, pImageFile);
    }

    fclose(pImageFile);
    return true;
    }
    [/code]
    OK, IMGHeader.Palette is a "char[768]". That is a 256-color palette of RGB data in that order. The pImage is a pointer to a "char" array that was dynamically created with enough storage for the linear bitmap data. The bitmap data ranges 0-255 and references an RGB triplet in the palette. Does it look like I setup the two bitmap headers properly? I know I'm putting the RGB data into the new file as BGR, as you can see, but it isn't comming out right. If the bitmap is good, then I can concentrate on finding the right palette. Daggerfall uses like ten different palette-files, of which four are 768b in size and just contain an array of 256 RGB triplets. The others have an 8bit header, then the 256 RGB triplets.

    And on a final note, Daggerfall is a 16bit DOS game, so the files are byte-aligned. I read in the data like this:
    [code]
    //This would read int he first four header vars
    short int XOffset, YOffset;
    short int Width, Height;
    ...
    fread(&XOffset, sizeof(char[2]), 1, File);
    fread(&YOffset, sizeof(char[2]), 1, File);
    fread(&Width, sizeof(char[2]), 1, File);
    fread(&Height, sizeof(char[2]), 1, File);
    [/code]
    Those variables are "short" in DOS, which are 2bytes in size. I assume this is the correct way to read them in. After all, the image comes out nearly-perfect, but off-color. Thanks for the help!

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
    [code]
    : fwrite(&(IMGHeader.Palette[pImage[Loop] + 2]), sizeof(char), 1, pImageFile);
    : fwrite(&(IMGHeader.Palette[pImage[Loop] + 1]), sizeof(char), 1, pImageFile);
    : fwrite(&(IMGHeader.Palette[pImage[Loop]]), sizeof(char), 1, pImageFile);
    [/code]
    That was the color problem. The lines shoulda' been this.
    [code]
    fwrite(&(IMGHeader.Palette[(pImage[Loop] * 3) + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[(pImage[Loop] * 3) + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop] * 3]), sizeof(char), 1, pImageFile);
    [/code]
    But the image comes out slanted. The first line or two is fine, then it slants. Do I have to pad the bitmap data somehow? I thought I read something about that somewhere.

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • pingpongpingpong Posts: 937Member
    Yup, BMP scan lines are padded to 32-bit boundaries.

    this is a function to calculate the bytes/line:
    [code]
    int GetBytesPerLine(int width, int bitsPerPixel)
    {
    return ((width * bitsPerPixel + 31) >> 5) << 2;
    }
    [/code]
    Dont ask!

    Now, you might change your code to be liks this:
    [code]
    // get the size of a scanline
    int bytesPerLine = GetBytesPerLine(BMIH.biWidth, BMIH.biBitCount);
    // get number of extra bytes we need to pad with (*3 since its BGR)
    int extra = bytesPerLine - width * 3;

    for(int y = 0; y < IMGHeader.Height; y++)
    {
    for(int x = 0; x < IMGHeader.Width; x++)
    {
    // write one line as usual
    fwrite(&(IMGHeader.Palette[(pImage[x + y * IMGHeader.Height] * 3) + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[(pImage[x + y * IMGHeader.Height] * 3) + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[x + y * IMGHeader.Height] * 3]), sizeof(char), 1, pImageFile);
    }

    // pad
    for(int pad = 0; pad < extra; pad++)
    {
    char dummy = 0;
    fwrite(&dummy, sizeof(char), 1, pImageFile);
    }
    }
    [/code]
    I havent tested the code but you should get the idea
  • SephirothSephiroth Fayetteville, NC, USAPosts: 1,035Member
    That fixed the color problem. It now displays the proper color, partially. The image is now twisted and it looks like the RGB data isn't right somehow. I'll post the code, but here's a link tot he image to see what I mean.

    http://dhta.oesm.org/sephiroth/WOLF00I0.IMG.jpg

    [code]
    //Setup our bitmap headers
    BMFH.bfType = 0x4d42;
    BMFH.bfSize = ((sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)) + (((sizeof(char) * IMGHeader.Width) * IMGHeader.Height) * 3));
    BMFH.bfReserved1 = 0;
    BMFH.bfReserved2 = 0;
    BMFH.bfOffBits = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

    BMIH.biSize = sizeof(BITMAPINFOHEADER);
    BMIH.biWidth = IMGHeader.Width;
    BMIH.biHeight = -IMGHeader.Height;
    BMIH.biPlanes = 1;
    BMIH.biBitCount = 24;
    BMIH.biCompression = BI_RGB;
    BMIH.biSizeImage = 0;
    BMIH.biXPelsPerMeter = IMGHeader.Width;
    BMIH.biYPelsPerMeter = IMGHeader.Height;
    BMIH.biClrUsed = 0;
    BMIH.biClrImportant = 0;

    //Setup the vars used for padding bitmaps
    Padding = 0;
    ExtraBytes = GetPadding(BMIH.biWidth, BMIH.biBitCount) - BMIH.biWidth * 3;

    //Write the bitmap, with padding
    fwrite(&BMFH, sizeof(BITMAPFILEHEADER), 1, pImageFile);
    fwrite(&BMIH, sizeof(BITMAPINFOHEADER), 1, pImageFile);
    for(int Y_Loop = 0; Y_Loop < IMGHeader.Height; Y_Loop++)
    {
    for(int X_Loop = 0; X_Loop < IMGHeader.Width; X_Loop++)
    {
    FileSize = (X_Loop + (Y_Loop * IMGHeader.Width));
    fwrite(&(IMGHeader.Palette[(pImage[FileSize] * 3) + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[(pImage[FileSize] * 3) + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[FileSize] * 3]), sizeof(char), 1, pImageFile);
    }

    for(int PadLoop = 0; PadLoop < ExtraBytes; PadLoop++)
    fwrite(&Padding, sizeof(int), 1, pImageFile);
    }
    [/code]
    See anything still wrong? If I can "un-twist" this image and display it properly, My work on the converter will be complete!

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

«1
Sign In or Register to comment.