From eb64ec7aee72bd9cf06589414efd5a1025b429fd Mon Sep 17 00:00:00 2001 From: Juuso Rytilahti <juuso.b.rytilahti@utu.fi> Date: Thu, 30 May 2024 13:00:15 +0000 Subject: [PATCH] uploaded the files for exercise 1 --- Exercise-1/Exercise1.java | 16 ++++ Exercise-1/TestZipper.java | 52 ++++++++++++ Exercise-1/Zipper.java | 170 +++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 Exercise-1/Exercise1.java create mode 100644 Exercise-1/TestZipper.java create mode 100644 Exercise-1/Zipper.java diff --git a/Exercise-1/Exercise1.java b/Exercise-1/Exercise1.java new file mode 100644 index 0000000..36deaa1 --- /dev/null +++ b/Exercise-1/Exercise1.java @@ -0,0 +1,16 @@ +package fi.utu.tech.ooj.exercise4.exercise1; + +import java.io.IOException; + +public class Exercise1 { + public Exercise1() { + System.out.println("Exercise 1"); + + try (var zipper = new TestZipper("books.zip")) { + zipper.run(); + } catch (IOException e) { + System.err.println("A failure occurred"); + e.printStackTrace(); + } + } +} diff --git a/Exercise-1/TestZipper.java b/Exercise-1/TestZipper.java new file mode 100644 index 0000000..e740600 --- /dev/null +++ b/Exercise-1/TestZipper.java @@ -0,0 +1,52 @@ +package fi.utu.tech.ooj.exercise4.exercise1; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; + +/** + * Test zipper. + * <p> + * Extracts zip, iterates through the files and prints information from each file. + * <p> + * From each file there will be printed: + * - name + * - amount of lines + * - amount of words + */ +class TestZipper extends Zipper { + TestZipper(String zipFile) throws IOException { + super(zipFile); + } + + @Override + protected Handler createHandler(Path file) { + return new Handler(file) { + @Override + public void handle() throws IOException { + var regex = Pattern.compile("\\W"); + var contents = Files.readString(file); + var lines = Files.readAllLines(file); + var firstLine = lines.isEmpty() ? "unknown" : lines.getFirst(); + var words = regex.splitAsStream(contents).filter(s -> !s.isBlank()).map(String::toLowerCase).toList(); + + System.out.printf(""" + + Originally was fetched from %s. + The founded file is %s. + The file contains %d lines. + The file contians %d words. + Possible title of the work: %s + + """, + tempDirectory, + file.getFileName(), + lines.size(), + words.size(), + firstLine + ); + } + }; + } +} diff --git a/Exercise-1/Zipper.java b/Exercise-1/Zipper.java new file mode 100644 index 0000000..2bd92d0 --- /dev/null +++ b/Exercise-1/Zipper.java @@ -0,0 +1,170 @@ +package fi.utu.tech.ooj.exercise4.exercise1; + +import fi.utu.tech.ooj.exercise4.Main; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; +import java.util.zip.ZipInputStream; + +// WORKAROUND: jos zip-tiedostoa ei löydy, kopioi resources-hakemistosta +// books.zip projektin juureen ja noudata alla olevia kahta ohjetta, +// jotka myös merkitty WORKAROUND-kommentilla + +/** + * Luokka, joka mallintaa unzippailuja (tiivistetyn zip-paketin purku). + * <p> + * Idea on, että luokan olion ollessa olemassa levyllä sijaitsee myös + * oliota varten olion luoma tilapäishakemisto. Kun olio suljetaan, + * myös hakemisto poistetaan. + * <p> + * Miten käytetään? Luo olio. Luonti olettaa, että zip-tiedoston on + * oltava olemassa. Luokan metodi 'run' aktivoi unzippauksen. Lopuksi + * sulje olio ('close'). + * <p> + * Vinkki: sulkeminen on helppoa Javan try-with-resources -toiminnolla. + */ +abstract public class Zipper implements AutoCloseable { + // zip-tiedosto purkamista varten + private final String zipFile; + + // java-luokka, jonka paketista etsitään zip-tiedostoa + private final Class<?> resolver = Main.class; + + // tilapäishakemiston polku + protected final Path tempDirectory; + + /** + * Merkitsee muistiin annetun zip-tiedoston ja + * luo tilapäishakemiston 'tempDirectory'. + * + * @param zipFile Zip-tiedostopolku (alkuehto: oltava olemassa ja ei-null) + * @throws IOException Zip-tiedostoa ei löydy tai tilapäishakemistoa ei voida luoda + */ + public Zipper(String zipFile) throws IOException { + // WORKAROUND: jos zip-tiedostoa ei löydy, kommentoi seuraavat 2 riviä + if (resolver.getResource(zipFile) == null) + throw new FileNotFoundException(zipFile); + + this.zipFile = zipFile; + + tempDirectory = Files.createTempDirectory("dtek0066"); + System.out.println("Luotu tilapäishakemisto " + tempDirectory); + } + + /** + * Poistaa tilapäishakemiston 'tempDirectory' olion sulkemisen yhteydessä. + * + * @throws IOException Kaikenlaisten I/O-virheiden sattuessa + */ + @Override + public void close() throws IOException { + try (final var stream = Files.walk(tempDirectory)) { + stream + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } + + System.out.println("Poistettu tilapäishakemisto " + tempDirectory); + } + + /** + * Purkaa 'zipFile'-tiedoston tilapäishakemistoon 'tempDirectory'. + * + * @throws IOException Kaikenlaisten I/O-virheiden sattuessa + */ + private void unzip() throws IOException { + final var destinationDir = tempDirectory.toFile(); + + // WORKAROUND: jos zip-tiedostoa ei löydy, vaihda seuraavaan + // try (final var inputStream = new FileInputStream(zipFile); + try (final var inputStream = resolver.getResourceAsStream(zipFile); + final var stream = new ZipInputStream(inputStream)) { + var zipEntry = stream.getNextEntry(); + while (zipEntry != null) { + final var newFile = new File(destinationDir, zipEntry.getName()); + final var destDirPath = destinationDir.getCanonicalPath(); + final var destFilePath = newFile.getCanonicalPath(); + if (!destFilePath.startsWith(destDirPath + File.separator)) { + throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); + } + System.out.println("Puretaan " + newFile); + if (zipEntry.isDirectory()) { + if (!newFile.isDirectory() && !newFile.mkdirs()) { + throw new IOException("Failed to create directory: " + newFile); + } + } else { + // fix for Windows-created archives + final var parent = newFile.getParentFile(); + if (!parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("Failed to create directory: " + parent); + } + + // write file content + try (final var fos = new FileOutputStream(newFile)) { + stream.transferTo(fos); + } + } + zipEntry = stream.getNextEntry(); + } + stream.closeEntry(); + } + } + + /** + * Ajaa unzippauksen ja kullekin luodulle tiedostolle käsittelijän. + * + * @throws IOException Kaikenlaisten I/O-virheiden sattuessa + */ + public void run() throws IOException { + unzip(); + + for (final var handler : createHandlers()) + handler.handle(); + } + + protected List<Handler> createHandlers() throws IOException { + try (final var stream = Files.list(tempDirectory)) { + return stream.map(this::createHandler).toList(); + } + } + + /** + * Käsittelijän luonti. + * + * @param file Käsiteltävä tiedosto (alkuehto: oltava olemassa ja ei-null) + * @return Käsittelijä + */ + protected abstract Handler createHandler(Path file); + + /** + * Yksittäisen tiedoston käsittelijä, jonka vastuulla on käsitellä + * yksittäinen tiedosto. + */ + protected abstract static class Handler { + public final Path file; + + /** + * Käsittelijän alustus. + * + * @param file Käsiteltävä tiedosto (alkuehto: oltava olemassa ja ei-null) + */ + public Handler(Path file) { + this.file = file; + } + + /** + * Käsittelee tiedoston. + * + * @throws IOException Kaikenlaisten I/O-virheiden sattuessa + */ + abstract public void handle() throws IOException; + } +} + -- GitLab