summaryrefslogtreecommitdiff
path: root/p3/HuffmanCompressor.java
diff options
context:
space:
mode:
authorpants <niklasjo2004@gmail.com>2026-09-21 14:16:34 -0700
committerpants <niklasjo2004@gmail.com>2026-09-21 14:16:34 -0700
commit81ba9eb66f8284d8760012973f84cdbe617ceb94 (patch)
tree466432644e9e3fd66ee183ec53a1f10abb1b7faa /p3/HuffmanCompressor.java
Diffstat (limited to 'p3/HuffmanCompressor.java')
-rw-r--r--p3/HuffmanCompressor.java209
1 files changed, 209 insertions, 0 deletions
diff --git a/p3/HuffmanCompressor.java b/p3/HuffmanCompressor.java
new file mode 100644
index 0000000..55228f1
--- /dev/null
+++ b/p3/HuffmanCompressor.java
@@ -0,0 +1,209 @@
+import java.io.*;
+import java.util.*;
+
+public class HuffmanCompressor {
+ private String filename;
+
+ public static final int CHAR_MAX = 255; // max char value
+ public static final int MAKE_CODE = 1;
+ public static final int COMPRESS = 2;
+ public static final int DECOMPRESS = 3;
+ public static final int ROUND_TRIP = 4;
+
+ public HuffmanCompressor(String filename) {
+ if (!filename.endsWith(".txt")) {
+ throw new IllegalArgumentException(
+ "This compressor only works on text files!");
+ }
+ this.filename = filename.split(".txt")[0];
+ }
+
+ public void makeCode() throws IOException {
+ System.out.println("I am about to make the Huffman code for "
+ + filename + ".txt...");
+ FileInputStream input = new FileInputStream(filename + ".txt");
+ int[] count = new int[CHAR_MAX];
+ int n = input.read();
+ while (n != -1) {
+ int prev = n;
+ count[n]++;
+ n = input.read();
+
+ // Remove added newline by ed
+ if (n == -1 && prev == 10) {
+ count[prev]--;
+ }
+ }
+
+ // Build the code; open the output file; save the code
+ System.out.println("\tI built up a frequency table of the " +
+ "characters in your file.");
+ System.out.println("\tNow, I'm going to call your HuffmanCode(int[]) " +
+ "constructor using that frequency table.");
+ HuffmanCode t = new HuffmanCode(count);
+
+ System.out.println("\tOkay! Now, I am going to save the code (using " +
+ "your save method) to the file " + filename +
+ ".code!");
+ PrintStream output = new PrintStream(new File(filename + ".code"));
+ t.save(output);
+ System.out.println("...I am done making the Huffman Code!");
+ }
+
+ public void compress(boolean debug) throws IOException {
+ System.out.println("I am about to attempt to COMPRESS "
+ + filename + ".txt:");
+ /* We must make the code before we can compress... */
+ this.makeCode();
+ System.out.println("\tNow that I have the Huffman Code, I am going " +
+ "to use the huffman code file created by");
+ System.out.println("\tyour save() method to compress the contents " +
+ "into " + filename + ".short!");
+
+ String[] codes = new String[CHAR_MAX];
+ Scanner codeInput = new Scanner(new File(filename + ".code"));
+ while (codeInput.hasNextLine()) {
+ int n = Integer.parseInt(codeInput.nextLine());
+ codes[n] = codeInput.nextLine();
+ }
+
+ // Open file to be compressed; open output file
+ FileInputStream input = new FileInputStream(this.filename + ".txt");
+ BitOutputStream output = new BitOutputStream(
+ new PrintStream(this.filename + ".short"), debug);
+
+ // Print out the debug binary to a .debug file
+ FileOutputStream debugOut = null;
+ if (debug) {
+ debugOut = new FileOutputStream(this.filename + ".debug");
+ }
+
+ // Do the compression
+ int n = input.read();
+ while (n != -1) {
+ if (codes[n] == null) {
+ // check if this is actually an error, or an ed added newline
+ if (!(n == 10 && input.read() == -1)) {
+ System.out.println("Your code file has no code for " + n +
+ " (the character '" + (char) n + "')");
+ System.out.println("exiting...");
+ System.exit(1);
+ }
+ n = -1;
+ } else {
+ for (int i = 0; i < codes[n].length(); i++) {
+ output.write(codes[n].charAt(i) - '0');
+ // Write to the .debug file
+ if (debugOut != null) {
+ debugOut.write(codes[n].charAt(i));
+ }
+ }
+ n = input.read();
+ }
+ }
+ input.close();
+ output.close();
+ System.out.println("...I am done compressing the file");
+ }
+
+ public void decompress(boolean printToConsole) throws IOException {
+ System.out.println("I am about to attempt to DECOMPRESS " +
+ filename + ".short:");
+
+ System.out.println("\tTo do this, I must first read in the huffman " +
+ "code used to compress the file.");
+ System.out.println("\tI will use your HuffmanCode(Scanner) " +
+ "constructor!");
+ // Open code file and construct tree
+ Scanner codeInput = new Scanner(new File(this.filename + ".code"));
+ HuffmanCode t = new HuffmanCode(codeInput);
+
+ // Open compressed file; open output
+ BitInputStream input = new BitInputStream(this.filename + ".short");
+ PrintStream output = System.out;
+ if (!printToConsole) {
+ System.out.println("\tNow, I will decompress the file using your " +
+ "translate() method and save");
+ System.out.println("\tthe output into " + this.filename + ".new");
+ output = new PrintStream(new File(this.filename + ".new"));
+ }
+ else {
+ System.out.println("\tNow, I will decompress the file using your " +
+ "translate() method and display it on the console");
+ }
+
+ // Decompress the file
+ t.translate(input, output);
+ output.close();
+ System.out.println("...I am done decompressing the file");
+ }
+
+ public static void main(String[] args) throws IOException {
+ Scanner console = new Scanner(System.in);
+
+ System.out.println("Welcome to the CSE 123 Huffman Compressor!");
+ System.out.println();
+
+ String filename;
+
+ do {
+ System.out.print("Which file would you like to work with (it " +
+ "must be a txt file)? ");
+ filename = console.nextLine().trim();
+ } while (!filename.endsWith(".txt"));
+
+ System.out.println();
+
+ int choice = -1;
+
+ while (choice == -1) {
+ System.out.println("Would you like to:");
+ System.out.println("\t(1) make a huffman code,");
+ System.out.println("\t(2) compress a file,");
+ System.out.println("\t(3) decompress a file, or");
+ System.out.println(
+ "\t(4) do a compression followed by a decompression");
+ System.out.print("1-4? ");
+ String choiceStr = console.nextLine().trim();
+ try {
+ choice = Integer.parseInt(choiceStr);
+ if (choice < 1 || choice > 4) {
+ choice = -1;
+ }
+ } catch(NumberFormatException e) {
+ /* Don't change choice; so, the loop will repeat. */
+ }
+ }
+
+ boolean debug = false;
+ if (choice == COMPRESS || choice == ROUND_TRIP) {
+ debug = prompt(
+ console,
+ "Would you like to debug the compressed file (y/n)? ");
+ }
+
+ boolean toConsole = false;
+ if (choice == DECOMPRESS || choice == ROUND_TRIP) {
+ toConsole = !prompt(
+ console,
+ "Would you like to print the result to a file (y/n)? ");
+ }
+
+ HuffmanCompressor huffman = new HuffmanCompressor(filename);
+ switch (choice) {
+ case 1: huffman.makeCode(); break;
+ case 2: huffman.compress(debug); break;
+ case 3: huffman.decompress(toConsole); break;
+ case 4:
+ huffman.compress(debug);
+ huffman.decompress(toConsole);
+ break;
+ }
+ }
+
+ public static boolean prompt(Scanner console, String message) {
+ System.out.print(message);
+ return console.nextLine().trim().toLowerCase().startsWith("y");
+
+ }
+}