Thread: Windows Specific File I/O

  1. #31
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The code looks right. Why not give the debugger a whirl?
    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. #32
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Elaborating on the previous thing: "PART" is of type const char[5] - a string literal. In the expression "PART" + part with part being an integer, the literal decays to a const char*. So what you have is a pointer + integer expression, yielding a different pointer. That is, if part is 1, you get a pointer to the offset 1 from the beginning of the literal, resulting in "ART". If part is 2, you get "RT". If part is 4 you get "" and if it's 5 you point at random data in your program's read-only data area.
    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

  3. #33
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by CornedBee View Post
    Elaborating on the previous thing: "PART" is of type const char[5] - a string literal. In the expression "PART" + part with part being an integer, the literal decays to a const char*. So what you have is a pointer + integer expression, yielding a different pointer. That is, if part is 1, you get a pointer to the offset 1 from the beginning of the literal, resulting in "ART". If part is 2, you get "RT". If part is 4 you get "" and if it's 5 you point at random data in your program's read-only data area.
    Thanks for that explanation

    Elysia:

    I don't have a debugger, nor do i have any experience using one. But i guess now is as good a time as any. I've heard alot of good things about the debugger in Visual Studio, but since i'm using GCC i'm thinking that maybe GDb is a better choice, is it available for Windows?
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  4. #34
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    but since i'm using GCC i'm thinking that maybe GDb is a better choice, is it available for Windows?
    Yes, via MinGW (or Cygwin, I suppose).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #35
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Neo1 View Post
    I don't have a debugger, nor do i have any experience using one. But i guess now is as good a time as any. I've heard alot of good things about the debugger in Visual Studio, but since i'm using GCC i'm thinking that maybe GDb is a better choice, is it available for Windows?
    I don't know anything about GCC, but from what I know, it's already built-in in the Windows package.
    I like Visual Studio better, however and would prefer it anyday over GCC, so maybe you're asking the wrong one about GCC & debugger & co.
    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.

  6. #36
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    OK, let's take a look at the current program now.

    First, even though MacGyver explicitly warned you about this, you managed to not read the documentation and realize that CreateFile returns INVALID_HANDLE_VALUE on failure, not NULL, thus rendering your !hFile check ineffective.

    Second, this will come back to bite you: since integer division truncates, you'll drop the last few bytes of the input file if its size doesn't evenly divide by the number of files you want to split it into.

    Third, and that's probably the crasher, check the operator precedence in this statement:
    Code:
    pBuffer = new char[NumberOfOutputFiles - 1 * OutputFileSize];
    Fourth, you leak the output file handles.

    Fifth, you have the same precedence problem in one of your WriteFile calls.

    Sixth, the WriteFile call that contains the problem makes not one bit of sense.

    Seventh, are you sure you want to append if the output file already exists? Because that's what OPEN_ALWAYS does.

    Eighth, for some reason you completely neglect error handling in the loop.



    Elysia, if that code looked right to you, you really have to look more carefully.
    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

  7. #37
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    Elysia, if that code looked right to you, you really have to look more carefully.
    Well, I can't be expected to figure out everything...
    That's what the debugger is for!
    Usually I'd figure out I get a buffer overrun somewhere and seeing as there's only one, I go back to the one and break out the size into its own variable or look at the assembly to see how much is allocated and realize that it isn't allocating enough, so I take a look at the code again and realize a little subtle mistake about the operators precedence... so no time lost.

    And more to the point, I avoid Win32 because of all the complexities. Better to wrap it in your own RAII classes.
    No worries about closing stuff. And I don't really know OpenFile/ReadFile at all. I tend to use C-style functions or MFC classes instead. Far easier.
    Last edited by Elysia; 03-03-2008 at 03:50 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.

  8. #38
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Usually I'd figure out I get a buffer overrun somewhere and seeing as there's only one, I go back to the one and break out the size into its own variable or look at the assembly to see how much is allocated and realize that it isn't allocating enough, so I take a look at the code again and realize a little subtle mistake about the operators precedence... so no time lost.
    What if it doesn't crash? What if it simply sneaks a wrong result into some spot no one looks at for a long time?

    Being able to analyze code visually is extremely important. Noticing a single missing letter can make the difference between a long, tiring bug hunt and no problem at all. Implicitly understanding operator precedence is similar.

    *shrug* It comes with experience. But only if you train it.
    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

  9. #39
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    What if it doesn't crash? What if it simply sneaks a wrong result into some spot no one looks at for a long time?
    Yes, that's a pain. Therefore you use MFC and "safe" APIs such as fread_s. I'd put the same size as I allocated in the size argument and it would read the correct amount of bytes or it would read too few or it would assert.
    Both of which are easy to spot.

    Being able to analyze code visually is extremely important. Noticing a single missing letter can make the difference between a long, tiring bug hunt and no problem at all. Implicitly understanding operator precedence is similar.
    Absolutely. Some things you can spot, some things you cannot. I should've spotted the operator precedence, though. Of course multiplication goes before subtraction. That was bad of me, but the rest? I don't think you can demand of me to know that since I usually stay away from Win32 or wrap it my own classes and re-use them.

    *shrug* It comes with experience. But only if you train it.
    But there are also some things you'll never learn to find
    Everyone is different in what they'll catch.
    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. #40
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by CornedBee View Post
    OK, let's take a look at the current program now.

    First, even though MacGyver explicitly warned you about this, you managed to not read the documentation and realize that CreateFile returns INVALID_HANDLE_VALUE on failure, not NULL, thus rendering your !hFile check ineffective.

    Second, this will come back to bite you: since integer division truncates, you'll drop the last few bytes of the input file if its size doesn't evenly divide by the number of files you want to split it into.

    Third, and that's probably the crasher, check the operator precedence in this statement:
    Code:
    pBuffer = new char[NumberOfOutputFiles - 1 * OutputFileSize];
    Fourth, you leak the output file handles.

    Fifth, you have the same precedence problem in one of your WriteFile calls.

    Sixth, the WriteFile call that contains the problem makes not one bit of sense.

    Seventh, are you sure you want to append if the output file already exists? Because that's what OPEN_ALWAYS does.

    Eighth, for some reason you completely neglect error handling in the loop.



    Elysia, if that code looked right to you, you really have to look more carefully.
    1. Ill look into adding proper error checking when it works as it is supposed to.

    2. I thought i had already fixed this problem, Elysia pointed it out in an earlier post.

    3. Don't know what i was thinking when i wrote that.

    Code:
    pBuffer = new char[(NumberOfOutputFiles - 1) * OutputFileSize];
    Right?

    4. I'm not quite sure what you mean, where do i leak handles?

    5. Fixed that now

    6. Which one do you mean? The one that is called if "i == NumberOfOutputFiles"? Why doesn't it make sense?

    7. Nope, i'll fix that aswell!

    8. I'll get to that, as i said in my OP i'm not quite comfortable with Win32 yet, especially GetLastErrorCode().

    Thanks for helping out!
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  11. #41
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Neo1 View Post
    4. I'm not quite sure what you mean, where do i leak handles?
    Once you open a file, you must close it as well.
    When you're finished reading/writing, close the handles with CloseHandle().

    8. I'll get to that, as i said in my OP i'm not quite comfortable with Win32 yet, especially GetLastErrorCode().

    Thanks for helping out!
    If a function fails, often they call SetLastError() with the error code. To get it, you can call GetLastError(). The documentation should say if you need to call GetLastError() or not, but you only need to call it if a function failed for some reason.
    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.

  12. #42
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Once you open a file, you must close it as well.
    When you're finished reading/writing, close the handles with CloseHandle().
    Basically the same as with the STl fstreams then

    The code looks like this now:

    Code:
    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <sstream>
    
    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;
    	}
    	
    	const unsigned int NumberOfOutputFiles = strtol(argv[2], NULL, 10);
    	
    	if(!NumberOfOutputFiles)
    	{
    		std::cerr << "Divison by 0!! BOOM the world just collapsed, try again..." << std::endl;
    		return 1;
    	}
    	
    	unsigned long OutputFileSize = 0;
    	unsigned int i = 1;
    	char *pBuffer = NULL;
    	std::string OutputFileName;
    	HANDLE hFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    	
    	if(!hFile)
    	{
    		std::cerr << "No such file." << std::endl;
    		return 1;
    	}
    	
    	unsigned long TotalFileSize = GetFileSize(hFile, NULL);
    	OutputFileSize = TotalFileSize / NumberOfOutputFiles;
    	pBuffer = new char[(NumberOfOutputFiles - 1) * OutputFileSize];
    	
    	std::cout << "File size is: " << TotalFileSize << " bytes." << std::endl;
    	std::cout << "Splitting into " << NumberOfOutputFiles << " files - " << OutputFileSize << " bytes each." << std::endl;
    	
    	DWORD dwBytesRead, lpNumberOfBytesWritten; //Necessary to avoid Segfaults
    	HANDLE OutputHandle;
    	
    	std::stringstream ss (std::stringstream::in | std::stringstream::out); // Used for converting 'i' to a std::string
    	
    	
    	for(; i <= NumberOfOutputFiles; i++)
    	{
    		ss << "PART" << i << argv[1];
    		OutputFileName = ss.str();
    		
    		ReadFile(hFile, pBuffer, OutputFileSize, &dwBytesRead, NULL);
    		OutputHandle = CreateFile(OutputFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    		
    		if(i == NumberOfOutputFiles)
    			WriteFile(OutputHandle, pBuffer, ((NumberOfOutputFiles - 1) * OutputFileSize), &lpNumberOfBytesWritten, NULL);
    		
    		else
    			WriteFile(OutputHandle, pBuffer, OutputFileSize, &lpNumberOfBytesWritten, NULL);
    	}
    	
    	CloseHandle(OutputHandle);
    	CloseHandle(hFile);
    	delete[] pBuffer;
    	return 0;
    }
    There is still some of the problems that Cornedbee mentioned that i have yet to fix.

    I don't get any errors when running the code above, it just doesn't output any files at all.

    Edit: Must've done something wrong before, don't know what, but it's working now and i didn't really change anything. I'm getting all the files outputted Only thing was that i had to clear the stringstream at the start of the loop, to get rid of the file names for the parts of the file that had already been written.
    Last edited by Neo1; 03-03-2008 at 04:36 PM.
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  13. #43
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Neo1 View Post
    1. Ill look into adding proper error checking when it works as it is supposed to.
    So you'd add error checking after having determined that there are no errors?

    2. I thought i had already fixed this problem, Elysia pointed it out in an earlier post.
    As far as I can see, you haven't. Although I suspect the i == NumberOfFiles stuff is supposed to fix it, it eludes me as to how it would accomplish that.

    Right?
    Right, except that entire concept is flawed.

    4. I'm not quite sure what you mean, where do i leak handles?
    You still do. Every succeeding CreateFile must be matched by a CloseHandle. Count how often you call CreateFile and how often you call CloseHandle. (Note: Don't count the occurrences in the code. Count how often they're actually executed.)

    6. Which one do you mean? The one that is called if "i == NumberOfOutputFiles"? Why doesn't it make sense?
    That one, yeah. As for why it doesn't make sense, well, it simply doesn't. Why don't you tell me why it does make sense? In other words, what do you hope to accomplish with it, and why do you think it accomplishes that?
    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

  14. #44
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The point was, I think, this:
    The file is, say, 2 MB.
    It should be split into 3 parts.
    2 MB = 2097152 bytes
    2097152 / 3 = 699050.66666666666666666666666667, hence 699050 (truncated).
    NumberOfOutputFiles = 3.
    First file, i = 1, so first file becomes 699050 bytes.
    Second file, i = 2, so second file becomes 699050 bytes.
    Third file, i = 3, so i == NumberOfOutputFiles, and therefore it writes
    (NumberOfOutputFiles - 1) * OutputFileSize = 2 * OutputFileSize = 1398100
    Which is obviously wrong I see now.

    But the point is, that it could fix it, though I don't know if it's the best way. Maybe.
    The forumla should be something like
    TotalFileSize - (OutputFileSize * (NumberOfOutputFiles - 1)) = 2097152 - (699050 * 2) = 699052 (File 1, 699050 + File 2, 699050 + File 3, 699052 = 699050 + 699050 + 699052 = 2097152 == TotalFileSize)
    And I also note that you do not read enough bytes to write. You always read OutputFileSize bytes.
    And you still use GetFileSize, but you should be using GetFileSizeEx.

    That's as far as I can see now.
    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.

  15. #45
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by CornedBee View Post
    So you'd add error checking after having determined that there are no errors?
    I know it might sound silly, but there is no need for me to check that the file path is valid, as long as i'm still developing the program, i'll just make sure to check that the path is valid when i'm testing, instead of having to add complexity to a program that isn't even working yet.

    You still do. Every succeeding CreateFile must be matched by a CloseHandle. Count how often you call CreateFile and how often you call CloseHandle. (Note: Don't count the occurrences in the code. Count how often they're actually executed.)
    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?

    But in essence, what you are saying is that i should call CloseHandle inside the loop? Like this..

    Code:
    for(; i <= NumberOfOutputFiles; i++)
    	{
    		ss.str("");
    		ss << "PART" << i << argv[1];
    		OutputFileName = ss.str();
    		
    		ReadFile(hFile, pBuffer, OutputFileSize, &dwBytesRead, NULL);
    		OutputHandle = CreateFile(OutputFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    		
    		if(i == NumberOfOutputFiles)
    			WriteFile(OutputHandle, pBuffer, ((NumberOfOutputFiles - 1) * OutputFileSize), &lpNumberOfBytesWritten, NULL);
    		
    		else
    			WriteFile(OutputHandle, pBuffer, OutputFileSize, &lpNumberOfBytesWritten, NULL);
    
    CloseHandle(OutputHandle);
    	}

    As far as I can see, you haven't. Although I suspect the i == NumberOfFiles stuff is supposed to fix it, it eludes me as to how it would accomplish that.


    Right, except that entire concept is flawed.


    That one, yeah. As for why it doesn't make sense, well, it simply doesn't. Why don't you tell me why it does make sense? In other words, what do you hope to accomplish with it, and why do you think it accomplishes that?
    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?
    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