Thread: Windows Specific File I/O

  1. #46
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Neo1 View Post
    Why is that? I'm using the same handles for many of the CreateFile calls, so i figured that i'd only have to close those handles and then i'm good. I'm assuming that when i call CreateFile on a handle that already has a file associated with it, the previous file gets overwritten? Or does that just mean that i leaks?
    It's just a value. Like a pointer to an unknown struct or the like.
    You're overwriting it and thus causing a leak. That's why you must close each handle first.

    But in essence, what you are saying is that i should call CloseHandle inside the loop? Like this..
    Yes! After you're done with the handle (don't need it anymore), you must close it. And if you assign it again, as you do, you're overwriting the previous value, so it becomes lost forever. CreateFile creates a new handle and returns it.

    Actually, i just assumed that Elysias proposal would work, didn't really think too much about what the code actually does, i guess that was a bit naive of me...

    If the integers don't match up when i'm dividing, it gets truncated right? So if i have say 889 Bytes that i wan't to split into 3 files, itt'l truncate the last byte? Shouldn't i just add 1 to the size of the buffer and the last call to WriteFile then? To make sure it gets it all?
    Perhaps you should read my above reply again, if you haven't already.
    You need to weak the formula a bit, that's all. Your files won't be 100% the same size, but that's something you're going to have to live with.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #47
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by Neo1 View Post
    1. Ill look into adding proper error checking when it works as it is supposed to.
    Error checking is for when your program doesn't work. Your program doesn't work, so now is the time to do the error checking.
    Last edited by robwhit; 03-03-2008 at 05:18 PM.

  3. #48
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Correct formula:
    Code:
    DWORD inputSize = ...;
    DWORD fileCount = ...;
    DWORD baseOutSize = inputSize / fileCount;
    DWORD remainder = inputSize % fileCount; // or inputSize - (fileCount * baseOutSize)
    std:.vector<char> buffer(baseOutSize+1);
    for(DWORD i = 0; i < fileCount; ++i) {
      DWORD thisSize = baseOutSize + ((i < remainder) ? 1 : 0);
      // ...
      HANDLE hOut = CreateFile(...);
      if(hOut == INVALID_HANDLE_VALUE) { error }
      if(!ReadFile(hOut, ..., thisSize, ...)) { error }
      if(!WriteFile(hOut, ..., thisSize, ...)) { error }
      CloseHandle(hOut);
    }
    For a file size of 23 bytes and 5 files, this will create the first 3 files with 5 bytes each and the remaining 2 files with 4 bytes each, for a total of 23 bytes. It's the most even distribution possible, with file sizes never straying more than a byte.


    Error checking is for when your program doesn't work. Your program doesn't work, so now is the time to do the error checking.
    Error checking is for always.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #49
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    ReadFile() can also return success (true) but NOT read the required number of bytes (ie if trying to read past the EOF etc).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #50
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In this program, this could only happen through a race condition, though. That is, after the program has determined the file size, but before it opens it for reading, another comes along and modifies the input file.
    Most Win32 API functions don't suffer from spurious wake-ups.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #51
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Thanks alot for that formula CornedBee, i've implemented it now, and i'm pretty sure it's working as it is supposed to.

    I've also added error checking for all the Win32 functions that i am calling, and it's returning the right error codes aswell. Oh and i've added a try catch block around the new operator aswell. All that is left now is to comment the code properly, as it is now it is very confusing, even for me, and i'm the one who wrote it.

    Code:
    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <exception>
    
    int main(int argc, char* argv[])
    {
    	if(argc != 3)
    	{
    		std::cerr << "Invalid number of arguments, "
    				  << "Correct usage is: split FILEPATH NUMBEROFOUTPUTFILES" << std::endl;
    		return 1;
    	}
    	
    	DWORD FileCount = strtol(argv[2], NULL, 10);
    	if(FileCount <= 0)
    	{
    		std::cerr << "Divison by 0!! BOOM the world just collapsed, try again..." << std::endl;
    		return 1;
    	}
    	
    	HANDLE hFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    	if(hFile == INVALID_HANDLE_VALUE)
    	{
    		std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    		return 1;
    	}
    	
    	char *pBuffer = NULL;
    	std::string OutputFileName;
    	std::stringstream ss (std::stringstream::in | std::stringstream::out); // Used for converting 'i' to a std::string
    	
    	DWORD InputSize = GetFileSize(hFile, NULL);
    	if(InputSize == INVALID_FILE_SIZE)
    	{
    		std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    		return 1;
    	}
    	
    	DWORD BaseOutSize = InputSize / FileCount;
    	DWORD Remainder = InputSize % FileCount;
    	
    	try
    	{
    		pBuffer = new char[BaseOutSize+1];
    	}
    	
    	catch (std::bad_alloc&)
    	{
    		std::cerr << "Error allocating memory." << std::endl;
    		return 1;
    	}
    	
    	std::cout << "File size is: " << InputSize << " bytes." << std::endl;
    	std::cout << "Splitting into " << FileCount << " files - " << BaseOutSize << " bytes each." << std::endl;
    	
    	DWORD dwBytesRead, lpNumberOfBytesWritten; //Necessary to avoid Segfaults
    	
    	
    	for(DWORD i = 0; i < FileCount; i++)
    	{
    		ss.str("");
    		ss << "PART" << i+1 << argv[1];
    		OutputFileName = ss.str();
    		
    		HANDLE OutputHandle;
    		DWORD CurrentFileSize = BaseOutSize + ((i < Remainder) ? 1 : 0);
    		
    		if(!ReadFile(hFile, pBuffer, CurrentFileSize, &dwBytesRead, NULL))
    		{
    			std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    			return 1;
    		}
    		
    		OutputHandle = CreateFile(OutputFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    		if(OutputHandle == INVALID_HANDLE_VALUE)
    		{
    			std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    			return 1;
    		}
    		
    		if(!WriteFile(OutputHandle, pBuffer, CurrentFileSize, &lpNumberOfBytesWritten, NULL))
    		{
    			std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    			return 1;
    		}
    		
    		if(!CloseHandle(OutputHandle))
    		{
    			std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    			return 1;
    		}
    	}
    	
    	if(!CloseHandle(hFile))
    	{
    		std::cerr << "Error " << GetLastError() << " occured." << std::endl;
    		return 1;
    	}
    	
    	delete[] pBuffer;
    	return 0;
    }
    I'm still using GetFileSize, because when i try to use GetFileSizeEx instead it just says that it is an undeclared function. I'm not sure why, because MSDN says it is defined in winbase.h, which is included in windows.h. I've also tried explicitly including winbase.h, but it's still the same?

    I think i'm pretty much done now then?
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  7. #52
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, you aren't deving for 95/98/ME/NT, are you? In that case, search the headers. It's probably guarded by some platform define, which I can't remember.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #53
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by Elysia View Post
    Well, you aren't deving for 95/98/ME/NT, are you? In that case, search the headers. It's probably guarded by some platform define, which I can't remember.
    That's the thing, i'm on Windows XP, so it should work aye?

    I've searched my winbase.h file in the compiler include folder, and i came up with this:

    Code:
    #if (_WIN32_WINNT >= 0x0500) 
    WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE,PLARGE_INTEGER);
    #endif
    What does the condition in the #if statement mean? Obviously my XP installation isn't meeting that requirement?

    Edit: The normal GetFileSize() function is just above the code i posted in the winbase file btw...
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  9. #54
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It means you must do
    #define _WIN32_WINNT 0x0500
    To target Windows XP or Windows 2000.

    You can also search MSDN for an article named "Using the Windows Headers."
    It contains information abut what defines you should define to state you are targeting a specific platform.

    To target Win2k and above, you must define
    _WIN32_WINNT = 0x0500
    WINVER = 0x0500

    This will allow you to access Windows 2000 API, such as GetFileSizeEx.
    Last edited by Elysia; 03-04-2008 at 02:33 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #55
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by Elysia View Post
    It means you must do
    #define _WIN32_WINNT 0x0500
    To target Windows XP or Windows 2000.
    But this also means that my program won't work under 98/NT right?

    So basically if i use GetFileSizeEx instead of what i'm using now, i'll lose compatability with alot of platforms? (Would my current code work on an older Windows installation anyways?)

    Why would i do that? What benefites does GetFileSizeEx have over GetFileSize?
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  11. #56
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The point of GetFileSizeEx is that it forces you to use a LARGE_INTEGER as the size, which copes with files bigger than 4GB. GetFileSize() as you use it gives you the high part of a size bigger than 32 bit in the "high part" of the supplied pointer. As you do not supply such, you will have to check for INVALID_FILE_SIZE as the return value, in which case the size was bigger than 4GB (most likely cause for this error - it could be something else wrong too).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #57
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by matsp View Post
    The point of GetFileSizeEx is that it forces you to use a LARGE_INTEGER as the size, which copes with files bigger than 4GB. GetFileSize() as you use it gives you the high part of a size bigger than 32 bit in the "high part" of the supplied pointer. As you do not supply such, you will have to check for INVALID_FILE_SIZE as the return value, in which case the size was bigger than 4GB (most likely cause for this error - it could be something else wrong too).

    --
    Mats
    Okay screw 98/NT then

    Thanks for the help everyone, especially CornedBee and Elysia.

    Edit: Hmm strange, i tried to define _WIN32_WINNT 0x0500 in my program as Elysia said, but it gives me a warning about redefinition. Seems like it has already been defines in windef.h, so why can't i use GetFileSizeEx in my program?
    Last edited by Neo1; 03-04-2008 at 02:45 PM.
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  13. #58
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yep, it means it won't work on 95/98/ME/NT anymore because GetFileSizeEx was introduced in Windows 2000.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #59
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Hmm strange, i tried to define _WIN32_WINNT 0x0500 in my program as Elysia said, but it gives me a warning about redefinition.
    You need to define it before including <windows.h>.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #60
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by CornedBee View Post
    You need to define it before including <windows.h>.
    Okay, so this fixed the redefinition warning and i can now use GetFileSizeEx, but for whatever reason my program segfaults when i run it? I haven't changed anything other than that since it last worked, so there must be something wrong with the way i'm using GetFileSizeEx?
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Newbie homework help
    By fossage in forum C Programming
    Replies: 3
    Last Post: 04-30-2009, 04:27 PM
  2. gcc link external library
    By spank in forum C Programming
    Replies: 6
    Last Post: 08-08-2007, 03:44 PM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. Batch file programming
    By year2038bug in forum Tech Board
    Replies: 10
    Last Post: 09-05-2005, 03:30 PM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM