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);
}
}
}