В данном посте я хочу рассказать , как создать простое консольное приложение на Java с использованием библиотеки args4j.
Не давно мне дали задание написать консольную утилиту при помощи библиотеки для парсинга аргументов. Я выбрал args4j и хочу поделиться своим опытом.
Вот полный текст задания:
Разработать консольную утилиту, которая соединяет заданные в командной строке входные текстовые файлы в выходной, указываемый после ключа -out. С ключом -u делает обратную операцию, принимая один входной файл и разбивая его на несколько. Выходной файл тоже является текстовым. Придумать для него формат, позволяющий запоминать имена входных файлов и находить их границы. Command Line: tar -u filename.txt или tar file1.txt file2.txt … -out output.txt.
Сначала надо подключить зависимость, я использовал Maven. Тут все простенько:
<!-- вставьте это в свой pom.xml в <dependencies>--> <dependency> <groupId>args4j</groupId> <artifactId>args4j</artifactId> <version>2.33</version> </dependency>
Теперь можно реализовать парсинг аргументов. Создадим класс Parser и добавим туда две переменные и список для остальных аргументов.
public class Parser{ @Option(name = "-u") private File u; @Option(name = "-out") private String out; @Argument private String arguments; }
Аннотация сверху дает понять библиотеке args4j, где хранить аргументы , значения опций и всякое , в общем все прям для ленивых. Сейчас будет чуть сложнее, нужно осмыслить то , что получили из консоли:
public static void main(String[] args) { new Parser().run(args); } private void run(String[] args) { CmdLineParser parser = new CmdLineParser(this); try { parser.parseArgument(args); if ((arguments == null && out != null) || (u != null && out != null)) { System.err.println("Ошибка ввода аргументов!"); System.err.println("tar [опции...] аргументы..."); System.err.println("\nПример: tar -u \"filename.txt\" \n tar \"file1.txt file2.txt\" -out output.txt"); throw new IllegalArgumentException(""); } if (out != null) { new Delimiter().tar(arguments.split(" "), out); } else { if((u!=null && !Objects.requireNonNull(u).exists()) ){ throw new IOException("Папки или файла не существует"); } new Delimiter().tar(u); } } catch (CmdLineException | IOException e) { System.err.println(e.getMessage()); System.exit(1); } }
В данном кусочке в основном можно обойтись самой популярной комбинацией клавиш у программистов , но я все же попробую часть разжевать. В начале стоит понимать , что мои проверки могут вам не подойти (9 строчку скорее всего придется переделать) там просто проверяю правильно ли пользователь ввел аргументы и если да , то смотрю , что дальше с ними делать. Если опция -out активирована, то идем в эту часть кода:
public void tar(String[] arguments, String out) throws IOException, CmdLineException { File f = new File(out); FileWriter writer; StringBuilder builder; if (f.createNewFile()) { writer = new FileWriter(f); for (String argument : arguments) { if(new File(argument).exists()) { FileReader fr = new FileReader(argument); BufferedReader reader = new BufferedReader(fr); builder = new StringBuilder(); int countLines = 0; String temp; while ((temp = reader.readLine()) != null) { builder.append(temp).append("\n"); countLines++; } writer.write(argument + " " + countLines + "\n"); writer.write(builder.toString()); }else{ System.out.println("Неверный аргумент "+ argument + "\n пример: \"text1.txt text2.txt\" -out text3.txt"); } } writer.close(); } else { throw new IOException("Не возможно создать новый файл"); } }
Предварительно создал новый класс Delimiter и написал две простенькие функции. Не думаю , что кому-то это сильно пригодится , да и тут в принципе не сложно , так что рассказывать не буду. Второй метод (просто перегрузил метод tar) :
public void tar(File u) throws IOException { FileReader fr = new FileReader(u); BufferedReader reader = new BufferedReader(fr); String buf = reader.readLine(); FileWriter writer; if(buf.matches("([A-Za-z0-9-_.]+/?)+ [0-9]+")) { while (buf != null) { String[] data = buf.trim().split(" "); String name = data[0]; int size = Integer.parseInt(data[1]); File f = new File(name); if (f.createNewFile()) { StringBuilder builder = new StringBuilder(); writer = new FileWriter(f); for (int i = 0; i < size; i++) { builder.append(reader.readLine()).append("\n"); } writer.write(builder.toString()); writer.close(); } else { System.out.println("Файл уже существует"); } buf = reader.readLine(); } }else{ reader.close(); throw new IOException("Неверные данные , нужен другой файл!"); } reader.close(); }
Эта функция тоже простая , основная идея в том , что когда файлы соединяются, метод пишет название файла, который был добавлен + число строчек в файле , а когда файлы нужно разделить , метод считывает название файла и количество строк которые нужно бездумно считывать и так далее пока файл не закончится.
Осталось самое главное
Нужно как-то собрать jar файл , чтобы запускать его из консоли. Есть два пути , один сложный и правильный , второй простой , но он не имеет ничего общего с хорошей программой. Для первого способа нужно прописывать все зависимости в manifest , но я пока для этого способа сыроват , есть второй - с помощью плагина:
<!-- Это нужно прописать в зависимости в pom в <dependencies>--> <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.5.0</version> </dependency> <!-- Это нужно прописать в plugins в pom --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.5.0</version> <configuration> <archive> <manifest> <mainClass>org.spbstu.gorchatovra.Parser</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>assemble-all</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
Надеюсь , код , который я написал выше, хотя бы частично понятен, ну если что загуглите , я сделал все, что мог.
Вот и подошел к концу пост , надеюсь кому-то смог помочь, я программист мягко говоря начинающий , так что я открыт для предложений , готовый проект тут.
Источники: args4j
