diff --git a/source/ch_x_filehandling.ptx b/source/ch_x_filehandling.ptx new file mode 100644 index 0000000..933b24e --- /dev/null +++ b/source/ch_x_filehandling.ptx @@ -0,0 +1,672 @@ + + + + + File Handling + + +

+ File handling is an integral part of programming. Most programming languages have the ability to read from, write to, create, delete, move, and copy files. +

+
+ + +
+ Class Imports + +

+ Java has several libraries included for file handling, though, they must be imported. Java includes a class called File in the io library. The class can be imported with the following line. Be sure to capitalize File. +

+ + + + import java.io.File; + + + +

+ The Scanner class from the util library will need to be imported if there is any need for a program to read a file. It should be noted that this library is unnecessary if the program will not be reading any data from a file. +

+ + + + import java.util.Scanner; + + + +

+ The FileWriter class can be used to write to files. In the same way that the Scanner class isn't needed unless the program will read from a file, the FileWriter class isn't needed unless the program will write to a file. +

+ + + + import java.io.FileWriter; + + + +

+ Finally, these last two classes provide error handling and must be used in tandem with the File class when reading from or writing to files. IOException handles file creation and writing errors, while FileNotFoundException handles errors when trying to read files. +

+ + + + import java.io.IOException; + + + + + + import java.io.FileNotFoundException + + + +
+ +
+ Creating Files + +

+ Before we can write code that creates a file, we must first import the necessary classes mentioned in the previous section (Scanner and FileWriter are not needed for a class that only creates files) and create a class. We will call this class CreateFile. +

+ + + + import java.io.File; + import java.io.IOException; + + public class CreateFile { + public static void main(String[] args) { + + } + } + + + +

+ Next, within the main function, we will create a File object. It is important to create a meaningful name for the File object. We will call ours myFile. +

+ + + + File myFile = new File("myfile.txt"); + + + + +

+ myFile is the name of the object within the program, while myfile.txt is the name of the file itself and will be the file name if the operation that creates the file is successful. +

+
+ +

+ Now that we have created a new File object, we can create a file using the createNewFile() method from the File class. While the previous line of code creates an object within the program for the file, this method actually does the work of creating a file and saving it in the current working directory. This method returns a boolean value. If the method returns true, the file was successfully created. If the method returns false, there is already a file using the chosen file name. We can use this method's possible return values in tandem with an if/else selection to determine if the file was created, or if a file with that file name already exists in the directory. +

+ +

+ First, lets look at the equivalent Python code: +

+ + + + import os + + filename = "myfile.txt" + + if not os.path.exists(filename): + with open(filename, 'x') as f: + pass + print(f"The file {filename} was created successfully.") + else: + print(f"The file {filename} already exists.") + + + +

+ Now, let's look at Java code that accomplishes the same task: +

