Lesson 16 - Working with custom files in Java - Zip archive

In the previous lesson, Working with files and folders in Java - New API, we showed how to work with files and folders in Java. Now you can work with many kinds of files, you can save and open them, play them, catch errors, ... But imagine a real application to manage employees. An employee will have text data (first name, last name, and email), a date (date of birth), a number (phone number) and a picture (their photo). Just for the sake of the picture it could be a problem to save all this data in one single file. Theoretically, we could choose some binary data format (because of the image) and insert text data into it. But it practice, binary files are quite awkward and it's hard to keep up with format changes.

Zip

Similar applications often use archives to store data. Consider MS-Word and its documents with the .docx file extension. If you change the extension of any .docx file to .zip, you will find that the document is actually a zip archive, with only a different extension. Try it.

Windows hide file extensions of known file types by default, so you can see Document instead of Document.docx. To change the settings, go to Control Panel -> Switch to the Icons view -> Folder Options -> Uncheck Hide extensions of known types.

Archives can contain multiple files and the user sees them as one from the outside without suspecting anything like that. The zip archive is exactly what we'll use to store our employee. And instead of .zip we'll set the file a completely different extension, it can be .employee or if you want to stick to three letters, just .emp.

The only thing the file extension does is telling Windows what application it should use to open the file when the user double-clicks it. Usually, each file name ends with a dot and a 3-letter extension. In fact, the filename doesn't have to have an extension at all, may have more of them, it may be longer than 3 characters, and may not even match what is really stored in the file. We'll mask the .zip file as .emp. We won't keep the original .zip extension to prevent the confused user from unpacking it and modifying the files.

The .emp file format

The zip folder structure could be as follows:

  • data.emp
    • employees.xml
    • images/
      • firstnamelastname_1.png
      • firstnamelastname_2.png

The employees.xml file might look like this:

<employees>
    <employee>
        <firstName>Thomas</firstName>
        <lastName>Cooper</lastName>
        <email>[email protected]</email>
        <phone>123456789</phone>
        <birthdate>1/1/1970</birthdate>
    </employee>
</employees>

The <employees> element wrapping the employees is here so the application can handle multiple employees in the future. It's necessary to think about such "small things" in the design phase.

Creating the Employee application

Create a new project, form application. An archive with the project is available below the article. There are all necessary form elements already generated in the project and the buttons have handling methods prepared.

A form to manage Employees in Java

Class Employee

Let's start with what should be clear - properties. Our employee will have:

  • first name,
  • last name,
  • email,
  • telephone number,
  • birthdate,
  • and will have a photo:
public class Employee {

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private LocalDate birthdate;
    private BufferedImage image;

    public Employee() {
        this("", "", "", "", LocalDate.now());
    }

    public Employee(String firstName, String lastName, String email, String phone, LocalDate birthdate) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.phone = phone;
        this.birthdate = birthdate;
    }

    @Override
    public String toString() {
        return "Employee{" + "first name=" + firstName + ", last name=" + lastName + '}';
    }
}

The class has two constructors. The first overload creates an empty employee. We use the second constructor to create an employee instance with all the data except for the image.

Getters and setters

The following code are just getters and setters for the class properties:

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}

public LocalDate getBirthdate() {
    return birthdate;
}

public void setBirthdate(LocalDate birthdate) {
    this.birthdate = birthdate;
}

public BufferedImage getImage() {
    return image;
}

public void setImage(BufferedImage image) {
    this.image = image;
}

We'll add an Employee variable to the form, but we won't instantiate it:

private Employee employee;

Employee manager

To keep the logic and GUI layers separated, we'll create a new class to manage employees. We'll name the class simply EmployeeManager. The class will contain a collection of employees. The collection will be DefaultListModel so we can use it for more employees later.

private final DefaultListModel<Employee> employees = new DefaultListModel<>();

Next, we'll create four methods in the class: save(), load(), getFirst(), and saveFirst(). We'll implement the save() and load() methods in the next lesson. The last two methods are here just to keep things simple, so that we can work with one employee easily. Their implementation will be as follows:

