В данном посте я хочу рассказать , как создать простое консольное приложение на 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)


  1. MichaelSkirda
    03.04.2023 08:18
    +5

    Крутяк, я бы еще про пузырьковую сортировку почитал статью


    1. Rodion56730 Автор
      03.04.2023 08:18
      -3

      Наслаждайся) https://habr.com/ru/post/204600/


  1. czuryk
    03.04.2023 08:18

    Не обижайте начинающих программистов, а то они когда станут сеньорами тоже над джунами будут издеваться )))

    PS код действительно может кому то быть полезен...


    1. MichaelSkirda
      03.04.2023 08:18

      3 минуса для хабра это еще нормально, особенно для начинающего программиста. Вообще хорошо, что у автора есть желание учиться и делиться опытом.


  1. grossws
    03.04.2023 08:18
    +1

    Рекомендую ознакомиться с использованием try-with-resources (есть даже в 1.8), оно наносит непоправимую пользу


  1. headliner1985
    03.04.2023 08:18
    +1

    Рекомендую вам ещё глянуть spring shell. Мне кажется там будет более удобно и стандартизированно, чем в кастомной библиотеке.