Skip to Content
Course content

219: Building a Basic File Compression Tool (RLE)

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Run-Length Encoding (RLE) is one of the simplest forms of data compression. It doesn't use complex math or dictionaries; it just looks for sequences of the same data value and replaces them with a single value and a count. If you have a file that looks like AAAAABBBCC, RLE turns it into 5A3B2C. It's not great for a standard English novel, but for simple images or files with lots of repeated padding, it's surprisingly effective.

Designing the Encoding Loop

I want to create a tool that reads a source file and writes a compressed version to a destination file. My general plan is to keep a counter, iterate through the file, and every time the next character differs from the current one, I'll write the count and the character to the output. I'm keeping this simple: I'll assume the input is basic ASCII text.

#include <stdio.h>
#include <stdlib.h>

void compress_file(FILE *src, FILE *dest) {
    int current = fgetc(src);
    if (current == EOF) return;

    int count = 1;
    int next;

    while ((next = fgetc(src)) != EOF) {
        if (next == current) {
            count++;
        } else {
            fprintf(dest, "%d%c", count, current);
            current = next;
            count = 1;
        }
    }
    // I'll handle the final sequence here...
}

The "Last Run" Trap

Here is where I usually trip up when I'm rushing. I wrote the loop above, tested it on a file that ended with AAA, and noticed the output was missing the last three characters entirely. Why? Because the fprintf only triggers when the character changes. When the loop hits EOF, it exits immediately, leaving that final count and character sitting in memory without ever writing them to the disk.

It's a classic "off-by-one" logic error. To fix this, I just need to call the print function one last time after the while loop finishes to flush out whatever was being tracked.

    // ... inside compress_file, after the while loop ...
    fprintf(dest, "%d%c", count, current); 
}

Wiring Up the File Handles

Now I need a main function to handle the actual file opening and closing. I'm using fopen with "rb" and "wb" because treating files as binary is generally a safer habit in C, even for text, as it prevents the runtime from messing with newline translations on Windows.

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s input.txt output.rle\n", argv[0]);
        return 1;
    }

    FILE *src = fopen(argv[1], "rb");
    if (!src) {
        perror("Error opening source file");
        return 1;
    }

    FILE *dest = fopen(argv[2], "wb");
    if (!dest) {
        perror("Error opening destination file");
        fclose(src);
        return 1;
    }

    compress_file(src, dest);

    fclose(src);
    fclose(dest);
    printf("Compression complete.\n");
    return 0;
}

One thing to keep in mind: this specific implementation has a flaw. If your input file contains numbers (like 11122), the output (3122) becomes ambiguous. In a production tool, I'd use a non-numeric delimiter or a fixed-width binary header for the count, but for learning the logic of RLE, this approach is the clearest way to see the algorithm in action.




📋 Practical Task

Build the RLE Decompression Tool

You've now seen how to compress a file using Run-Length Encoding. Now, you need to write the inverse. Create a program called decompress.c that reads an RLE-compressed file (e.g., 5A3B2C) and expands it back to its original form (AAAAABBBCC).

Requirements:

  • The program should take two command-line arguments: the compressed input file and the decompressed output file.
  • Use fscanf or fgetc to read the count (integer) and the character.
  • Use a loop to write the character to the output file the specified number of times.
  • Ensure you handle file errors (e.g., file not found) gracefully.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.