2016-07-18 2 views
1

Я пытаюсь создать конвертер из структурированного TXT в таблицу Excel, и у меня возникают проблемы с чтением файла TXT и правильное хранение данных.Java: как разобрать структурированный TXT-файл?

Файл TXT дается со следующим содержанием:

-
HOSTNAME: hostname1
IP: ipAddress1
DEVICE INFO:
ИМЯ: deviceName1_1, SERIALNUMBER: serialNumber1_1
-
HOSTNAME: hostname2
IP : ipAddress2
ИНФОРМАЦИЯ О УСТРОЙСТВЕ:
ИМЯ: deviceName2_1, SERIALNUMBER: serialNumber2_1
ИМЯ: deviceName2_2, SERIALNUMBER: serialNumber2_2
ИМЯ: deviceNam e2_3, SERIALNUMBER: serialNumber2_3
-
HOSTNAME: hostname3
IP: ipAddress3
DEVICE INFO:
ИМЯ: deviceName3_1, SERIALNUMBER: serialNumber3_1
ИМЯ: deviceName3_2, SERIALNUMBER: serialNumber3_2

Пожалуйста, обратите внимание, что это TXT файл имеет 3 блоки информации. Каждый блок информации разделен специальным символом «-». Файл TXT может иметь более или менее блоки информации. Под информация об устройстве может быть более или менее строк наименований устройств и серийных номеров.

Ожидается, что он проанализирует файл и сохранит данные в созданных объектах.

Объект должен иметь следующие поля:

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

Обычно один объект может быть создан на блок информации. Если под информацией устройства есть несколько строк имени устройства и серийных номер, то несколько объекты должны быть созданы с тем же именем хоста и IP, но другое имя устройства и серийный номер ,

Ожидаемый результат:
Всего 6 объектов должны быть созданы со следующими данными.

Объект # 1 имеет hostname1, ipAddress1, deviceName1, serialNumber1
Объект # 2 имеет hostname2, ipAddress2, deviceName2_1, serialNumber2_1
Объект # 3 имеет hostname2, ipAddress2, deviceName2_2, serialNumber2_2
Объект # 4 имеет hostname2, ipAddress2 , deviceName2_3, serialNumber2_3
Объект # 5 имеет hostname3, ipAddress3, deviceName3_1, serialNumber3_1
Объект # 6 имеет hostname3, ipAddress3, deviceName3_2, serialNumber3_2


До сих пор я пытался писать этот код:

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); 
         } 
        } 
       } 
      } 

Но объекты имеют имя хоста, но IP является NULL или наоборот. Я также пробовал этот код:

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]); 
    } 

Но я потерялся здесь.

У меня возникли проблемы с разделением желаемых данных и их помещением в объекты. Как я должен делать это правильно, как ожидалось? Любые идеи и/или предложения?

+0

Вы можете добавить чек для символа -, а затем просто выполнить цикл и проверить следующую строку, пока не достигнете конца документа. –

+0

@SvenOlderaan Да, я добавил чек для символа «-», он показан в моем фрагменте кода _if (line.equals («-»)) {_ , и я попытался сделать еще один цикл с while. Но он по-прежнему дает мне строку за строкой, и я не могу поместить данные в каждый объект для каждого цикла. – ig90

ответ

1

Вам необходимо создать объекты устройства, если вы столкнулись с линией, начинающейся с «NAME:». Чтобы сохранить значения IP и HOSTNAME, вы должны использовать локальные переменные. Пример реализация может выглядеть следующим образом:

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); 
       } 
      } 
     } 
    } 
} 
+0

Я тестировал его, и он работает! Необходимо было определить поля _ip_ и _hostname_ в первом поле while, тогда как поле цикла и имени должно быть определено под вторым циклом while. Объект должен был быть создан, когда действительно найдена строка с именем «NAME:»! Теперь это имеет смысл. Спасибо! – ig90

+0

@ ig90 Рад, что этот ответ сработал для вас. Хотя этот ответ верен, имейте в виду, что всегда полезно проверить свой файл, чтобы убедиться, что он имеет правильную структуру. См. Мой ответ о том, как правильно это сделать. Он автономный и готовый к запуску (кроме класса Device). –

0

Я бы структурировать разбор на несколько функций, а также проверить, если синтаксис файла является правильным. Предложение:

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(); 
    } 
} 

Он выкинет InvalidFileException, если файл не имеет правильной структуры. Затем вы можете обработать ошибку в вызывающей функции.

+0

Я внимательно посмотрел на ваш код. Он компактный, передовой и полезный. Я попытался использовать его, но в _assertLine (reader.readLine(), «DEVICE INFO:»); _ он не сравнивает строку String _line_ и String _value_: ** ИМЯ: deviceName1_1, SERIALNUMBER: serialNumber1_1 ** и ** ИНФОРМАЦИЯ О УСТРОЙСТВЕ: ** Тем не менее, ваш код интересен, мне придется изучить его больше. Спасибо, что поделились этим кодом. – ig90

+0

@ ig90 Хм.Я действительно пробовал свой код с вашими данными примера, и он работает безупречно. Может быть, ваша файловая структура немного отключена? Как ведущие или завершающие пробелы? Кстати, было бы разумно урезать их во время обработки;) –

+0

Aha! Потому что я добавил несколько System.out.printlns над вашим _assertLine (reader.readLine(), «DEVICE INFO:»); _ это бросило мне исключение. При добавлении дополнительных строк печати метод _assertLine_ не проверяет соответствующие строки. Это интересно. Без моих линий печати ваш код работает безупречно. И да, я буду обрезать пробелы программным путем :) – ig90

Смежные вопросы