PG1: What if your program correctly makes the input file and then just sort of freezes and the output never happens? Make sure that you close every file as soon as you're done using it. In particular, if you aren't using a file, close it immediately. Let's say I make a pipe for communicating with my child. I will write. My child will read. I: Make that pipe. Fork that child. Immediately close the reading end of the pipe because I am never going to use it. As soon as I'm done writing to the pipe, I close the writing end of the pip. Child: is summoned into existence Immediately closes the write end of the pipe. When the child is done reading, the child should close the read end of the pipe. If you are reading from a pipe, and the writer's end is closed, that triggers an end-of-file. If I am reading from a pipe, and the writer's end is not closed, then I will sit and wait forever (block) until some new stuff is entered into the pipe. Let's say I'm the child, and I will be reading from the pipe, but I don't close my writer's end. My parent will write to the pipe, finish writing to the pipe, and then close the writer's end. That's great. But since I never closed MY writer's end, my reader's end still thinks the pipe is open, and it waits for input that never is going to come, and I don't get that End of File. And, the code I'm using to test your PG1, my two programs, both rely on EOF being there when it needs to be there. **** If we take a look at files to which data can be read or written, there are several different "kinds" of files that an OS has to use correctly. Read-Only files: CD-ROM. Read-Write files: sequential access and random access. Sequential Access: tape drive. I have to start at the beginning and read forward until I find the thing I want. Pipes, sockets are also sequential access. Big disadvantage: slow Big advantage: You can store honkin' large files if you want to. Random access: you see on most disk drives. You can jump forward or backward to any point in the file you want. Whether you choose to use that feature or not, the file is still random access. Some languages have you use a different command or different parameter to open and use a random access file. Java, in particular, has a special file type RandomAccessFile for this purpose. The operating system does not distinguish between a sequential access file or a random access file on a hard drive. When a file (on Linux) is opened in append mode then it doesn't matter where you set the file pointer. All writes occur at the end of the file. Why might I want to use random access files? Databases All databases use a random-access file structure. It would take too long to search a huge file sequentially for that thing you want. Being able to random access files is, I think, a necessity for programming. By and large, if you are opening a file for sequential reading you use the flag O_RDONLY . If you are using a file for sequential writing and you're starting from scratch, you use the flag O_WRONLY | O_CREAT | O_TRUNC If you are using a file for sequential writing but you're adding to what's already there, you use O_WRONLY | O_CREAT | O_APPEND If you are using a file for random access reading, you use O_RDONLY. If you are using a file for random access reading and writing, you use O_RDWR | O_CREAT. Do NOT use O_TRUNC; that will delete all existing data. Do not use O_APPEND; that will add all new data to the end instead of where you want to put it. truncate shrinks a file to the size you want it to be. It discards the last part of the file. On Linux, truncate can also be used to lengthen a file by adding nulls (ASCII 0) to the end. This has a very limited usage. But it is very fast. It is faster than actually 9000 nulls.