--- title: Computer Programming II Lab 9 V0.3 description: In this lab, we are going to talk about Binary I/O and how we can manipulate binary files, we should know that every file in your computer is a binary file, but the files that contain binary which represents a text will be considered as text files as they are very common. --- <h1 style='border: none'><center>Computer Programming II Lab 9</center></h1> <h2 style='border: none'><center>Binary I/O</center></h2> <h5><center>The Islamic University of Gaza<br>Engineering Faculty<br>Department of Computer Engineering</center></h5> <h6>Authors: Usama R. Al Zayan<span style="float:right">2023/04/28</span></h6> <h6>Parts of this Lab were adapted from work done by Mohammed Nafiz ALMadhoun and Mohammed AlBanna</h6> --- --- <p style='text-align:justify'> In this lab, we are going to talk about Binary I/O and how we can manipulate binary files, we should know that every file in your computer is a binary file, but the files that contain binary which represents a text will be considered as text files as they are very common. </p> ## Viewing Files as Binary You can view any file as a binary file using a `Hex Editor`, which is a program that will display the binary data of a file, you could also see your whole hard drive or ram as a big binary chunk. You could use this [online hex editor](https://hexed.it/), or you could install a program such as [HxD](https://mh-nexus.de/en/hxd/). <center> ![The binary data of an Image](https://i.imgur.com/LSCmetA.png =500x) The binary data of an Image. </center> **Note:** We read binary data as hex because it's easier for us, and programs usually store data as bytes (two hex digits). ## Binary I/O Classes The main classes for reading and writing as binary is `InputStream`, and `OutputStream`, these two abstract classes define the common methods for writing or reading binary data (which could be something other than files). Please read the documentation here: [`java.io.InputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) ,[`java.io.OutputStream`]( https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html). As an example, we will take a look at the `FileOutputStraem` class which will output the binary data to a file. #### Example 1 ```java= import java.io.*; public class Test{ public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("testfile.bin"); fos.write(0x10); fos.write(0x20); fos.write(0x30); fos.close(); } } ``` And here's the file in a hex editor: <center> ![Example 1 Output](https://i.imgur.com/EUxSI67.png =500x) Example 1 Output </center> Now we could use `FileInputStream` to read the data from that file. ## Data Streams So it's useful to write data byte by byte, but sometimes we need something bigger than a byte, something like `int`, or `float`, we could do that by hand but there is an easier way, to use `DataInputStraem` and `DataOutputStream` classes. Please take a look at the documentation here: [`java.io.DataInputStraem`](https://docs.oracle.com/javase/8/docs/api/java/io/DataOutputStream.html), [`java.io.DataOutputStream`]( https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html). ### Example 2 ```java= import java.io.*; public class Test{ public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("testfile.bin"); DataOutputStream dos = new DataOutputStream(fos); for (int i=1000000;i<1010000;i++){ dos.writeInt(i); } dos.close(); fos.close(); } } ``` Notice that we've created a `FileOutpuStream`, then we've constructed the `DataOutputStream` using that object because we could write data to something other than a file (e.g. a network packet!). So this file will contain the numbers from `1000000` to `1010000`, and the output size will be `40,000` bytes because each `int` will take four bytes. Now if we created a text file with the same data, it will take about `90,000` bytes. **Writing binary data to a binary file is faster in writing and reading, and take much lower space.** ### Example 3 In this example, we will save and read the data of students using `DataOuptutStream` and `DataInputStream`. #### Student Class ```java= public class Student { private String name; private float gpa; public Student(String name, float gpa) { this.name = name; this.gpa = gpa; } public Student(DataInputStream dataStream) throws IOException{ name = dataStream.readUTF(); gpa = dataStream.readFloat(); } public void saveToStream (DataOutputStream dataStream) throws IOException{ dataStream.writeUTF(name); dataStream.writeFloat(gpa); } public void printDetails(){ System.out.printf("Name: %s%n", name); System.out.printf("GPA : %.2f%n", gpa); } } ``` #### Saving Data ```java= Student[] students = { new Student("Student 1", 60), new Student("Student 2", 70.1f), new Student("Student 3", 95.2f), new Student("Student 4", 50.5f), }; try(FileOutputStream fos = new FileOutputStream("students.bin")){ try(DataOutputStream dos = new DataOutputStream(fos)){ dos.writeInt(students.length); // Write the length of the array! for (Student s : students){ s.saveToStream(dos); } } } ``` #### Reading Data ```java= Student[] students = null; try(FileInputStream fis = new FileInputStream("students.bin")){ try(DataInputStream dis = new DataInputStream(fis)){ students = new Student[dis.readInt()]; for (int i=0;i<students.length;i++){ Student s = new Student(dis); s.printDetails(); students[i] = s; } } } ``` ## Object Streams In this section, we will try to use `ObjectOutpuStream`, and `ObjectInputStraem`, which are classes that help us automatically serialize an object, so the previous example will be trivial and it will help you a lot if you want to save the data of a certain object. A serializable class should implement the interface `Serializable`, which will tell the output stream that this class could be serialized. ### Example 4 In this example, we will create the previous example using Object Streams. #### Student Class ```java= public class Student implements Serializable { private String name; private float gpa; public Student(String name, float gpa) { this.name = name; this.gpa = gpa; } public void printDetails(){ System.out.printf("Name: %s%n", name); System.out.printf("GPA : %.2f%n", gpa); } } ``` #### Saving Data ```java= Student[] students = { new Student("Student 1", 60), new Student("Student 2", 70.1f), new Student("Student 3", 95.2f), new Student("Student 4", 50.5f), }; try(FileOutputStream fos = new FileOutputStream("students.bin")){ try(ObjectOutputStream oos = new ObjectOutputStream(fos)){ oos.writeObject(students); } } ``` #### Reading Data ```java= Student[] students = null; try(FileInputStream fis = new FileInputStream("students.bin")){ try(ObjectInputStream ois = new ObjectInputStream(fis)){ students = (Student[]) ois.readObject(); for (int i=0;i<students.length;i++){ students[i].printDetails(); } } } ``` ## Random Access File Notice that in the previous examples, we access the data sequentially, but sometimes we need to access the data in a random way (which means we will read whatever address we want). Notice that Random Access File is not an output or input stream, it's not a stream. Notice that the constructor of a `RandomAccessFile` contains the file path and a mode, the mode specifies if you want to read, read-write, or write to that file. Please take a look at the documentation: [`java.ioRandomAccessFile`](https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html). ### Example 5 ```java= public class Test{ public static void main(String[] args) throws Exception { try (RandomAccessFile raf = new RandomAccessFile("testfile.bin", "r")){ System.out.println(raf.readInt()); System.out.println(raf.readInt()); raf.seek(4 * 100); System.out.println(raf.readInt()); System.out.println(raf.readInt()); raf.seek(4 * 2); System.out.println(raf.readInt()); System.out.println(raf.readInt()); } } } ``` Notice that we are reading the output file of Example 1. The seek method will move the file pointer to a certain location in the file. **Q: What should be the output of this program?** ## How to deal with CSV Files A Comma Separated Values (CSV) file is a plain text file that stores data by delimiting data entries with commas. CSV files are often used when data needs to be compatible with many different programs. CSVs can be opened in text editors, spreadsheet programs like Excel, or other specialized applications. ### The Structure of a CSV File CSV files may sometimes be called Character Separated Values or Comma Delimited files. They mostly use the comma character to separate (or delimit) data, but sometimes use other characters, like semicolons. The idea is that you can export complex data from one application to a CSV file, and then import the data in that CSV file into another application. A CSV file has a fairly simple structure. It’s a list of data separated by commas. For example, let’s say you have a few stdents, and you export them as a CSV file. You’d get a file containing text like this: :::info name, gpa Student 1, 60.0 Student 2, 70.1 Student 3, 95.2 Student 4, 50.5 ::: ### Example 6 In this example, we will try to print objects to CSV files and convert them again to objects. #### Student Class ```java= public class Student{ private String name; private float gpa; public Student(String name, float gpa) { this.name = name; this.gpa = gpa; } @Override public String toString(){ return name + ", " + gpa; } } ``` #### Saving Object as .csv file ```java= ArrayList<Student> students = new ArrayList<>(); students.add(new Student("Student 1", 60)); students.add(new Student("Student 2", 70.1f)); students.add(new Student("Student 3", 95.2f)); students.add(new Student("Student 4", 50.5f)); try(PrintWriter pw = new PrintWriter("students.csv")){ //print header line pw.println("name, gpa"); for (Student s: students) { //print each student object as string pw.println(s); } } ``` #### Reading .csv file ```java= try(Scanner scanner = new Scanner(new File("students.csv"))){ //read header line String s = scanner.nextLine(); while (scanner.hasNext()){ s = scanner.nextLine(); String[] strings = s.split(", "); System.out.println(new Student(strings[0], Float.parseFloat(strings[1]))); } } ``` ## How to deal with Excel files using JExcel API library First, you have to load the following library `net.sourceforge.jexcelapi.jxl:2.6.12`. As shown on pre-lab 9. ### Example 7 In this example, we will try to print objects to Excel files and convert them again to objects. #### Student Class ```java= public class Student{ private String name; private float gpa; public Student(String name, float gpa) { this.name = name; this.gpa = gpa; } public String getName() { return name; } public float getGpa() { return gpa; } } ``` #### Saving Object as .xls file ```java= ArrayList<Student> students = new ArrayList<>(); students.add(new Student("Student 1", 60)); students.add(new Student("Student 2", 70.1f)); students.add(new Student("Student 3", 95.2f)); students.add(new Student("Student 4", 50.5f)); WritableWorkbook myFirstWbook = null; try { myFirstWbook = Workbook.createWorkbook(new File("students.xls")); WritableSheet excelSheet = myFirstWbook.createSheet("Sheet 1", 0); //head line excelSheet.addCell(new Label(0, 0, "name")); excelSheet.addCell(new Label(1, 0, "gpa")); for (int i = 0; i < students.size(); i++) { //write student name Label label = new Label(0, i + 1, students.get(i).getName()); excelSheet.addCell(label); //write student gpa Number number = new Number(1, i +1, students.get(i).getGpa()); excelSheet.addCell(number); } myFirstWbook.write(); } catch (IOException | WriteException e) { e.printStackTrace(); } finally { if (myFirstWbook != null) { try { myFirstWbook.close(); } catch (IOException | WriteException e) { e.printStackTrace(); } } } ``` #### Reading .xls file Try it yourself, if you need some help have a look at [this](https://mkyong.com/java/jexcel-api-reading-and-writing-excel-file-in-java/). ## Lab Tasks ### Task 1: Create a Hex Dump program In this task, you should create a program that takes a file name as an argument, and prints the hex dump of it, here is an example of my solution: <center> ![Task 1 Expected Ouptut](https://i.imgur.com/2cUgg91.png =500x) Task 1 Expected Ouptut </center> ### Task 2: Data Recovery program In this task, you should create a data recovery program, which will recover files from the hard disk after deleting it, these programs will search for something called **file signature** which is something that identifies files, then they extract that file from the hard disk binary. Take a look here: [List of file signatures - Wikipedia](https://en.wikipedia.org/wiki/List_of_file_signatures). Your program should take a file as input (to avoid destroying your hard drive you will read a file), and output what files it finds. The program should extract PDF and OGG files, PDF files will **always start** with these bytes: `25 50 44 46` And **end** with these bytes: `25 25 45 4F` OGG(open source media) files will **always start** with these bytes: `4F 67 67 53` And **end** with these bytes: `00 00 05 0E` Your program should search for this pattern and extract the PDF and PNG files from this dump file: [dumpfile.bin](https://drive.google.com/file/d/1WGND3Z9yIewKXXpzg7EO9EOcmRJRZRfg/view?usp=share_link). This dump file contains 2 pdf and 1 PNG files, so your program should output two files! ###### tags: `Computer Programming II` `Lab` `IUG` `Computer Engineering` <center>End Of Lab 9</center>