This commit is contained in:
2026-01-17 19:41:41 +03:00
parent a7021eee5c
commit 81223ec955
11 changed files with 681 additions and 1 deletions

39
file-filter/.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.kotlin
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

10
file-filter/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

7
file-filter/.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
file-filter/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
file-filter/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.filefilter</groupId>
<artifactId>file-filter-utility</artifactId>
<name>File Filter Utility</name>
<version>1.0.0</version>
<description>Утилита для фильтрации содержимого файлов по типам данных</description>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer>
<mainClass>com.filefilter.FileFilterApp</mainClass>
</transformer>
</transformers>
<finalName>file-filter</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
<picocli.version>4.7.5</picocli.version>
<maven.compiler.source>11</maven.compiler.source>
</properties>
</project>

70
file-filter/pom.xml Normal file
View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.filefilter</groupId>
<artifactId>file-filter-utility</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>File Filter Utility</name>
<description>Утилита для фильтрации содержимого файлов по типам данных</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<picocli.version>4.7.5</picocli.version>
</properties>
<dependencies>
<!-- Picocli для парсинга аргументов командной строки -->
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>${picocli.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- Maven Shade Plugin для создания fat JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.filefilter.FileFilterApp</mainClass>
</transformer>
</transformers>
<finalName>file-filter</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,240 @@
package com.filefilter;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
@Command(name = "file-filter",
mixinStandardHelpOptions = true,
version = "1.0",
description = "Утилита фильтрации содержимого файлов по типам данных")
public class FileFilterApp implements Runnable {
@Parameters(description = "Входные файлы для обработки")
private List<String> inputFiles = new ArrayList<>();
@Option(names = {"-o", "--output"},
description = "Путь для выходных файлов (по умолчанию: текущая директория)")
private String outputPath = ".";
@Option(names = {"-p", "--prefix"},
description = "Префикс имен выходных файлов")
private String prefix = "";
@Option(names = {"-a", "--append"},
description = "Режим добавления в существующие файлы")
private boolean appendMode = false;
@Option(names = {"-s", "--short-stats"},
description = "Краткая статистика")
private boolean shortStats = false;
@Option(names = {"-f", "--full-stats"},
description = "Полная статистика")
private boolean fullStats = false;
private Statistics statistics;
private FileWriterManager writerManager;
public static void main(String[] args) {
int exitCode = new CommandLine(new FileFilterApp()).execute(args);
System.exit(exitCode);
}
@Override
public void run() {
if (inputFiles == null || inputFiles.isEmpty()) {
System.err.println("Ошибка: не указаны входные файлы");
return;
}
statistics = new Statistics();
writerManager = new FileWriterManager(outputPath, prefix, appendMode);
// Обработка файлов
for (String inputFile : inputFiles) {
processFile(inputFile);
}
// Закрытие всех выходных файлов
writerManager.closeAll();
// Вывод статистики
printStatistics();
}
private void processFile(String filename) {
Path filePath = Paths.get(filename);
if (!Files.exists(filePath)) {
System.err.println("Предупреждение: файл не найден: " + filename);
return;
}
if (!Files.isReadable(filePath)) {
System.err.println("Предупреждение: файл недоступен для чтения: " + filename);
return;
}
try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
processLine(line, filename, lineNumber);
}
} catch (IOException e) {
System.err.println("Ошибка при чтении файла " + filename + ": " + e.getMessage());
}
}
private void processLine(String line, String filename, int lineNumber) {
if (line.trim().isEmpty()) {
return; // Пропускаем пустые строки
}
DataType type = detectType(line);
try {
switch (type) {
case INTEGER:
long intValue = Long.parseLong(line.trim());
writerManager.writeInteger(intValue);
statistics.addInteger(intValue);
break;
case FLOAT:
double floatValue = Double.parseDouble(line.trim());
writerManager.writeFloat(floatValue);
statistics.addFloat(floatValue);
break;
case STRING:
writerManager.writeString(line);
statistics.addString(line);
break;
}
} catch (IOException e) {
System.err.println("Ошибка при записи данных из файла " + filename +
", строка " + lineNumber + ": " + e.getMessage());
} catch (NumberFormatException e) {
// Если парсинг не удался, считаем строкой
try {
writerManager.writeString(line);
statistics.addString(line);
} catch (IOException ioException) {
System.err.println("Ошибка при записи строки из файла " + filename +
", строка " + lineNumber + ": " + ioException.getMessage());
}
}
}
private DataType detectType(String line) {
String trimmed = line.trim();
// Проверяем на целое число
try {
Long.parseLong(trimmed);
return DataType.INTEGER;
} catch (NumberFormatException e) {
// Не целое число
}
// Проверяем на вещественное число
try {
Double.parseDouble(trimmed);
return DataType.FLOAT;
} catch (NumberFormatException e) {
// Не число
}
// Иначе это строка
return DataType.STRING;
}
private void printStatistics() {
System.out.println();
if (!shortStats && !fullStats) {
return; // Статистика не запрошена
}
if (shortStats) {
printShortStatistics();
} else if (fullStats) {
printFullStatistics();
}
}
private void printShortStatistics() {
System.out.println("=== Краткая статистика ===");
if (statistics.getIntegerCount() > 0) {
System.out.println("Целые числа: " + statistics.getIntegerCount() + " элементов");
}
if (statistics.getFloatCount() > 0) {
System.out.println("Вещественные числа: " + statistics.getFloatCount() + " элементов");
}
if (statistics.getStringCount() > 0) {
System.out.println("Строки: " + statistics.getStringCount() + " элементов");
}
if (statistics.getIntegerCount() == 0 &&
statistics.getFloatCount() == 0 &&
statistics.getStringCount() == 0) {
System.out.println("Данные не обработаны");
}
}
private void printFullStatistics() {
System.out.println("=== Полная статистика ===");
if (statistics.getIntegerCount() > 0) {
System.out.println("\елые числа:");
System.out.println(" Количество: " + statistics.getIntegerCount());
System.out.println(" Минимум: " + statistics.getIntegerMin());
System.out.println(" Максимум: " + statistics.getIntegerMax());
System.out.println(" Сумма: " + statistics.getIntegerSum());
System.out.println(" Среднее: " + statistics.getIntegerAverage());
}
if (statistics.getFloatCount() > 0) {
System.out.println("\nВещественные числа:");
System.out.println(" Количество: " + statistics.getFloatCount());
System.out.println(" Минимум: " + statistics.getFloatMin());
System.out.println(" Максимум: " + statistics.getFloatMax());
System.out.println(" Сумма: " + statistics.getFloatSum());
System.out.println(" Среднее: " + statistics.getFloatAverage());
}
if (statistics.getStringCount() > 0) {
System.out.println("\nСтроки:");
System.out.println(" Количество: " + statistics.getStringCount());
System.out.println(" Длина самой короткой: " + statistics.getStringMinLength());
System.out.println(" Длина самой длинной: " + statistics.getStringMaxLength());
}
if (statistics.getIntegerCount() == 0 &&
statistics.getFloatCount() == 0 &&
statistics.getStringCount() == 0) {
System.out.println("Данные не обработаны");
}
}
private enum DataType {
INTEGER, FLOAT, STRING
}
}

