Загрузка данных


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;

/**
 * Вспомогательный класс с общими ресурсами и методами для потоков
 * {@link WriterThread} и {@link CheckerThread}.
 * <p>
 * Синхронизация доступа к файлу обеспечивается через конструкцию
 * {@code synchronized} на объекте-мониторе {@link #MONITOR}.
 * </p>
 *
 * @author Student
 * @version 1.0
 */
public class FileHelper {

    /** Имя рабочего файла. */
    public static final String FILE_NAME = "currentdata.txt";

    /**
     * Объект-монитор для синхронизации.
     * Оба потока синхронизируются на этом объекте, чтобы
     * переименование не выполнялось во время записи.
     */
    public static final Object MONITOR = new Object();

    /**
     * Возвращает текущую дату и время в формате {@code yyyy-MM-dd HH:mm:ss}.
     * Использует {@link java.util.Calendar}.
     *
     * @return строка с текущей датой и временем
     */
    public static String currentTime() {
        Calendar c = Calendar.getInstance();
        return String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c);
    }

    /**
     * Формирует уникальное имя файла на основе даты, времени и миллисекунд.
     *
     * @return уникальное имя вида {@code saved_yyyyMMdd_HHmmss_SSS.txt}
     */
    public static String uniqueName() {
        Calendar c = Calendar.getInstance();
        return String.format("saved_%1$tY%1$tm%1$td_%1$tH%1$tM%1$tS_%1$tL.txt", c);
    }

    /**
     * Возвращает текущий размер файла {@link #FILE_NAME} в байтах.
     * Использует класс {@link java.io.File}.
     *
     * @return размер файла в байтах или {@code 0L}, если файла нет
     */
    public static long fileSize() {
        try {
            File f = new File(FILE_NAME);
            return f.exists() ? f.length() : 0L;
        } catch (SecurityException e) {
            System.err.println("Нет доступа к файлу: " + e.getMessage());
            return 0L;
        }
    }

    /**
     * Сохраняет текущий файл под уникальным именем и обнуляет исходный.
     * <p>
     * Метод <b>должен вызываться только при удержании монитора
     * {@link #MONITOR}</b> — иначе возможно переименование файла
     * во время записи первым потоком.
     * </p>
     * Использует {@link java.io.File} для переименования и
     * {@link java.io.FileOutputStream} для обнуления.
     *
     * @throws IOException если переименование или обнуление не удалось
     */
    public static void saveAndClear() throws IOException {
        File src = new File(FILE_NAME);

        // Проверка существования и непустоты файла
        if (!src.exists() || src.length() == 0) {
            return;
        }

        // Формируем уникальное имя и переименовываем
        File dst = new File(uniqueName());
        if (!src.renameTo(dst)) {
            throw new IOException("Не удалось переименовать "
                    + src.getName() + " в " + dst.getName());
        }

        // Обнуляем исходный файл через FileOutputStream с append=false
        try (FileOutputStream fos = new FileOutputStream(FILE_NAME, false)) {
            // открытие с append=false автоматически очищает файл
        } catch (IOException e) {
            throw new IOException("Не удалось обнулить файл "
                    + FILE_NAME + ": " + e.getMessage(), e);
        }
    }
}