(OLDER) <- More Stuff -> (NEWER) (NEWEST)
Printer Friendly Version



A simple file I/O program in C

2009/10/19 by Girish Venkatachalam



Girish Venkatachalam is a UNIX hacker with more than a decade of networking and crypto programming experience. His hobbies include yoga,cycling, cooking and he runs his own business. Details here:

http://gayatri-hitech.com
http://spam-cheetah.com

Doing even the simplest programming tasks in C can be daunting due to its fondness for segfaulting. A C program can be found crashing on printf, command line parsing or nearly every attempt to print a string that is NULL. Or even access it.

Of course C can crash and behave nastily in many other ways too. That is why you need hand holding when you are learning C programming.

And one continues to learn C programming for many many years. I have dealt with this topic in my other articles in this very site. So please refer to those articles for the facets of C that trips newbies.

In any case I had to write this code sample as part of my work. I am presently reverse engineering the MAPI protocol that MS Outlook speaks to MS Exchange. My work does not so much involve reverse engineering since Microsoft has published the entire MAPI protocol in full detail.

So my work mostly involves implementing the specification. And there is a project called OpenChange that has done the bulk of the work by riding on top of Samba project. In spite of all this context and help, I still find the project pretty daunting and challenging.

As part of this work I had to read and write mail attachments. So I thought I will write a simple C program and validate it before integrating with the rest of the complex stuff.

In so doing I felt that this sample might help a beginner C programmer and even some experience hands since file I/O is such a common activity and C is filled with various slips and dangers.

I could have read the file size by reading the file header using the stat(2) system call. But I chose this approach of read(2) returning zero. Of course you could improve this program in many ways. But this program is good in many ways though purists may object to some of my practices.

Using syslog() is a great way to debug and inform the user what is going on. I want to switch over from using printf() to this as this can double up as printf once you open the log with the LOG_PERROR flag.

Once the development phase of the program is over you can remove this flag and all logs go to the logfile alone. It is quite cool.

Of course you can do pretty much everything this does using perl or any other scripting language also. Please look at Sys::Syslog in perl.





In case you are wondering, this program can read and write binary files as well as text files. Shows the power and simplicity of C programming and in an oblique way also the genius/simplicity of UNIX itself.

I will now leave the program to do the rest of the talking.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <err.h>
#include <errno.h>


/* Read and write binary/text from/to the file system */

int
readfile(char *f)
{
        int fd, c, bytes;
        char buf[1024];

        /* Open file for reading */
        fd = open(f, O_RDONLY);
        if(fd < 0) {
               perror("File open for reading");
               exit(128);
        }

        do {
               bytes = read(fd, buf, sizeof(buf));
               /* Once we are done reading then break
               * out of the infinite loop.
               */
               if(bytes == 0)
                       break;
               if(bytes < 0) {
                       perror("read(2)");
                       exit(128);
               }
        
               syslog(LOG_INFO, "Read %d bytes from [%s]", bytes, f);
               /* Spit the file out on STDOUT */
               write(STDOUT_FILENO, buf, bytes);

        } while(1); /* Infinite loop */

        syslog(LOG_INFO, "Finished reading");
        return 0;
}

int
writefile(char *f)
{
        int infd, outfd, c, inbytes, outbytes;
        char buf[1024], outf[1024];

        printf("Please give output file to write to:");
        scanf("%s", outf);


        /* Open file for reading */
        infd = open(f, O_RDONLY);
        if(infd < 0) {
               perror("File open for reading");
               exit(128);
        }


        /* Open file for writing */
        outfd = open(outf, O_CREAT | O_APPEND | O_WRONLY, S_IRWXU );
        if(outfd < 0) {
               perror("File open for writing");
               exit(128);
        }

        syslog(LOG_INFO, "File contents of %s", f);

        do {
               inbytes = read(infd, buf, sizeof(buf));
               /* Once we are done reading then break
               * out of the infinite loop.
               */
               if(inbytes == 0)
                       break;
               if(inbytes < 0) {
                       perror("read(2)");
                       exit(128);
               }
               outbytes = write(outfd, buf, inbytes);
               if(outbytes < 0) {
                       perror("read(2)");
                       exit(128);
               }
               syslog(LOG_INFO, "%d bytes read and %d written",
                   inbytes, outbytes);

        } while(1); /* Infinite loop */

        syslog(LOG_INFO, "Finished writing");
        return 0;
}