View File

@@ -0,0 +1,135 @@
package com.filefilter;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
* Менеджер для управления записью данных в выходные файлы
*/
public class FileWriterManager {
private static final String INTEGERS_FILE = "integers.txt";
private static final String FLOATS_FILE = "floats.txt";
private static final String STRINGS_FILE = "strings.txt";
private final String outputPath;
private final String prefix;
private final boolean appendMode;
private BufferedWriter integerWriter;
private BufferedWriter floatWriter;
private BufferedWriter stringWriter;
/**
* Конструктор менеджера файлов
*
* @param outputPath путь для выходных файлов
* @param prefix префикс имен файлов
* @param appendMode режим добавления в файлы
*/
public FileWriterManager(String outputPath, String prefix, boolean appendMode) {
this.outputPath = outputPath != null ? outputPath : ".";
this.prefix = prefix != null ? prefix : "";
this.appendMode = appendMode;
}
/**
* Записать целое число в файл
*/
public void writeInteger(long value) throws IOException {
if (integerWriter == null) {
integerWriter = createWriter(INTEGERS_FILE);
}
integerWriter.write(String.valueOf(value));
integerWriter.newLine();
}
/**
* Записать вещественное число в файл
*/
public void writeFloat(double value) throws IOException {
if (floatWriter == null) {
floatWriter = createWriter(FLOATS_FILE);
}
floatWriter.write(String.valueOf(value));
floatWriter.newLine();
}
/**
* Записать строку в файл
*/
public void writeString(String value) throws IOException {
if (stringWriter == null) {
stringWriter = createWriter(STRINGS_FILE);
}
stringWriter.write(value);
stringWriter.newLine();
}
/**
* Создать writer для указанного файла
*/
private BufferedWriter createWriter(String filename) throws IOException {
Path dirPath = Paths.get(outputPath);
// Создаем директорию если не существует
if (!Files.exists(dirPath)) {
try {
Files.createDirectories(dirPath);
} catch (IOException e) {
throw new IOException("Не удалось создать директорию: " + outputPath +
". Причина: " + e.getMessage(), e);
}
}
Path filePath = dirPath.resolve(prefix + filename);
StandardOpenOption[] options;
if (appendMode) {
options = new StandardOpenOption[]{
StandardOpenOption.CREATE,
StandardOpenOption.APPEND
};
} else {
options = new StandardOpenOption[]{
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
};
}
try {
return Files.newBufferedWriter(filePath, StandardCharsets.UTF_8, options);
} catch (IOException e) {
throw new IOException("Не удалось создать файл: " + filePath +
". Причина: " + e.getMessage(), e);
}
}
/**
* Закрыть все открытые файлы
*/
public void closeAll() {
closeWriter(integerWriter, "integers");
closeWriter(floatWriter, "floats");
closeWriter(stringWriter, "strings");
}
/**
* Безопасно закрыть writer
*/
private void closeWriter(BufferedWriter writer, String type) {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
System.err.println("Предупреждение: ошибка при закрытии файла " +
type + ": " + e.getMessage());
}
}
}
}

