user3514355
user3514355

Reputation:

Java: How to parse a structured TXT file?

I am trying to create a converter from a structured TXT into Excel table and I am having issues with TXT file reading and proper data storing.

A TXT file is given with the following content:

-
HOSTNAME: hostname1
IP: ipAddress1
DEVICE INFO:
NAME: deviceName1_1, SERIALNUMBER: serialNumber1_1
-
HOSTNAME: hostname2
IP: ipAddress2
DEVICE INFO:
NAME: deviceName2_1, SERIALNUMBER: serialNumber2_1
NAME: deviceName2_2, SERIALNUMBER: serialNumber2_2
NAME: deviceName2_3, SERIALNUMBER: serialNumber2_3
-
HOSTNAME: hostname3
IP: ipAddress3
DEVICE INFO:
NAME: deviceName3_1, SERIALNUMBER: serialNumber3_1
NAME: deviceName3_2, SERIALNUMBER: serialNumber3_2

Please take notice that this TXT file has 3 blocks of information. Each block of information is split by a special symbol "-". A TXT file can have more or less blocks of information. Under device info there can be more or less lines of device names and serial numbers.

It is expected to parse the file and to store data in created objects.

An object should have these fields:

String hostname;
String ip;
String name;
String serialnumber;

Usually 1 object may be created per block of information. If under the device info there are multiple lines of device name and serial number, then multiple objects should be created having the same hostname and IP, but different device name and serial number.

The expected result:
In total 6 objects should be created with the following data.

Object#1 has hostname1, ipAddress1, deviceName1, serialNumber1
Object#2 has hostname2, ipAddress2, deviceName2_1, serialNumber2_1
Object#3 has hostname2, ipAddress2, deviceName2_2, serialNumber2_2
Object#4 has hostname2, ipAddress2, deviceName2_3, serialNumber2_3
Object#5 has hostname3, ipAddress3, deviceName3_1, serialNumber3_1
Object#6 has hostname3, ipAddress3, deviceName3_2, serialNumber3_2


So far I have tried writing this code:

private ArrayList<Device> readFile() {

        ArrayList<Device> devices = new ArrayList<Device>
        BufferedReader br = null;

            try {
                br = new BufferedReader(new InputStreamReader(new FileInputStream(txtFile)));

                String line = "";
                String data;
                int i=0;
                while ((line = br.readLine()) != null) {
//                  Device device = new Device();
                    if (line.equals("-")) {
//                      Device device = new Device();
                        while ((line = br.readLine()) != null) {
                            Device device = new Device();
                            if (line.contains("HOSTNAME: ")) {
//                              Device device = new Device();
                                if (line.substring(0,10).equals("HOSTNAME: ")) {
                                    device.setHostname(line.substring(10,line.length()));
                                    devices.add(device);
                                }
                            }
                            if (line.contains("IP: ")) {
//                              Device device = new Device();
                                if (line.substring(0,4).equals("IP: ")) {
                                    device.setIp(line.substring(4,line.length()));
                                    devices.add(device);
                                }
                            }
                        devices.add(device);
                        }
                    }
                }
            }

But then objects have a hostname, but IP is NULL or vice versa. I have also tried this code:

try {
            Scanner scanner = new Scanner(txtFile);
            int i = 0;
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                String array[] = line.split(",");
                DeviceData device = new DeviceData(array[0],array[1]);
                System.out.println("Eilute " + (i++) + ": " + array[0]);
    }

But I have lost myself here.

I am having trouble with separating desired data and putting it into objects. How should I do it right as expected? Any ideas and/or suggestions?

Upvotes: 1

Views: 769

Answers (2)

Mario Dekena
Mario Dekena

Reputation: 843

I would structure the parsing into multiple functions and also check, if the syntax of the file is right. Suggestion:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class ReadDevices {

    public static class InvalidFileException extends Exception {
        private static final long serialVersionUID = -6525977749423883875L;
    }

    public static void main(String[] args) {
        ArrayList<Device> devices;
        try {
            devices = readFile("yourFile.txt");
        } catch (IOException | InvalidFileException e) {
            System.out.println("Something is wrong with the file!");
            return;
        }
        // do something with devices
    }

    public static ArrayList<Device> readFile(String file) throws IOException, InvalidFileException {
        ArrayList<Device> devices = new ArrayList<Device>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        // discard "-"
        assertLine(reader.readLine(), "-");
        String hostnameLine;
        while ((hostnameLine = reader.readLine()) != null) {
            String hostname = parseLineWithLabel(hostnameLine, "HOSTNAME");
            String ip = parseLineWithLabel(reader.readLine(), "IP");
            assertLine(reader.readLine(), "DEVICE INFO:");

            String line;
            String[] deviceLabels = new String[] { "NAME", "SERIALNUMBER" };
            while ((line = reader.readLine()) != null) {
                if (line.equals("-"))
                    break;
                String[] deviceInfo = parseLineWithMultiLabel(line, deviceLabels);
                devices.add(new Device(hostname, ip, deviceInfo[0], deviceInfo[1]));
            }
        }
        reader.close();
        return devices;
    }

    private static String parseLineWithLabel(String line, String label) throws InvalidFileException {
        String[] parts = line.split(": ");
        if (!parts[0].equals(label))
            throw new InvalidFileException();
        return parts[1];
    }

    private static String[] parseLineWithMultiLabel(String line, String[] labels) throws InvalidFileException {
        String[] multi = line.split(", ");
        String[] result = new String[multi.length];
        for (int i = 0; i < multi.length; i++)
            result[i] = parseLineWithLabel(multi[i], labels[i]);
        return result;
    }

    private static void assertLine(String line, String value) throws InvalidFileException {
        if (!line.equals(value))
            throw new InvalidFileException();
    }
}

It will throw an InvalidFileException if the file has not the right structure. You can then handle the error in the calling function.

Upvotes: 0

mavroprovato
mavroprovato

Reputation: 8372

You should create device objects when you encounter a line starting with "NAME: ". In order to keep the IP and HOSTNAME values, you should use local variables. A sample implementation could look like this:

br = new BufferedReader(new InputStreamReader(
        new FileInputStream(txtFile)));
String line;
while ((line = br.readLine()) != null) {
    if (line.equals("-")) {
        String ip = null;
        String hostname = null;
        while ((line = br.readLine()) != null) {
            if (line.contains("HOSTNAME: ")) {
                if (line.substring(0, 10).equals("HOSTNAME: ")) {
                    hostname = line.substring(10, line.length());
                }
            }

            if (line.contains("IP: ")) {
                if (line.substring(0, 4).equals("IP: ")) {
                    ip = line.substring(4, line.length());
                }
            }

            if (line.contains("NAME: ")) {
                if (line.substring(0, 6).equals("NAME: ")) {
                    Device device = new Device();
                    device.setIp(ip);
                    device.setHostname(hostname);
                    System.out.println("Adding device with ip = " +
                            ip + " and hostname " + hostname);
                    System.out.println("Details: " + line);
                    devices.add(device);
                }
            }
        }
    }
}

Upvotes: 1

Related Questions