В данном посте я хочу рассказать , как создать простое консольное приложение на 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
Комментарии (6)
czuryk
03.04.2023 08:18Не обижайте начинающих программистов, а то они когда станут сеньорами тоже над джунами будут издеваться )))
PS код действительно может кому то быть полезен...
MichaelSkirda
03.04.2023 08:183 минуса для хабра это еще нормально, особенно для начинающего программиста. Вообще хорошо, что у автора есть желание учиться и делиться опытом.
grossws
03.04.2023 08:18+1Рекомендую ознакомиться с использованием try-with-resources (есть даже в 1.8), оно наносит непоправимую пользу
headliner1985
03.04.2023 08:18+1Рекомендую вам ещё глянуть spring shell. Мне кажется там будет более удобно и стандартизированно, чем в кастомной библиотеке.
MichaelSkirda
Крутяк, я бы еще про пузырьковую сортировку почитал статью
Rodion56730 Автор
Наслаждайся) https://habr.com/ru/post/204600/