LD

Files and Exceptions in Java

Quick Recap & Agenda

  • Quick recap of last week + a new demo.
  • HW 6
  • Working with Files in Java
  • Handling Exceptions

Last Week's Topics

  • The Java Collections Framework
  • The List Interface
  • ArrayLists vs Linked Lists
  • Generic Collections
  • Stacks, Queues, Sets, Maps
  • Comparators, Comparables

Using Lists

  • The List interface is implemented by two distinct concrete classes:
    • ArrayList: backed by an array.
    • LinkedList: backed by a chain of “nodes”.
  • Choosing between ArrayList and LinkedList depends on algorithmic complexity.

List Implementation

  • Declaring and creating a list:

    ArrayList<Integer> lst = new ArrayList<>();
    
    • Concrete implementation required for RHS (Right Hand Side).
    • Concrete Type or Interface for Variable.
    • Complete the type: a list OF Integers.

Demo: List Tradeoffs

  • Demonstration of the tradeoffs between different list implementations.

Comparing Robots

  • To sort Robots, we have to define an ordering.

  • We could choose alphabetic by Name.

  • We could choose chronological by Model.

  • Or by cost, intelligence, distance, power, anything!

    public class Robot {
        private String name;
        private int model;
        // plus other stuff for robots.
    }
    //file: Robot.java
    

Comparator Interface

  • Comparator is a simple interface with one key method.

  • Each object instance encapsulates a comparison method.

  • These are used by sorting algorithms to sort data.

    public interface Comparator<T> {
        public int compare(T o1, T o2);
    }
    
    class MyRobotComparator implements Comparator<Robot> {
        public int compare(Robot o1, Robot o2) {
            return o1.name.compareTo(o2.name);
        }
    }
    
    class MyRobotComparator implements Comparator<Robot> {
        public int compare(Robot o1, Robot o2) {
            return o2.model - o1.model;
        }
    }
    

Generics (in Java)

  • For a class that uses instances of another class
  • A mechanism that allows you to specify the state and behavior of the class without needing to know (exactly) what the other class is.
  • They’re like templates or “variables” for types!

Generic Collections

  • Specify the type of the elements in the collection: <etype>
  • Allows the Java compiler to check that you’re using it properly.
  • Eliminates type casts and run-time exceptions (crashes)
  • Similar to polymorphism, but with more "guard rails".

Generic Collections - Code

public interface List<E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}
  • Related generic type
  • Method parameters
  • Method return values

Given Generic Interface

public interface List<Student> {
    void add(Student elt);
    void set(int index, Student elt);
    Student get(int index);
}

public class Roster {
    protected List<Student> students;

    public Student getStudent(int index) {
        return students.get(index);
    }
}

//Compiler translates interface to this:
public interface List<E> {
    void add(E elt);
    void set(int index, E elt);
    E get(index);
}

//Used like this:

Polymorphism vs Generics

  • Generics are related to polymorphism; however, they are distinct!

  • Polymorphism is when we refer to objects of different classes by the type of a common parent. (E.g., Rectangle and Circle are Shapes.)

  • But when we pull an item out of a collection, we would only know the parent class, not the "real" class.

  • Generics let the compiler keep track of this for us.

    // Polymorphic but Not Generic
    public interface List {
        void add(Object x);
        void set(int index, Object value);
        Object get(int index);
    }
    
    // Can lead to ambiguous looking code:
    List a = new LinkedList();
    a.add(2);
    a.add(3);
    a.add(5);
    ...
    
    List b = new LinkedList();
    b.add("Cat");
    b.add("Dog");
    ...
    
    Object x = a.get(0);
    Object y = b.get(0);
    
    // Compare to using generics:
    List<Integer> a = new LinkedList<>();
    a.add(2);
    a.add(3);
    a.add(5);
    ...
    
    List<String> b = new LinkedList<>();
    b.add("Cat");
    b.add("Dog");
    ...
    
    int x = a.get(0);
    String y = b.get(0);
    

Generic Types (Classes and Interfaces)

  • Take one or more type parameters
  • Used for:
    • Variable types (instance variables, local variables, method parameters)
    • Method return types
    • Other generic type declarations
  • Conventionally named with single capital letter

This Week's Focus

  • Working with Files!
    • Reading/writing text files.
    • Reading/writing binary files.
    • The IOStream perspective
  • Handling Exceptions:
    • try-catch-throw
    • try-with-resources

Basic OS Organization

  • OS is a collection of pieces:
    • Process management
    • Main memory management
    • File management
    • I/O system management
    • Networking
    • Protection system
  • Diagram showing CPU, Main Memory, Devices, and the interaction between Software (Process & Resource Manager, Memory Manager, Device Manager, File Manager) and Hardware.

Linux Kernel Map

  • Diagram illustrating the layers of the Linux kernel, including applications, system interfaces, kernel system, virtual file system, memory management, storage, networking, device drivers, and hardware.

Working with Files and Directories in Java

  • Introduction to file and directory manipulation in Java.

Files and Directories

  • A file is an organized, named sequence of data that is stored on a semi-permanent medium (like a hard drive, flash drive, or ssd).
  • It's a container for data that doesn't belong to any one instance of a running program.
  • Files represent data "at rest".
  • Examples: mp3, docx, png, gif, pdf, java, class, zip, txt, rtf, xls, html, jpg, …
  • Open source language models involve VERY large files. The newest exciting model, Mixtral 8x22B, has a total of 176 billion parameters, which as a single downloadable file takes 352 \, \text{GB}.

Directories

  • Files are organized into directories (aka folders), which are simply containers for files.
  • Directories are also files.
  • Exact details on how files and directories are represented internally depends on the "file system".
  • Typical file systems include: fat32, ntfs, apfs, ext4, xfs, …
  • Examples: /, /home, /usr, /Applications, C:\Programs, C:\Users, "My Documents", …