int
main(int argc, char **argv)
{
        int fd;
        char *filename;
        
        openlog("fio", LOG_PERROR | LOG_CONS | LOG_PID, LOG_USER);

        if(argc < 3) {
               printf(" %s usage: %s <filename> r | w\n",
                   argv[0], argv[0]);
               exit(128);
        }

        if(argv[2][0] == 'r') {
               readfile(argv[1]);
        } else {
               writefile(argv[1]);
        }

}





More Articles by Girish Venkatachalam




Click here to add your comments





Mon Oct 19 13:28:37 2009: Subject:   TonyLawrence

gravatar
due to its fondness for segfaulting.

Well, C itself has no such fondness. Our sloppy programming certainly does, but that's not C's fault :-)



Mon Oct 19 21:07:51 2009: Subject:   BruceGarlock
http://garlockfamily.com
gravatar
Just a little 'nitpick' -- on my screen (24" iMac) the yellow code highlighting is difficult to read (the if statements)





Mon Oct 19 21:43:32 2009: Subject: Segfaults   AndrewSmallshaw

gravatar
Segfaults can actually be quite a useful thing - one of the more useful debugging tools for C is ElectricFence whose sole purpose is to cause segfaults and cause them quickly. That helps resolve all kinds of pointer errors in low-level data structures. In general I would prefer my program to crash and burn than come up with obviously incorrect results - it is generally a whole lot easier to debug.

Along the same lines I tend to make fairly extensive use of assert() in my code - assert(0s serve a documentary function regarding prerequisites and expected conditions, but they also help enormously when debugging. In a debugger I almost never use watchpoints and only rarely breakpoints - a debugging session typically involves running the program as normal inside the debugger and waiting for something to blow up. If the tests are smartly placed and liberal enough (without being distracting) you can usually find the problem early enough to see what the problem is straight away.



Mon Oct 19 22:32:19 2009: Subject:   TonyLawrence

gravatar
the yellow code highlighting is difficult to read

Just one more reason I don't like color highlighting.

Don't miss responses! Subscribe to Comments by RSS or by Email

Click here to add your comments


If you want a picture to show with your comment, go get a Gravatar


Auto FTP Manager


ad

/Girish/c-fileio.html copyright October 2009 Girish Venkatachalam All Rights Reserved

Have you tried Searching this site?

Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more. We appreciate comments and article submissions.

Publishing your articles here

Jump to Comments



Many of the products and books I review are things I purchased for my own use. Some were given to me specifically for the purpose of reviewing them. I resell or can earn commissions from the sale of some of these items. Links within these pages may be affiliate links that pay me for referring you to them. That's mostly insignificant amounts of money; whenever it is not I have made my relationship plain. I also may own stock in companies mentioned here. If you have any question, please do feel free to contact me.

Specific links that take you to pages that allow you to purchase the item I reviewed are very likely to pay me a commission. Many of the books I review were given to me by the publishers specifically for the purpose of writing a review. These gifts and referral fees do not affect my opinions; I often give bad reviews anyway.

We use Google third-party advertising companies to serve ads when you visit our website. These companies may use information (not including your name, address, email address, or telephone number) about your visits to this and other websites in order to provide advertisements about goods and services of interest to you. If you would like more information about this practice and to know your choices about not having this information used by these companies, click here.


book graphic unix and linux troubleshooting guide

My Troubleshooting E-Book will show you how to solve tough problems on Linux and Unix systems!



 I sell and support
 Kerio Mail server






More:
       - Programming
       - Girish


Unix/Linux Consultants

Skills Tests

Guest Post Here