public Employee getFirst() {
    return employees.size() == 0 ? new Employee() : employees.get(0);
}

public void saveFirst(Employee employee) {
    this.employees.clear();
    this.employees.addElement(employee);
}

Editing the form

That would be everything in the manager for now. Let's move to the form for a second and create there a manager instance. We'll let it instantiate the Employee class for us:

private final EmployeeManager manager = new EmployeeManager();
private Employee employee = manager.getFirst();

In addition, we'll add two helper methods to the form's code to update the information on the form and in the Employee instance:

private void refreshForm() {
    jTxtFirstName.setText(employee.getFirstName());
    jTxtLastName.setText(employee.getLastName());
    jTxtEmail.setText(employee.getEmail());
    jTxtPhoneNumber.setText(employee.getPhone());
    jTxtBirthday.setText(Constants.FORMAT_DATA.format(employee.getBirthdate()));
    jPanel1.getGraphics().drawImage(employee.getImage(), 0, 0, 123, 135, null);
}

private void loadFromForm() {
    employee.setFirstName(jTxtFirstName.getText());
    employee.setLastName(jTxtLastName.getText());
    employee.setEmail(jTxtEmail.getText());
    employee.setPhone(jTxtPhoneNumber.getText());
    employee.setBirthdate(LocalDate.parse(jTxtBirthday.getText(), Constants.FORMAT_DATA));
}

Button handling

Finally, let's look at the button handlers.

Selecting the image

The first handler we're going to implement is the image selection button:

private void jBtnImageActionPerformed(java.awt.event.ActionEvent evt) {
    loadFromForm();
    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setFileFilter(new FileNameExtensionFilter("Images...", "png"));
    final int result = fileChooser.showOpenDialog(this);
    if (result == JFileChooser.APPROVE_OPTION) {
        final File image = fileChooser.getSelectedFile();
        try {
            employee.setImage(ImageIO.read(image));
            refreshForm();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

First, we save any values from the form components to the Employee class instance. Next, we create a new JFileChooser dialog to select the user image. If the image is selected successfully, ImageIO.read() will load the image and save it to the employee. Finally, we call the refreshForm() method to display the image on the form.

Saving

The handler of the save button will look like this:

private void jBtnSaveActionPerformed(java.awt.event.ActionEvent evt) {
    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setFileFilter(new FileNameExtensionFilter("Employee files...", "emp"));
    final int result = fileChooser.showSaveDialog(this);
    if (result == JFileChooser.APPROVE_OPTION) {
        final File employeeFile = fileChooser.getSelectedFile();
        try {
            loadFromForm();
            manager.saveFirst(employee);
            manager.save(employeeFile);
        } catch (IOException | XMLStreamException e) {
            e.printStackTrace();
        }
    }
}

Using JFileChooser dialog, we select the file to which we want to store our data. If we select the file, we load the data from the form into the employee instance. We pass this instance to the manager to save the data. Finally, using the save() method we write all the data to the file.

Loading

As the last thing, we'll show how to load the data back:

private void jBtnLoadActionPerformed(java.awt.event.ActionEvent evt) {
    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setFileFilter(new FileNameExtensionFilter("Employee files...", "emp"));
    final int result = fileChooser.showOpenDialog(this);
    if (result == JFileChooser.APPROVE_OPTION) {
        final File employeeFile = fileChooser.getSelectedFile();
        try {
            manager.load(employeeFile);
            employee = manager.getFirst();
            refreshForm();
        } catch (IOException | ParserConfigurationException | SAXException e) {
            e.printStackTrace();
        }
    }
}

Once again, we display the JFileChooser dialog in the method, this time to select the employee. If we select the file, we call the load() method on the EmployeeManager class instance. After loading the data successfully, we display the data of the first employee on the form.

Now we have the application designed. Next time, in the lesson Working with custom files in Java - Saving and loading ZIPs, we'll finally look at the actual processing of ZIP files in Java and export and import our employees.


 

Download

Downloaded 0x (40.55 kB)
Application includes source codes in language Java

 

 

Activities (6)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!