Это очень запутанная проблема.
У нас есть Java-приложение (Java8 и работающее на JBoss 6.4), которое зацикливает определенное количество объектов и записывает несколько строк в файл на каждом раунде.
В каждом раунде мы проверяем, получили ли мы объект File в качестве параметра, и если нет, мы создаем новый объект и создаем физический файл:
if (file == null){
File file = new File(filename);
try{
file.createNewFile();
} catch (IOException e) {e.printStackTrace();}}
Итак, идея в том, что файл создается только один раз, после чего шаг пропускается и мы сразу приступаем к написанию. Переменное имя файла не является путем, это просто имя файла без пути, поэтому файл создается по пути jboss_root/tmp/hsperfdata_имя пользователя/
редактировать1. Я добавлю сюда также методы, используемые при написании, если они имеют отношение к делу:
fw = new FileWriter(indeksiFile, true); // append = true
bw = new BufferedWriter(fw);
out = new PrintWriter(bw);
.
.
out.println(..)
.
.
out.flush();
out.close(); // this flushes as well -> line above is useless
Итак, теперь проблема в том, что иногда, довольно редко, физический файл исчезает из пути в середине процесса. Ссылка на java-объект никогда не теряется, но кажется, что сам объект исчезает, потому что код автоматически создает файл снова по тому же пути и продолжает записывать в него данные. Этого бы не произошло, если бы условие file == null не оценивалось как истинное. Очевидно, что эффект заключается в том, что мы теряем строки, которые были записаны в предыдущий файл. Java-приложение не замечает никаких ошибок и продолжает работать.
Итак, у меня было бы три тесно связанных вопроса, на которые я не смог найти ответ в Google.
Помощь приветствуется! Спасибо!




File.createNewFile Я никогда не использовал в своем коде: это не нужно.
При последующей записи в файл он, вероятно, создает его заново или добавляет.
В любом случае есть гонка в файловой системе. Кроме того, поскольку это не атомарные действия,
вы можете получить что-то нестабильное.
Итак, вы хотите записать в файл, добавив существующий файл или создав его. Для текста UTF-8:
Path path = Paths.get(filename);
try (PrintWriter out = new PrintWriter(
Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.APPEND),
false)) {
out.println("Killroy was here");
}
После комментария Честно говоря, насколько вы заинтересованы в причине, трудно сказать. Перезапуск приложения или исключения ввода-вывода (?), которые можно найти в журналах. Добавьте ведение журнала в определенный журнал для добавления к файлам и (регистрируемую) периодическую проверку существования этих файлов.
охрана Здесь мы делаем повторный физический доступ к файловой системе.
Чтобы предотвратить добавление к файлу дважды одновременно (из которых я ожидаю исключения), можно создать критическую секцию в той или иной форме.
// For 16 semaphores:
final int semaphoreCount = 16;
final int semaphoreMask = 0xF;
Semaphore[] semaphores = new Semaphore[semaphoreCount];
for (int i = 0; i < semaphores.length; ++i) {
semaphores[i] = new Semaphore(1, true); // FIFO
}
int hash = filename.hashcode() & semaphoreMask ; // toLowerCase on Windows
Semaphore semaphore = semaphores[hash];
try {
semaphore.aquire();
... append
} finally {
semaphore.release();
}
Блокировка файлов была бы более техническим решением, которое я бы не хотел предлагать.
Лучшим решением, которое у вас, возможно, уже есть, будет очереди сообщений на файл.
Данные могут исчезнуть из-за createNewFile, так как атомарность не гарантируется. То же самое, когда один и тот же файл добавляется одновременно. Одна мера, которую я добавлю к ответу.
«Перезапуск приложения или исключения ввода-вывода (?) можно найти в журналах. Добавьте ведение журнала в определенный журнал для добавления к файлам и (зарегистрированную) периодическую проверку существования этих файлов». Приложение ничего не замечает, никаких исключений ввода/вывода. И да, мы проверили, что файл сначала создается, затем исчезает, а затем снова создается, регистрируя периодическую проверку. Помните, что createNewFile (по крайней мере, должен) вызываться только один раз. Итак, каков будет механизм, из-за которого файл, который он создал, исчезнет позже? Что вы подразумеваете под добавлением одновременно, кем?
Я имел в виду параллелизм, если более одного потока будут делать то же самое. Или в редком случае при перезапуске приложения (сделав дважды createNewFile). Наиболее вероятной причиной может быть второй createNewFile для имени файла такой же — дубликат имени файла, созданный каким-то образом. Например, с временным шаблоном ччммсс вместо ччммсс; первый - это двенадцатичасовой повторяющийся узор. Также System.currentMillis может не продвигать свой длинный результат. Проще говоря: Не имею представления.
Я уверен, что это, вероятно, очень близко к решению проблемы, но это не помогает мне понять явление, наблюдаемое с текущим решением. В качестве справочной информации: текущее решение уже находится в разработке и работает примерно в 90% случаев (что, безусловно, недостаточно). Я бы очень хотел знать, какой механизм теперь отвечает за исчезновение файла.