+ + + + import java.io.File; + import java.io.IOException; + + public class CreateFile { + public static void main(String[] args) { + if (myFile.createNewFile()) { // If the file was created successfully + System.out.println("The file " + myFile.getName() + " was created sucessfully."); + } else { // If a file with the file name chosen already exists + System.out.println("The file " + myFile.getName() + " already exists."); + } + } + } + + + + +

+ You may have noticed the use of another method from the File class; getName(). This method returns a string containing the name of the file. +

+
+ +

+ The code may seem complete at this point, but if you remember from the previous section, error handling using the IOException is required for program to compile. Let's utilize best practices and add in try/catch blocks to handle exceptions thrown by the IOException class. +

+ + + + try { + if (myFile.createNewFile()) { // If the file was created successfully + System.out.println("The file " + myFile.getName() + " was created sucessfully."); + } else { // If a file with the file name chosen already exists + System.out.println("The file " + myFile.getName() + " already exists."); + } + } catch (IOException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + + + + +

+ The IOException e part in the parenthesis next to the catch. This creates a variable called e that refers to an IOException object. In other words, e refers to the error created if the try block fails. The line e.printStackTrace(); prints the stack trace to the console. This is what the console may output if the program tries to create a file, but is blocked by the operating system due to insufficient permissions: +

+
+ + + + An error occurred. + java.io.IOException: Permission denied + at java.base/java.io.File.createNewFile(File.java:1040) + at CreateFile.main(CreateFile.java:7) + + + + +

+ At this point, the program will function correctly. Let's add the try/catch blocks to the foundational code written before to get a complete program. +

+ +

+ First, the equivalent Python code: +

+ + + + import os + + filename = "myfile.txt" + + try: + if not os.path.exists(filename): + with open(filename, 'x') as f: + pass # Create the file without writing anything + print(f"The file {filename} was created successfully.") + else: + print(f"The file {filename} already exists.") + except OSError as e: + print("An error occurred.") + import traceback + traceback.print_exc() + + + +

+ Now, the completed Java code: +

+ + + + import java.io.File; + import java.io.IOException; + + public class CreateFile { + public static void main(String[] args) { + try { + File myFile = new File("myfile.txt"); + if (myFile.createNewFile()) { // If the file was created successfully + System.out.println("The file " + myFile.getName() + " was created sucessfully."); + } else { // If a file with the file name chosen already exists + System.out.println("The file " + myFile.getName() + " already exists."); + } + } catch (IOException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + + } + } + + + +

+ You may be wondering: "What if I don't want to create a file in the current working directory?" Good question! In Windows environments, you can specify the file path using two back slashes for each back slash in the file path. For each pair of back slashes, the first back slash acts as an escape character. So, if you want to save a file to this directory: +

+ +
+            C:\Users\UserName\Documents
+        
+ +

+ The line of code that creates a File object will look like this: +

+ + + + File myFile = new File("C:\\Users\\UserName\\Documents\\myfile.txt"); + + + +

+ If you are working in a Linux or Apple environment, you can simply use the file path with single forward slashes: +

+ + + + File myFile = new File("/home/UserName/Documents/myfile.txt"); + + +
+ +
+ Writing to Files + +

+ The createNewFile() method is useful for attempting to create files and reporting if the operation was successful, however, createNewFile() does not write anything to files it creates. In fact, if you use createNewFile() to create a .txt file and then open the file, the file will be blank. +

+ +

+ To write to a file, we will need to create a different class. We will do the same setup as the previous section. First, we will import the classes (File and Scanner are not needed) and create the framework for a class that will write to a file. Let's call this class WriteFile: +

+ + + + import java.io.FileWriter; + import java.io.IOException; + + public class WriteFile { + public static void main(String[] args) { + + } + } + + + +

+ Next, we will create a FileWriter object. Let's call it myWriter: +

+ + + + FileWriter myWriter = new FileWriter("myfile.txt"); + + + +

+ In this next step, we will use the write() method from the FileWriter class. This Method will take any data within the parenthesis and write that data to the file selected. The write() method takes most standard data types: +

+ + + + myWriter.write("File successfully updated!"); + myWriter.close(); + + + + +

+ You may have noticed the close() function being used after writing to the file. This is a very important step and must be included when working with files! Without using this method, the file may remain active in system resources even after the program is closed. This can lead file corruption or other terrible problems that are best avoided! +

+
+ +

+ Next, we will again add the required try/catch blocks utilizing the IOException class. Just like with creating files, the program will not compile without these crucial additions! We will also add some print statements to inform us of the success of the file write operation. First, a Python example: +

+ + + + try: + with open("myfile.txt", "w") as my_writer: + my_writer.write("File successfully updated!") + print("File successfully written to.") + except OSError as e: + print("An error occurred.") + import traceback + traceback.print_exc() + + + +

+ And the equivalent Java code: +

+ + + + try { + FileWriter myWriter = new FileWriter("myfile.txt"); + myWriter.write("File successfully updated!"); + myWriter.close(); + System.out.println("File successfully written to."); + } catch (IOException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + + + +

+ And that's it! We will add our code to the foundational code for a complete program. First, an example of equivalent Python code: +

+ + + + try: + with open("myfile.txt", "w") as my_writer: + my_writer.write("File successfully updated!") + print("File successfully written to.") + except OSError as e: + print("An error occurred.") + import traceback + traceback.print_exc() + + + +

+ The completed Java code: +

+ + + + import java.io.FileWriter; + import java.io.IOException; + + public class WriteFile { + public static void main(String[] args) { + try { + FileWriter myWriter = new FileWriter("myfile.txt"); + myWriter.write("File successfully updated!"); + myWriter.close(); + System.out.println("File successfully written to."); + } catch (IOException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + } + } + + + +

+ Files in a specific directory can be written to using the same technique as the last section in which file paths are specified, with two back slashes used in Windows environments. +

+ + +

+ If a file does not already exist (for example, myfile.txt does not exist), the write() method will create the file. Despite this, it is still a good idea to create separate methods or classes for creating and writing to files. Not only is it good practice to ensure methods only accomplish one thing, but the createNewFile() method avoids overwriting files that already exist. Imagine a file with the name myfile.txt already exists and contains important information. Attempting to create a file using the write() method will delete that data forever. +

+
+ +

+ Speaking of overwriting data, what if we want to append text to the end of any text already in myfile.txt? To accomplish this, we can pass a boolean argument along with the file name when creating a new data argument: +

+ + + + FileWriter myWriter = new FileWriter("myfile.txt", true); // true enables append mode + + + +

+ Now, when we use write() method like before, the text will be appended if there is already text in the document. If we were to update our code to include the boolean argument: +

+ + + + import java.io.FileWriter; + import java.io.IOException; + + public class WriteFile { + public static void main(String[] args) { + try { + FileWriter myWriter = new FileWriter("myfile.txt", true); // true enables append mode + myWriter.write("File successfully updated!"); + myWriter.close(); + System.out.println("File successfully written to."); + } catch (IOException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + } + } + + + +

+ and then run the program twice, the contents of myfile.txt would be: +

+ + + + File successfully updated!File successfully updated! + + + +

+ This doesn't look very good! There is no space between the first and second sentences! We can make this look a little better by simply adding a space after the exclamation mark in the string: +

+ + + + myWriter.write("File successfully updated! "); // Added space at end + myWriter.close(); + + + +

+ This works fine if you want all text to be on the same line, but what if we want each additional write to appear on a new line? The first solution may be to use the \n newline character: +

+ + + + myWriter.write("File successfully updated!\n"); // Added newline character + myWriter.close(); + + + +

+ This would work fine most of the time, but older Windows programs and operating systems use the \r\n newline character. To ensure the text appears on a new line regardless of what system the code is running on, concatenate the string with the System.lineSeparator() method: +

+ + + + myWriter.write("File successfully updated!" + System.lineseparator()); // Added newline character + myWriter.close(); + + + +

+ Running either variation used for adding new lines twice will result in the following contents in myfile.txt: +

+ + + + File successfully updated! + File successfully updated! + + +
+ +
+ Reading Files + +

+ Let's take a look at how we can use Java to read file contents. We'll start again with library imports and building a class, this time importing the Scanner and FileNotFoundException classes. We will call this class ReadFile: +

+ + + + import java.io.File; + import java.io.FileNotFoundException; + import java.util.Scanner + + public class ReadFile { + public static void main(String[] args) { + + } + } + + + +

+ We will then create a new File object exactly the same as the one from the section on creating files. Additionally, we will create a Scanner object. The Scanner object is the object that does the file reading. We will call this scanner fileReader: +

+ + + + File myFile = new File("myfile.txt"); + Scanner fileReader = new Scanner(myFile); + + + + +

+ The myFile File object we created on the first line was passed to the Scanner object created on the second line. +

+
+ +

+ The next lines consist of a while loop that reads each line of the file passed to the Scanner object and reads them. First, a Python code example. A for loop is used instead in the Python example: +

+ + + + with open("filename.txt", "r") as file_reader: + for line in file_reader: + print(line.strip()) + + + +

+ The equivalent Java code: +

+ + + + while (fileReader.hasNextLine()) { + String data = fileReader.nextLine(); + System.out.println(data); + } + fileReader.close(); + + + +

+ The hasNextLine() method checks checks if the line below the current line has any data. This will evaluate to true even if the next line only contains blank spaces. Within the while loop, a string variable called data is used to store the current line that the Scanner object is pointing to. The nextLine() method does two things. Firstly, it returns the current line when called. Secondly, it moves the Scanner's position to the next line. In other words, for each iteration of the while loop, each line in the text is read, stored temporarily in the data variable, and printed to the console. Finally, the close() method accomplishes and holds the same importance as in the section on writing to files. +

+ +

+ Alternatively, the following code can be used to store the all lines of myfile.txt to one variable: +

+ + + + String data = ""; + while (fileReader.hasNextLine()) { + data = data + fileReader.nextLine() + System.lineSeparator(); + } + System.out.println(data); + fileReader.close(); + + + + +

+ Pay close attention to the details of this code. data must be declared using an empty string or it may not work correctly within the while loop. Additionally, care must be given to reassigning data in the while loop. data is concatinated (to ensure all lines are included) with fileReader.nextLine() and a new line operator. Each step of this process ensures what is stored in data matches exactly what is in myfile.txt. +

+
+ +

+ Using the second method of storing all file contents to one file, the resulting full code including try/catch blocks (this time using FileNotFoundException instead of IOException) will look something like this. First, the Python code: +

+ + + + try: + with open("myfile.txt", "r") as file_reader: + data = "" + for line in file_reader: + data += line # line already includes the newline character + print(data) + except FileNotFoundError as e: + print("An error occurred.") + import traceback + traceback.print_exc() + + + + +

+ And the Java equivalent: +

+ + + + import java.io.File; + import java.io.FileNotFoundException; + import java.util.Scanner + + public class ReadFile { + public static void main(String[] args) { + try { + File myFile = new File("myfile.txt"); + Scanner fileReader = new Scanner(myFile); + String data = ""; + while (fileReader.hasNextLine()) { + data = data + fileReader.nextLine() + System.lineSeparator(); + } + System.out.println(data); + fileReader.close(); + } catch (FileNotFoundException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + } + } + + + +

+ In this code, we simply print the contents of the file to the console, but it is easy to imagine how the data variable could be used in conjunction with the write class created in the previous section to create a copy of myfile.txt. +

+
+ +
+ Deleting Files + +

+ Finally, we will take a look at using Java to delete files. This one is pretty straight-forward and follows the structure used to create files. This time, however, try/catch blocks are not needed for the program to compile. We will call this class DeleteFile. The completed code should look something like this. +

+ + + + import java.io.File; + + public class DeleteFile { + public static void main(String[] args) { + File myFile = new File("myfile.txt"); + if (myFile.delete()) { + System.out.println("Deleted " + myFile.getName()); + } else { + System.out.println("File could not be deleted."); + } + } + } + + + +

+ This is almost identical to the code within the try block of the CreateFile class we made earlier. The main difference is the use of the delete() method. This method will delete any file with the name provided when creating the myFile object. Similar to the createNewFile() method, it will return true if the file existed and could be deleted, and false if the file could not be deleted. +

+
+ +
\ No newline at end of file diff --git a/source/main.ptx b/source/main.ptx index 7d8abe0..6c62fed 100644 --- a/source/main.ptx +++ b/source/main.ptx @@ -14,6 +14,7 @@ +