2012-06-28 15 views
15

Obecnie pracuję nad projektem, który przetwarza pliki z katalogu źródłowego w jednej z jego procedur. Jest proces Java, który szuka określonego katalogu i próbuje czytać i przetwarzać pliki, jeśli istnieją. Pliki są zamykane i aktualizowane przez proces innej osoby trzeciej. Pytanie brzmi: jak mogę sprawdzić, czy plik jest całkowicie napisany? Próbuję użyć file.length(), ale wygląda na to, że nawet jeśli proces pisania nie został zakończony, zwraca rzeczywisty rozmiar. Mam wrażenie, że rozwiązanie powinno być zależne od platformy. Każda pomoc będzie doceniona.Sprawdzanie, czy plik jest całkowicie zapisany.

AKTUALIZACJA: To pytanie nie różni się znacząco od duplikatu, ale ma odpowiedź z działającym fragmentem kodu, który jest wysoko oceniany.

+3

Czy rozważałeś użycie blokad plików? – cklab

+0

Dzięki. Sprawdzam to. Czy możemy być pewni, że zamki są zawsze tworzone w procesie pisania? –

+2

Cóż, chodzi o to, że jeśli spróbujesz uzyskać blokadę, powinieneś otrzymać wyjątek. Właśnie natknąłem się na to: http://docs.oracle.com/javase/7/docs/api/java/io/File.html # canWrite% 28% 29 Nigdy go nie używałeś, ale możesz go zrobić, żeby zobaczyć, jak to działa. Wygląda ciekawie. – cklab

Odpowiedz

9

Czy producent procesu zamyka plik po zakończeniu jego pisania? Jeśli tak, próba otwarcia pliku w procesie konsumenta z wyłączną blokadą zakończy się niepowodzeniem, jeśli proces producenta nadal trwa.

+1

Pliki są kopiowane za pomocą polecenia rsync pod linuxem, więc uważam, że tak. Fajny pomysł, spróbuję teraz. –

+0

Czy możesz napisać przykład ilustrujący procedurę? –

+0

To nie jest bardzo pomocna poprawna odpowiedź :( –

2

Nie sądzę, że istnieje ogólne rozwiązanie tego problemu. Poszukiwanie rozmiaru pliku jest nieprawidłowe, ponieważ niektóre aplikacje mogą ustawić rozmiar pliku przed każdym wywołaniem zapisu. Jedną z możliwości jest użycie blokowania. Będzie to wymagało, aby pisarz posiadał blokadę zapisu (lub wyłączną blokadę). Jeśli nie możesz zmodyfikować programu piszącego, możesz użyć narzędzi dostarczonych przez system operacyjny, takich jak utrwalacz w systemie Linux, aby zobaczyć, że istnieje proces, który nadal uzyskuje dostęp do pliku.

1

Jeśli zamierzasz użyć tego kodu na jednej platformie, może być w stanie używać NIO's FileLock facility. Ale uważnie przeczytaj dokumentację i zauważ, że na wielu platformach blokada jest tylko doradcza.

Innym rozwiązaniem jest mieć jeden proces zapisać plik z nazwą, że proces ten nie będzie wiedział, a następnie zmień nazwę pliku na rozpoznawalnej nazwy kiedy zapis jest kompletny. Na większości platform operacja zmiany nazwy ma wartość atomową, jeśli źródło i miejsce docelowe są tym samym woluminem systemu plików.

+0

Dobra rada, dziękuję, zrobię to, jeśli nie uda się z Javą.To jest trochę trudne, aby zmienić zachowanie producenta z powodu pewnych okoliczności –

13

Mam roztwór roboczy:

private boolean isCompletelyWritten(File file) { 
    RandomAccessFile stream = null; 
    try { 
     stream = new RandomAccessFile(file, "rw"); 
     return true; 
    } catch (Exception e) { 
     log.info("Skipping file " + file.getName() + " for this iteration due it's not completely written"); 
    } finally { 
     if (stream != null) { 
      try { 
       stream.close(); 
      } catch (IOException e) { 
       log.error("Exception during closing file " + file.getName()); 
      } 
     } 
    } 
    return false; 
} 

Dzięki @cklab i @Will i wszyscy inni, którzy je szukać w "exclusive lock" sposób. Właśnie napisałem tutaj kod, aby inni zainteresowani korzystali z niego. Wierzę, że rozwiązanie z przemianowaniem sugerowane przez @tigran działa również, ale czyste rozwiązanie Java jest lepsze dla mnie.

P.S. Początkowo użyłem FileOutputStream zamiast RandomAccessFile, ale blokuje to zapisywanie pliku.

+2

To działa na Winows, ale nie na Linuksie – Nilesh

+0

@Nelish to jest dziwne, ponieważ początkowo zaimplementowałem je w systemie Linux dla Linuksa –

+0

Cóż, próbowałem go w systemie UNIX.Aplikacja winscp lub ftp przesyłała plik podczas próby zablokowania i mogłem to zrobić! – Nilesh

1

Jedno proste rozwiązanie Użyłem w przeszłości dla tego scenariusza z Windows jest użycie boolean File.renameTo(File) i próbować przenieść oryginalny plik do oddzielnego folderu pomostowego:

Jeśli success jest false, wówczas potentiallyIncompleteFile jest wciąż zapisywane.

+0

Dobra sugestia dla użytkowników systemu Windows, ale nie jest ona agnostyczna. W systemie Linux/Unix można usuwać i zmieniać nazwy plików, które są nadal otwarte przez inne procesy. –

+1

Dlatego moja odpowiedź brzmi "z systemem Windows", a nie "dla wszystkich systemów". – JoshDM

Powiązane problemy