# # A simple file I/O program in
APLawrence.com -  Resources for Unix and Linux Systems, Bloggers and the self-employed

A simple file I/O program in C

I've removed advertising from most of this site and will eventually clean up the few pages where it remains.

While not terribly expensive to maintain, this does cost me something. If I don't get enough donations to cover that expense, I will be shutting the site down in early 2020.

If you found something useful today, please consider a small donation.



Some material is very old and may be incorrect today

© October 2009 Girish Venkatachalam
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]);
        }

}


running cheetah
SpamCheetah
Stop spam dead in its tracks!

If you found something useful today, please consider a small donation.



Got something to add? Send me email.





(OLDER)    <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

->
-> A simple file I/O program in

4 comments


Inexpensive and informative Apple related e-books:

Take Control of Preview

Photos: A Take Control Crash Course

Take Control of Numbers

Are Your Bits Flipped?

Take Control of OS X Server





More Articles by © Girish Venkatachalam







Mon Oct 19 13:28:37 2009: 7298   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: 7301   BruceGarlock

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: 7302   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: 7305   TonyLawrence

gravatar
the yellow code highlighting is difficult to read

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

------------------------


Printer Friendly Version

Have you tried Searching this site?

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.

Contact us


Printer Friendly Version





Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? (Brian Kernighan)




Linux posts

Troubleshooting posts


This post tagged:

Girish

Programming



Unix/Linux Consultants

Skills Tests

Unix/Linux Book Reviews

My Unix/Linux Troubleshooting Book

This site runs on Linode