{"id":12025,"date":"2025-10-30T02:00:00","date_gmt":"2025-10-30T06:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=12025"},"modified":"2025-09-26T14:06:13","modified_gmt":"2025-09-26T18:06:13","slug":"read-and-write-data-in-c","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=12025","title":{"rendered":"Read and write data in C"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"12025\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>The first C function that most people learn is the <code>puts<\/code> function to print a simple string. That&#8217;s a great function to print information to the user, but if you want to do more than that, you&#8217;ll need to explore other functions.<\/p>\n\n\n\n<p>Let&#8217;s learn about how to <em>read and write data in C<\/em> by writing a simple implementation of a common Linux command. The <strong>cp<\/strong> command will copy one file to another, like this simple example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cp file.txt copy.txt<\/code><\/pre>\n\n\n\n<p>You can write your own version of the <strong>cp<\/strong> command by using only a few basic C functions to read and write data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-simplest-case-reading-one-character-at-a-time\">The simplest case: reading one character at a time<\/h2>\n\n\n\n<p>A trivial way to <em>read input and print output<\/em> is by using the <code>fgetc<\/code> and <code>fputc<\/code> functions, to read and write data <em>one character at a time<\/em>. The usage is defined in <code>stdio.h<\/code> like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int fgetc(FILE *stream);\nint fputc(int c, FILE *stream);<\/code><\/pre>\n\n\n\n<p>Copying one file to another then becomes a matter of opening the source and destination files, then reading one character at a time from the first file, then writing that character to the second file. The fgetc function returns either the single character read from the input file or the end of file (<code>EOF<\/code>) marker when the file is done. Once you&#8217;ve read <code>EOF<\/code>, you&#8217;ve finished copying and you can close both files.<\/p>\n\n\n\n<p>At the core of this program is a <code>do<\/code> loop that reads data one character at a time, then prints it one at a time to the output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    do {\n        ch = fgetc(infile);\n        if (ch != EOF) {\n            fputc(ch, outfile);\n        }\n    } while (ch != EOF);<\/code><\/pre>\n\n\n\n<p>The full implementation needs to open the source file and output file in <em>binary<\/em> mode, so the &#8220;new line&#8221; characters don&#8217;t get translated, such as when working on other systems that might have a different &#8220;new line&#8221; character:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main(int argc, char **argv)\n{\n    FILE *infile;\n    FILE *outfile;\n    int ch;\n\n    \/* parse the command line *\/\n\n    \/* usage: cp infile outfile *\/\n\n    if (argc != 3) {\n        fprintf(stderr, \"Incorrect usage\\n\");\n        fprintf(stderr, \"Usage: cp infile outfile\\n\");\n        return 1;\n    }\n\n    \/* open the input file *\/\n\n    infile = fopen(argv&#91;1], \"rb\");\n    if (infile == NULL) {\n        fprintf(stderr, \"Cannot open file for reading: %s\\n\", argv&#91;1]);\n        return 2;\n    }\n\n    \/* open the output file *\/\n\n    outfile = fopen(argv&#91;2], \"wb\");\n    if (outfile == NULL) {\n        fprintf(stderr, \"Cannot open file for writing: %s\\n\", argv&#91;2]);\n        fclose(infile);\n        return 3;\n    }\n\n    \/* copy one file to the other *\/\n\n    \/* use fgetc and fputc *\/\n\n    do {\n        ch = fgetc(infile);\n        if (ch != EOF) {\n            fputc(ch, outfile);\n        }\n    } while (ch != EOF);\n\n    \/* done *\/\n\n    fclose(infile);\n    fclose(outfile);\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Let&#8217;s save this program as <code>1cp.c<\/code> and compile it using the GNU C compiler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -Wall -o 1cp 1cp.c<\/code><\/pre>\n\n\n\n<p>Programming your own <strong>cp<\/strong> command by reading and writing data one character at a time does the job, but it&#8217;s not very fast. You might not notice when copying &#8220;everyday&#8221; files like documents and text files, but you&#8217;ll really notice the difference when copying large files. That&#8217;s because working on one character at a time requires significant overhead.<\/p>\n\n\n\n<p>Here&#8217;s an example of copying the program&#8217;s source code and comparing it with <strong>diff<\/strong>. We don&#8217;t see any output from <strong>diff<\/strong>, which means the two files are the same, as we would expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ .\/1cp 1cp.c \/tmp\/1cp.c\n\n$ diff 1cp.c \/tmp\/1cp.c<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-better-way-reading-and-writing-in-blocks\">The better way: reading and writing in blocks<\/h2>\n\n\n\n<p>A better way to write this <strong>cp<\/strong> command is by reading a chunk of the input into memory (called a buffer), then writing that collection of data to the second file. This is much faster because the program can read more of the data at one time, which requires fewer &#8220;reads&#8221; from the file.<\/p>\n\n\n\n<p>You can read a file into a variable by using the <code>fread<\/code> function. This function takes several arguments: the array or memory buffer to read data into, the size of the smallest thing you want to read, how many of those things you want to read, and the file to read from:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);<\/code><\/pre>\n\n\n\n<p>The different options provide quite a bit of flexibility for more advanced file input and output, such as reading and writing files with a certain data structure. But in the simple case of <em>reading data from one file and writing data to another file<\/em>, you can use a buffer that is just an array of characters.<\/p>\n\n\n\n<p>You can write the buffer to another file using the <code>fwrite<\/code> function. This uses a similar set of options to the <code>fread<\/code> function: the array or memory buffer to read data from, the size of the smallest thing you need to write, how many of those things you need to write, and the file to write to.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);<\/code><\/pre>\n\n\n\n<p>In the case where the program reads a file into a buffer, then writes that buffer to another file, the array can be of a fixed size. For example, you can use a <code>char<\/code> array that is 200 characters long:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    char buffer&#91;200];<\/code><\/pre>\n\n\n\n<p>With that assumption, we need to change the loop in the <strong>cp<\/strong> program to read data from a file into a buffer then write that buffer to another file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    while (!feof(infile)) {\n        buffer_length = fread(buffer, sizeof(char), 200, infile);\n        fwrite(buffer, sizeof(char), buffer_length, outfile);\n    }<\/code><\/pre>\n\n\n\n<p>Here&#8217;s the full source code to the updated <strong>cp<\/strong> program, which now uses a buffer to read and write data:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main(int argc, char **argv)\n{\n    FILE *infile;\n    FILE *outfile;\n    char buffer&#91;200];\n    size_t buffer_length;\n\n    \/* parse the command line *\/\n\n    \/* usage: cp infile outfile *\/\n\n    if (argc != 3) {\n        fprintf(stderr, \"Incorrect usage\\n\");\n        fprintf(stderr, \"Usage: cp infile outfile\\n\");\n        return 1;\n    }\n\n    \/* open the input file *\/\n\n    infile = fopen(argv&#91;1], \"r\");\n    if (infile == NULL) {\n        fprintf(stderr, \"Cannot open file for reading: %s\\n\", argv&#91;1]);\n        return 2;\n    }\n\n    \/* open the output file *\/\n\n    outfile = fopen(argv&#91;2], \"w\");\n    if (outfile == NULL) {\n        fprintf(stderr, \"Cannot open file for writing: %s\\n\", argv&#91;2]);\n        fclose(infile);\n        return 3;\n    }\n\n    \/* copy one file to the other *\/\n\n    \/* use fread and fwrite *\/\n\n    while (!feof(infile)) {\n        buffer_length = fread(buffer, sizeof(char), 200, infile);\n        fwrite(buffer, sizeof(char), buffer_length, outfile);\n    }\n\n    \/* done *\/\n\n    fclose(infile);\n    fclose(outfile);\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Let&#8217;s save this source code as <code>cpbuf.c<\/code> and compile it using the GNU C compiler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -Wall -o cpbuf cpbuf.c<\/code><\/pre>\n\n\n\n<p>As before, we can use this new program to copy its source code and compare it with the <strong>diff<\/strong> program to verify that the original and the copy are the same:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ .\/cpbuf cpbuf.c \/tmp\/cpbuf.c\n\n$ diff cpbuf.c \/tmp\/cpbuf.c<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"yes-it-really-is-faster\">Yes, it really is faster<\/h2>\n\n\n\n<p>Reading and writing data using buffers is the better way to write this version of the cp program. Because it reads chunks of a file into memory at once, the program doesn&#8217;t need to read data as often. You might not notice a difference in using either method on smaller files, but you&#8217;ll really see the difference if you need to copy something that&#8217;s much larger or when copying data on slower media like over a network connection.<\/p>\n\n\n\n<p>I ran a comparison using the Linux <strong>time<\/strong> command, which runs another program, and tells you how long that program took to complete. For my test, I wanted to see the difference in time, so I copied a big ISO file I had on my system.<\/p>\n\n\n\n<p>I first copied the image file using the standard Linux <strong>cp<\/strong> command to see how long that takes. By running the Linux <strong>cp<\/strong> command first, I also eliminated the possibility that Linux&#8217;s built-in file-cache system wouldn&#8217;t give my program a false performance boost. The test with Linux <strong>cp<\/strong> took much less than one second to run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ls -sh install.iso \n2.7G install.iso\n\n$ time cp install.iso copy.iso\nreal    0m0.008s\nuser    0m0.002s\nsys 0m0.006s<\/code><\/pre>\n\n\n\n<p>Copying the same file using my own version of the <strong>cp<\/strong> command took significantly longer. But reading data from an input into a buffer and then writing that buffer to an output file is much faster:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ time .\/1cp install.iso copy1.iso\nreal    0m21.974s\nuser    0m18.120s\nsys 0m3.651s\n\n$ time .\/cpbuf install.iso copy2.iso\nreal    0m4.079s\nuser    0m1.104s\nsys 0m2.895s<\/code><\/pre>\n\n\n\n<p>And in all cases, the copies are exactly the same as the original. Using a checksum program like <strong>md5sum<\/strong> or <strong>sha256sum<\/strong> verifies that each file is the same:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ md5sum *.iso\n96b917d39c83ae579994752d2051091a  copy1.iso\n96b917d39c83ae579994752d2051091a  copy2.iso\n96b917d39c83ae579994752d2051091a  copy.iso\n96b917d39c83ae579994752d2051091a  install.iso<\/code><\/pre>\n\n\n\n<p>My demonstration <strong>cp<\/strong> program used a buffer that was 200 characters. I&#8217;m sure the program would run much faster if I read more of the file into memory at once. But for this comparison, you can already see the huge difference in performance, even with a small 200-character buffer.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><em>This article is adapted from <a href=\"https:\/\/opensource.com\/article\/21\/3\/file-io-c\">Learn how file input and output works in C<\/a> by Jim Hall, and is republished with the author&#8217;s permission.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re new to C programming, here are a few tips to improve reading and writing files.<\/p>\n","protected":false},"author":33,"featured_media":6830,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[5,150],"tags":[91,152],"class_list":["post-12025","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-programming","tag-linux","tag-programming"],"modified_by":"Jim Hall","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/12025","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12025"}],"version-history":[{"count":2,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/12025\/revisions"}],"predecessor-version":[{"id":12029,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/12025\/revisions\/12029"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/6830"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}