Directories (cont.)

  • Every operating system includes a "root directory" which contains all other directories — perhaps through a sequence of other directories, and so on.
  • On Windows, the root directory is usually named "C:", on MacOS and Linux, the root directory is simply "/".
  • To list the contents of a directory, use the "ls" tool.

Root Listing (Macbook)

  • Example output of the ls -l / command on a Macbook, showing the contents of the root directory.

Root Listing (Fedora)

  • Example output of the ls -l / command on a Fedora system, showing the contents of the root directory.

Paths

  • A path is a way to refer to a specific file, perhaps one which is in another directory from the current one.
  • An absolute path refers to a file using a path beginning with the root directory.
  • A relative path pertains to a file relevant to the current directory.
  • Every process (aka, running program) keeps track of its own "current working directory".

Paths (continued)

  • A separator character is used within a path to separate directory names from a filename, and to break the directories into a sequence.
  • Examples:
    • /Users/adam/Documents/teaching/courses/171/Fall2021/Workshops/W1.pdf
    • /Users/adam/eclipse-workspace/fileio/src/FileInputDemo.java
    • FileInputDemo.java
    • ./fileio/src/FileInputDemo.java

Special Paths and Directories

  • The "." symbol usually represents the current directory.
  • The ".." symbol usually represents "one directory up".
  • The "~" symbol represents a users home directory (on Mac and Linux systems — I'm not sure how to do it on Windows).

Sidebar: The Shell

  • The shell (aka terminal) is a program that reads commands and executes them, while maintaining some environment variables to keep the process organized.

  • Examples:

    • PATH is a list of all directories searched when you run a command (such as javac).
    • PWD is the current working directory used for relative paths (this is also maintained by other processes, such as IntelliJ or Eclipse)
  • Try this in Java:

    Map<String, String> env = System.getenv();
    

Sidebar: Commandline Arguments

  • The other, easier, way to get outside information into your programs is to use commandline arguments.
  • All tokens (strings, separated by whitespace) on the commandline after your main class name will be put into the argv array in main.

Commandline Arguments Example

  • Example of using commandline arguments in Java:

    // Output:
    adam@dbmbp FilesExceptions % java CommandLineArgs red yellow blue "csc 171 too"
    Here are the arguments:
    0 is red
    1 is yellow
    2 is blue
    3 is csc 171 too
    
    // Usage example:
    public class CommandLineArgs {
        public static void main(String[] args) {
            System.out.println("Here are the arguments:");
            for (int n = 0; n < args.length; n++)
                System.out.println(n + " is " + args[n]);
        }
    }
    // CommandLineArgs.java
    

Key Facts

  1. Files are permanent storage for data "at rest".
  2. Directories are special files that contain other files and directories. Each running program maintains a working directory. The top-level directory on a system is special and is called the root.
  3. Files are specified using paths, which can be absolute (to the root) or relative (to the current directory).
  4. The linux tools ls, cd, and pwd are used to list and change directories.
  5. The operating system manages file access and shares resources safely between multiple uses.
  6. File systems are used by the operating system to organize all the files on a machine.

Objective

  • Learn how to read and write sequential text-based files.
  • In depth info here (not necessary to digest all): https://docs.oracle.com/javase/tutorial/essential/io/index.html

File IO in Java

  • We need to know about a few classes:
    • File: access attributes but NOT the data
    • FileReader, FileWriter (both are Reader, Writer): access a file as a stream of characters.
    • FileInputStream, FileOutputStream (InputStream, OutputStream): access a file as a stream of bytes.
    • RandomAccessFile: access a file however you like!

Text File IO in Java

  • We need to know about a few classes:
    • File: access attributes but NOT the data
    • FileReader, FileWriter (both are Reader, Writer): access a file as a stream of characters.
    • BufferedReader, BufferedWriter: access a file efficiently.
    • PrintWriter: pretty print to a file.

java.io.File

  • java.io.File is the primary class for working with metadata, such as access times, permissions, and file names.
  • Methods include:
    • exists(), canRead(), canWrite()
    • delete(), renameTo()
    • isDirectory(), isFile()
    • list(), listFiles(), mkdir(), mkdirs()
    • lastModified(), setLastModified(), length()
  • More info: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/File.html
  • These can also be passed to Scanner constructors.

In depth example: FileInspector.java

  • Example of using the File class to inspect file metadata.

What about reading/writing?

  • Introduction to reading and writing file content.

java.io.FileReader/Writer

  • Classes for reading and writing character streams.
  • read(), reset(), skip(), close(), write()
  • Note - can read individual characters or arrays
  • More info: https://docs.oracle.com/en/java/javase/11/docs/api/ java.base/java/io/FileReader.html

Using FileReaders

  • The familiar Scanner class provides a constructor which reads from the FileReader base class, which means you can easily use all your favorite Scanner methods when reading from a file.

  • Example:

    FileReader fr = new FileReader("file.txt")
    Scanner scnr = new Scanner(fr);
    

Using FileWriters

  • In the case of writing to files, we want to recreate the effects of calling System.out.println() and System.out.printf().

  • The System.out object is an instance of a PrintStream, which prints a sequence of bytes. For printing text, we can connect a PrintWriter to a FileWriter.

  • Example:

    FileWriter fw = new FileWriter("file.txt");
    PrintWriter oWriter = new PrintWriter(fw);
    oWriter.print("Hello, world!");
    

Closing Files

  • It's good practice to close() your FileStreams when you're finished with them — but if you forget, the garbage collector will (eventually) take care of it.
  • Even better — use a try-with-resources statement.
  • More on this later.