Чтение XML файла в Java unit тесте: простое решение
Обязательно убедитесь в том, что файл example.txt находится в директории src/test/resources , если вы используете для работы инструменты Maven или аналогичные инструменты в Gradle.
Использование InputStream для получения String
Предлагаемый подход к преобразованию InputStream в String выглядит следующим образом:
Скопировать код
String result = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)) .lines().collect(Collectors.joining("\n"));
В этом фрагменте кода применяются функциональные возможности Java 8, а также используется указанная кодировка, где оптимальным вариантом будет UTF-8.
Библиотеки, упрощающие работу
Работа с файлами становится значительно проще, если использовать такие библиотеки как Apache Commons IO и Google Guava.
Скопировать код
String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8); // Спасибо Apache Commons IO за облегчение задачи!
Когда важен размер: работа с большими файлами
Если вы столкнулись с работой с большими файлами, стоит избегать ошибок OutOfMemoryError, исполняя чтение содержимого файла по строкам или воспользуйтеcь потоками. Важно также учесть те ситуации, когда доступ к файлу ограничен или файл не может быть найден.
Будущее уже здесь: Java NIO
С версии языка Java 7, класс java.nio.file.Files предлагает методы для эффективного чтения файлов:
Скопировать код
List lines = Files.readAllLines(Paths.get(resource.toURI()), StandardCharsets.UTF_8); String content = String.join("\n", lines); // Теперь проблемы с переводами строк в прошлом!
Визуализация
Представим, что ваш unit-тест — это кухня, а рецепт (ресурс) — необходим для приготовления блюда (теста).
Возьмём кухню(тестовую среду) : Рецепт (ресурс) — необходимость для блюда (теста).
Чтение рецепта — Представляет собой получение списка ингредиентов (чтение текстового файла ресурса).
- Находим рецепт на полке (определяем расположение файла).
: Находим ‘»Boiled_water.txt»‘ в директории ‘resources’.
- Читаем инструкции (загружаем ресурс).
: Используем getResourceAsStream(«/Boiled_water.txt») для чтения файла ‘Boiled_water.txt’.
- Приступаем к выполнению рецепта (используем загруженный ресурс).
✨: Проверяем и подтверждаем свойства, основываясь на прочитанном рецепте.
Таким образом, вы просто и легко сможете найти и использовать ресурсы, подобно опытному шеф-повару!
Построение надёжности
Важно предусмотреть обработку ошибок и исключений, которые могут возникнуть при чтении файла.
SAX and DOM parsing in Java
Для начала разберемся, что такое XML файл и для чего он нужен.
Для Java-приложений XML-файлы могут также служить в качестве конфигурационных файлов (например, для сохранения параметров приложения, конфигурации сервисов и других настроек).
Также, XML файл достаточно удобен для передачи какой либо информации между разными системами (например между сервером и телефоном). Представляет собой текстовый файл, содержащий информацию в структурированном виде, который понятен для большинства языков программирования, и как раз в этом и есть основное назначение XML файла.
XML(eXtensible Markup Language) — расширяемый язык разметки документов. В отличие от HTML, который направлен на визуальное представление документа в браузере, XML используется для обмена данными между компьютером и приложением.
Внутри, файл выглядит, как набор тегов с информацией(открывающие и закрывающие) в виде древовидной структуры.
Рассмотрим пример ниже. В каждом файле существует корневой тег — в нашем случае (он может иметь любое имя, в зависимости от выполняемой задачи). Далее, идут ветви, их может быть несколько, в нашем случае они одного типа с тегом voter и visit. И внутри мы имеем атрибуты с их значениями.
Далее, на основе XML нам нужно создать объектную модель. Для этого создается пакет model и в нем создается класс, с таким именем, как и в XML файле.
Класс создается для добавления и дальнейшей работы с элементами, которые находятся в XML файле.
Существуют несколько стратегий обработки XML документов. Мы
рассмотрим — DOM (Document Object Model) и SAX (Simple API for XML). Основное их отличие связано с тем, что использование DOM позволяет читать и вносить изменения в существующий XML-документ, а также создавать новый. Стратегия использования SAX основывается на том, что содержимое XML-документа только анализируется. XML-текст может быть больших размеров: DOM должен весь документ «заглотить» и проанализировать, а SAX-парсер обрабатывает XML-документ последовательно и не требует дополнительной памяти.
DOM API
DOM (Document Object Model) — это стандартный способ представления и взаимодействия с содержимым XML-документов в программах на Java. Предоставляет процесс обработки по факту, загружая файл полностью в память. Хорошо работает с небольшими файлами.
Для парсинга, нам следует открыть файл, используя объекты типа — File, DocumentBuilderFactory, DocumentBuilder, Document.
В DOM есть три важных объекта — Node(каждый элемент(отступы, строки и тд) в XML), NodeList(получаем лист наших Node), Element(конкретный объект, заключаемый в тег).
SAX API
SAX(Simple API for XML) — это API, который используется для чтения и обработки XML-документов в Java. Он очень быстр и мало зависит от объема данных, за счет этого имеет большую популярность.
Чтение XML документа с помощью SAX является событийном процессом, то есть SAX предоставляет набор обработчиков событий, которые вызываются автоматически при обработке каждого элемента документа. Файл в память подгружается частями.
Для парсинга мы используем объекты типа — SAXParserFactory(Определяет API фабрики, который позволяет приложениям сконфигурировать и получить SAX базируемый синтаксический анализатор, чтобы проанализировать XML-документы), SAXParser. И для успешной работы парсера нам необходимо переопределить нужные нам методы класса DefaultHandler.
Как на JAVA прочитать XML файл и сохранить нужные теги в txt
Подскажите пожалуйста как прочитать файл xml и сохранить нужные теги из xml в txt?Как прочитать я нашел пример,а вот как в нужном формате и нужные теги сохранить в файл txt нет вариантов и примеров.
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; import org.w3c.dom.Element; import java.io.File; public class ReadXMLFile < public static void main(String argv[]) < try < File fXmlFile = new File("C:/Users/m/1.xml"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(fXmlFile); doc.getDocumentElement().normalize(); System.out.println("Root element :" + doc.getDocumentElement().getNodeName()); NodeList nList = doc.getElementsByTagName("RPC"); System.out.println("----------------------------"); for (int temp = 0; temp < nList.getLength(); temp++) < Node nNode = nList.item(temp); System.out.println("\nCurrent Element :" + nNode.getNodeName()); if (nNode.getNodeType() == Node.ELEMENT_NODE) < Element eElement = (Element) nNode; System.out.println("nLineOff : " + eElement.getElementsByTagName("nLineOff") .item(0).getTextContent()); System.out.println("nSampOf : " + eElement.getElementsByTagName("nSampOff") .item(0).getTextContent()); System.out.println("nLatOff : " + eElement.getElementsByTagName("nLatOff") .item(0).getTextContent()); System.out.println("nLogOff : " + eElement.getElementsByTagName("nLogOff") .item(0).getTextContent()); System.out.println("nHeightOff : " + eElement.getElementsByTagName("nHeightOff") .item(0).getTextContent());
5785 4499 52.9228 51.2782 88 5785 4500 0.2657 0.3863 1000 -0.000629859420341615,-0.223122036521553,1.12086419504931,-0.00166704310369315,0.0798597682706705,-0.000899894909963547,0.00452992546379495,-0.00498748520833035,-0.19287326775007,-8.02494837414716e-006,-0.00175245427363783,0.00872684259858483,0.0924116681162977,0.00330580402582468,-0.0534953241623651,-0.220768199926586,-0.0165982505580707,0.000376542853708549,0.00123610261105306,2.46952697602973e-005 1,0.0349982910036457,-0.171965466071745,0.00378529601232002,0.0435950815503886,-0.0013451064641388,0.000810424022544801,-0.0386705988037442,-0.196998549022927,-0.014808547070133,-1.58057179388088e-006,-3.94321130622832e-005,0.000485925893074298,8.50005809004955e-006,0.000435329396104605,-0.000184313172903366,-4.13928280693823e-006,-1.45601625707564e-006,1.00712449717027e-006,-1.62246321693561e-009 -0.003581376214989,-1.23999388532035,-0.33375378178584,-0.0089249060727823,-0.377350306048088,-0.000343628359105678,-0.00340616403483169,0.136805969291967,-0.112451794001893,8.30351273299052e-006,-0.00502068410363809,0.341147340488919,0.292923369023971,0.00475258337204313,0.139287474541054,0.0738581437485123,0.00122282963400602,0.00560805330976629,0.000324523732033018,3.39691952758513e-005 1,-0.100469576238657,0.342731813830848,-0.00106839175550786,-0.036322535737517,-0.00229461974715611,0.00429871271034196,-0.275663554167947,-0.222377712459759,-0.00381610993591663,0.000120925008163237,-0.00254906454270333,-0.0018228051271036,-2.94135306231405e-005,-0.00270145938972221,-0.00175693286779135,-4.27857847608908e-005,0.000564958154223928,0.000523081585364959,8.17777145449374e-006
А вот как должно получиться
LINE_OFF: +016861.00 pixels SAMP_OFF: +09000.00 pixels LAT_OFF: +31.91180000 degrees LONG_OFF: +34.83660000 degrees HEIGHT_OFF: +0151.000 meters LINE_SCALE: +016861.00 pixels SAMP_SCALE: +09000.00 pixels LAT_SCALE: +00.35000000 degrees LONG_SCALE: +000.27250000 degrees HEIGHT_SCALE: +01000.000 meters LINE_NUM_COEFF_1: -2.46171188635817E-04 LINE_NUM_COEFF_2: -1.47710964084078E-01 LINE_NUM_COEFF_3: -1.06673007501914E+00 LINE_NUM_COEFF_4: +5.19941637061845E-04 LINE_NUM_COEFF_5: -3.55654494286889E-02 LINE_NUM_COEFF_6: -9.80856071325358E-03 LINE_NUM_COEFF_7: -7.15318128266239E-02 LINE_NUM_COEFF_8: +6.73934234589977E-03 LINE_NUM_COEFF_9: +7.82996474433665E-02 LINE_NUM_COEFF_10: +4.6133622833714E-05 LINE_NUM_COEFF_11: +2.11551917752547E-01 LINE_NUM_COEFF_12: +3.38124239437932E-02 LINE_NUM_COEFF_13: -4.111212231148E-02 LINE_NUM_COEFF_14: +7.24423632364558E-03 LINE_NUM_COEFF_15: +2.36786172122104E-01 LINE_NUM_COEFF_16: +1.13371499977947E-01 LINE_NUM_COEFF_17: +5.32253491635625E-02 LINE_NUM_COEFF_18: +3.14170792230535E-02 LINE_NUM_COEFF_19: -1.20184342996339E-01 LINE_NUM_COEFF_20: -2.59016826406118E-05 LINE_DEN_COEFF_1: +1.000000000000000E+00 LINE_DEN_COEFF_2: +4.39761245167075E-02 LINE_DEN_COEFF_3: -7.34157175750287E-02 LINE_DEN_COEFF_4: +6.70071844747449E-02 LINE_DEN_COEFF_5: +5.32337872838106E-02 LINE_DEN_COEFF_6: -2.13795569967263E-01 LINE_DEN_COEFF_7: +1.12579030832835E-01 LINE_DEN_COEFF_8: -2.29223869490968E-01 LINE_DEN_COEFF_9: -1.06565742876344E-01 LINE_DEN_COEFF_10: -4.98303114973655E-02 LINE_DEN_COEFF_11: +1.03547646590588E-04 LINE_DEN_COEFF_12: -3.35515101379487E-05 LINE_DEN_COEFF_13: -1.27927628481434E-04 LINE_DEN_COEFF_14: -1.6718322058499E-05 LINE_DEN_COEFF_15: +6.16730230707693E-05 LINE_DEN_COEFF_16: -6.69051745615597E-05 LINE_DEN_COEFF_17: +1.78092278049708E-05 LINE_DEN_COEFF_18: -7.5619677347166E-05 LINE_DEN_COEFF_19: -7.60462558298554E-05 LINE_DEN_COEFF_20: +8.5618310563909E-07 SAMP_NUM_COEFF_1: +5.3207492868647E-03 SAMP_NUM_COEFF_2: +1.32527441382844E+00 SAMP_NUM_COEFF_3: -4.06661889823262E-01 SAMP_NUM_COEFF_4: +1.19482554000525E-03 SAMP_NUM_COEFF_5: -8.71092464725264E-01 SAMP_NUM_COEFF_6: +1.83554695124862E-03 SAMP_NUM_COEFF_7: -1.4192691109485E-03 SAMP_NUM_COEFF_8: -1.01108718491505E-01 SAMP_NUM_COEFF_9: +2.76524195549878E-01 SAMP_NUM_COEFF_10:-2.33672396665198e-005 SAMP_NUM_COEFF_11: -8.83936860421929E-04 SAMP_NUM_COEFF_12: -4.47479184150679E-03 SAMP_NUM_COEFF_13: +2.44088258384728E-01 SAMP_NUM_COEFF_14: -6.08823715677875E-03 SAMP_NUM_COEFF_15: +6.51513147236411E-02 SAMP_NUM_COEFF_16: -8.33450145155483E-02 SAMP_NUM_COEFF_17: +1.85983393077634E-03 SAMP_NUM_COEFF_18: +6.31482475699896E-04 SAMP_NUM_COEFF_19: +4.79590317963116E-04 SAMP_NUM_COEFF_20: -5.41846884544707E-006 SAMP_DEN_COEFF_1: +1.000000000000000E+00 SAMP_DEN_COEFF_2: -7.47583814681025E-02 SAMP_DEN_COEFF_3: -6.7745918621938E-01 SAMP_DEN_COEFF_4: -8.30972360837843E-04 SAMP_DEN_COEFF_5: +4.81098553101387E-02 SAMP_DEN_COEFF_6: +6.50744079860006E-04 SAMP_DEN_COEFF_7: +9.86332260057519E-05 SAMP_DEN_COEFF_8: -5.4512876046618E-03 SAMP_DEN_COEFF_9: +1.97221105606794E-01 SAMP_DEN_COEFF_10: -4.59324283097777E-03 SAMP_DEN_COEFF_11: -1.02594722777159E-04 SAMP_DEN_COEFF_12: +1.27606857420804E-04 SAMP_DEN_COEFF_13: -2.08533649717521E-04 SAMP_DEN_COEFF_14: -8.11354685815867E-06 SAMP_DEN_COEFF_15: +1.13012977791055E-03 SAMP_DEN_COEFF_16: +7.45530007608694E-04 SAMP_DEN_COEFF_17: -1.34849361180783e-05 SAMP_DEN_COEFF_18: +2.60925409576969E-06 SAMP_DEN_COEFF_19: -4.53323469824312E-04 SAMP_DEN_COEFF_20: +1.04986842051962e-05
Универсальный загрузчик XML на java. Или как загрузить файлы ГАР на 250 гб и остаться при памяти
С проблемой загрузки больших XML столкнулся при переходе с КЛАДР и ФИАС на справочники ГАР - Государственный адресный реестр (Федеральная информационная адресная система).
Справочник ГАР содержит более подробную информацию чем предыдущие классификаторы. В том числе информацию по муниципальным делениям. В связи с чем справочник после распаковки занимет около 250 ГБ, что примерно в 3 раза больше чем тот же ФИАС.
Предыдущая загрузка работала на DOM-модели, т.е. весь XML-файл считывался в память. Соответственно при попытке загрузить ГАР таким же способом стали стабильно получать OutOfMemory. А значит настало время менять подход к загрузке)
DOM (Document Object Model) - это стандартный интерфейс для работы с документами в формате XML (Extensible Markup Language). DOM-модель представляет XML-документ в виде дерева объектов, где каждый элемент и атрибут документа является узлом дерева.
SAX (Simple API for XML) является событийно-ориентированным API для чтения XML-документа. Он предоставляет возможность читать XML-документ последовательно и обрабатывать события, такие как начало и конец элемента, содержимое элемента и т.д.
StAX (Streaming API for XML) также является API для последовательного чтения и записи XML-документов. Он предоставляет потоковый доступ к XML-документу, позволяя читать его и записывать по частям. StAX предоставляет возможность читать и записывать XML-документы в виде потока событий, аналогично SAX, но также предоставляет возможность читать и записывать XML-документы в виде итерируемых наборов событий. StAX позволяет эффективно обрабатывать большие XML-документы и не требует реализации обработчиков событий.
Загрузка XML-документа с помощью DOM-модели довольно медленная, особенно для больших документов, поскольку требует создания полной структуры DOM в памяти. Однако, DOM-модель позволяет легко и удобно работать с XML-документами, поэтому она широко используется в Java-приложениях.
SAX и StAX позволяет обрабатывать XML-документы любого размера, поскольку он не хранит всю структуру в памяти. Однако, для работы необходимо реализовать обработчики событий.
Одним из главных преимуществ использования StAX является его скорость работы и эффективность. И и отличие от DOM, который загружает весь XML-документ в память перед его обработкой, StAX-парсер обрабатывает XML-документ по одному элементу за раз, что позволяет работать с большими XML-файлами.
Понятно. Останавливаемся на StAX 🙂
Реализуем класс для универсальной загрузки XML. Будем читать данные комфортными порциями и мапить их на произвольные объекты. Класс объекта передаем в загрузчик.
public class XMLAttributeReader < private Logger logger = LoggerFactory.getLogger(XMLAttributeReader.class); private InputStream inputStream; private String attr; private XMLEventReader eventReader; private ObjectMapper mapper; private final Integer RECORDS_COUNT; private void configure() < mapper = new ObjectMapper(); mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); try < XMLInputFactory factory = XMLInputFactory.newInstance(); eventReader = factory.createXMLEventReader(inputStream); >catch (XMLStreamException e) < logger.error(e.getMessage()); >> public void close() < try < eventReader.close(); >catch (XMLStreamException e) < e.printStackTrace(); >> public XMLAttributeReader(InputStream inputStream, String attr, Integer RECORDS_COUNT) < this.inputStream = inputStream; this.attr = attr; this.RECORDS_COUNT = RECORDS_COUNT; configure(); >public Boolean hasNext() < return eventReader != null ? eventReader.hasNext() : false; >public List getNextPart(Class valueType) < ListvalueList = new ArrayList<>(); int count = 0; try < while (eventReader.hasNext() && count < RECORDS_COUNT) < XMLEvent event = eventReader.nextEvent(); switch (event.getEventType()) < case XMLStreamConstants.START_ELEMENT: StartElement startElement = event.asStartElement(); String qName = startElement.getName().getLocalPart(); if (qName.equalsIgnoreCase(attr)) < Map map = attributesToMap(startElement.getAttributes()); T value = mapper.convertValue(map, valueType); valueList.add(value); count++; >break; > > > catch (XMLStreamException e) < logger.error(e.getMessage()); >return valueList; > private static Map attributesToMap(Iterator attributes) < Mapmap = new HashMap<>(); while (attributes.hasNext()) < Attribute attr = attributes.next(); map.put(attr.getName().toString(), attr.getValue()); >return map; > >
Структура справочника состоит из нескольких типов XML-файлов. Для каждой создадим таблицу в БД, опишим сущности. Пример для адресных объектов:
package com.example.XMLToBase.db.entity; import javax.persistence.*; import java.util.Date; // @Data @Entity @Table(name = "gar_addressobject") public class GarAddressobject
Читаем нашим XML загрузчиком адреса пачками в структуру GarAddressobject и тут же производим сохранение в БД.
private void processAddr(File file) < logger.info("Start loading " + file.getParent() + "/" + file.getName()); try (InputStream is = new FileInputStream(file)) < XMLAttributeReader xmlReader = new XMLAttributeReader(is, "OBJECT", RECORDS_PER_ITERATION); int i = 0; int j = 1; Listlist; while (xmlReader.hasNext()) < list = xmlReader.getNextPart(GarAddressobject.class); garAddressobjectRepository.saveAll(list); i += Math.min(RECORDS_PER_ITERATION, list.size()); if ((i / RECORDS_PER_ITERATION) != j)< j = i / RECORDS_PER_ITERATION; logger.info("saved records: " + i); >list.clear(); > logger.info("saved records: " + i); xmlReader.close(); > catch (IOException e) < e.printStackTrace(); >>
Для файлов домов, муниципальных образований и пр. алгоритм такой же, полный код загрузчика по ссылке
- Регламентная загрузка ГАР перестала падать изза нехватки памяти
- Можно управлять кол-вом строк, которые за раз вычитывает XML-загрузчик
- Сам загрузчик довольно универсальный, его можно переиспользовать в других задачах
- Понимаем отличия в подходах DOM и SAX. Знаем где какой вариант лучше подойдет 🙂
Всем спасибо! Комментарии приветствуются