ccwc (Coding Challenges Word Count) is a custom implementation of the classic Unix wc (word count) command-line utility, written entirely in Java. It is built to be memory-efficient, scalable for massive files, and fully compatible with standard Unix pipelines.
This project was built as part of the Build Your Own wc Tool Challenge.
Explore the docs · Report Bug · LinkedIn · Email
-
-c: Count bytes in a file or stream. -
-l: Count lines (newline characters). -
-w: Count words (sequences of characters delimited by whitespace). -
-m: Count characters (correctly handles multi-byte UTF-8 encoded text). -
Default Mode: Output lines, words, and bytes simultaneously when no flag is provided.
-
Standard Input (stdin): Supports Unix piping (e.g.,
cat file.txt | ccwc -l). -
Memory Safe: Uses a streaming single-pass architecture. It can process files larger than available RAM without crashing.
- Java Development Kit (JDK) 17 or higher.
- A terminal/command prompt environment.
Because this project uses standard Java libraries with no external dependencies, you can compile it directly using javac.
-
Clone the repository:
git clone https://github.com/MohammadRokib/wc-tool-java.git cd ccwc -
Compile the Java source files into an
outdirectory:# On Linux / macOS / Git Bash / Windows CMD javac -d out src/ccwc/*.java
The application is run via the java command, pointing to the out directory as the classpath.
java -cp out ccwc.Main [-c] [-l] [-w] [-m] [filename]If no filename is provided, the tool automatically reads from standard input (stdin).
1. Count bytes in a file:
$ java -cp out ccwc.Main -c test.txt
342190 test.txt2. Count lines in a file:
$ java -cp out ccwc.Main -l test.txt
7145 test.txt3. Count words in a file:
$ java -cp out ccwc.Main -w test.txt
58164 test.txt4. Count characters in a file (UTF-8 aware):
$ java -cp out ccwc.Main -m test.txt
339292 test.txt5. Default mode (lines, words, bytes):
$ java -cp out ccwc.Main test.txt
7145 58164 342190 test.txt6. Reading from Standard Input (Piping):
When reading from stdin, the filename is omitted from the output.
$ cat test.txt | java -cp out ccwc.Main -l
7145Instead of reading entire files into memory (which causes OutOfMemoryError on large files), ccwc uses a single-pass, streaming architecture.
The project is divided into four main components:
Main.java: The entry point. Delegates argument parsing toOptions, invokes theCounter, and formats the standard output usingSystem.out.printf.Options.java: A Data Transfer Object (DTO) that parses command-line arguments into boolean flags. If no flags are provided, it automatically enables the default metrics (lines, words, bytes).Counter.java: The core engine. It features two entry points:count(Path path, Options): For file inputs. UsesFiles.size()for an instant O(1) byte count, avoiding unnecessary disk reads.count(InputStream in, Options): For standard input. Uses a sharedcountFromStreammethod that loops through decoded characters exactly once, checking for line breaks, word boundaries, and character counts simultaneously.
CountingInputStream.java: ExtendsFilterInputStream(Decorator Pattern). When reading fromstdin, this class sits at the bottom of the stream stack, intercepting raw bytes to tally the total byte count as they flow up to the character decoder.
If you are testing the standard input byte count (-c) on Windows using PowerShell, you may notice a 3-byte discrepancy compared to reading the file directly (e.g., 342187 instead of 342190).
Why? PowerShell's cat alias (Get-Content) decodes files into .NET strings and silently strips the 3-byte UTF-8 Byte Order Mark (BOM) before piping the data to external executables like java.exe.
Your Java code is correct. To verify raw byte piping on Windows, use Command Prompt (cmd.exe) with the type command, or use Git Bash:
:: In cmd.exe
type test.txt | java -cp out ccwc.Main -cMohammad Rokib