View File

@@ -0,0 +1,112 @@
package com.filefilter;
/**
* Класс для сбора статистики по обработанным данным
*/
public class Statistics {
// Статистика для целых чисел
private long integerCount = 0;
private long integerMin = Long.MAX_VALUE;
private long integerMax = Long.MIN_VALUE;
private long integerSum = 0;
// Статистика для вещественных чисел
private long floatCount = 0;
private double floatMin = Double.MAX_VALUE;
private double floatMax = Double.MIN_VALUE;
private double floatSum = 0.0;
// Статистика для строк
private long stringCount = 0;
private int stringMinLength = Integer.MAX_VALUE;
private int stringMaxLength = Integer.MIN_VALUE;
/**
* Добавить целое число в статистику
*/
public void addInteger(long value) {
integerCount++;
integerMin = Math.min(integerMin, value);
integerMax = Math.max(integerMax, value);
integerSum += value;
}
/**
* Добавить вещественное число в статистику
*/
public void addFloat(double value) {
floatCount++;
floatMin = Math.min(floatMin, value);
floatMax = Math.max(floatMax, value);
floatSum += value;
}
/**
* Добавить строку в статистику
*/
public void addString(String value) {
stringCount++;
int length = value.length();
stringMinLength = Math.min(stringMinLength, length);
stringMaxLength = Math.max(stringMaxLength, length);
}
// Геттеры для целых чисел
public long getIntegerCount() {
return integerCount;
}
public long getIntegerMin() {
return integerCount > 0 ? integerMin : 0;
}
public long getIntegerMax() {
return integerCount > 0 ? integerMax : 0;
}
public long getIntegerSum() {
return integerSum;
}
public double getIntegerAverage() {
return integerCount > 0 ? (double) integerSum / integerCount : 0.0;
}
// Геттеры для вещественных чисел
public long getFloatCount() {
return floatCount;
}
public double getFloatMin() {
return floatCount > 0 ? floatMin : 0.0;
}
public double getFloatMax() {
return floatCount > 0 ? floatMax : 0.0;
}
public double getFloatSum() {
return floatSum;
}
public double getFloatAverage() {
return floatCount > 0 ? floatSum / floatCount : 0.0;
}
// Геттеры для строк
public long getStringCount() {
return stringCount;
}
public int getStringMinLength() {
return stringCount > 0 ? stringMinLength : 0;
}
public int getStringMaxLength() {
return stringCount > 0 ? stringMaxLength : 0;
}
}