Pytanie Dlaczego mój plik się zamyka, jeśli przez jakiś czas nic z nim nie robię?


Oryginalna sytuacja:

Aplikacja, nad którą właśnie pracuję, otrzyma powiadomienie z innej aplikacji, gdy dany plik ma dodane dane i jest gotowy do odczytu. W tej chwili mam coś takiego:

class Foo(object):
    def __init__(self):
        self.myFile = open("data.txt", "r")
        self.myFile.seek(0, 2) #seeks to the end of the file

        self.mainWindow = JFrame("Foo",
                                 defaultCloseOperation = JFrame.EXIT_ON_CLOSE,
                                 size = (640, 480))
        self.btn = JButton("Check the file", actionPerformed=self.CheckFile)
        self.mainWindow.add(self.btn)
        self.mainWindow.visible = True

    def CheckFile(self, event):
        while True:
            line = self.myFile.readline()
            if not line:
                break
            print line

foo = Foo()

W końcu funkcja CheckFile () zostanie uruchomiona po odebraniu określonego komunikatu na gnieździe. W tej chwili uruchamiam go z JButton.

Pomimo faktu, że plik nie jest nigdzie nigdzie dotykany w programie, a ja go nie używam with w aktach, ciągle dostaję ValueError: I/O operation on closed file kiedy próbuję readline() to.

Pierwsze rozwiązanie:

Próbując ustalić, kiedy dokładnie plik został zamknięty, zmieniłem kod aplikacji na:

foo = Foo()
while True:
    if foo.myFile.closed == True:
        print "File is closed!"

Ale problem zniknął! Lub jeśli zmienię to na:

foo = Foo()
foo.CheckFile()

to początkowy CheckFile(), dzieje się od razu, działa. Ale kiedy kliknę przycisk ~ 5 sekund później, wyjątek zostanie podniesiony ponownie!

Po zmianie nieskończonej pętli na just pass, i odkrywając, że wszystko wciąż działa, mój wniosek był taki, że początkowo, nic nie pozostało do zrobienia po utworzeniu a Foo, kod aplikacji się kończył, foo wychodził poza zakres, a więc foo.myFile wychodził poza zakres i plik został zamknięty. Mimo to huśtawka utrzymywała okno otwarte, co powodowało błędy, gdy próbowałem operować na nieotwartym pliku.

Dlaczego wciąż jestem zdezorientowany:

Dziwną częścią jest, jeśli foo wyszedł poza zasięg, dlaczego więc huśtawka wciąż była w stanie się w nią wciągnąć foo.CheckFile() w ogóle? Kiedy klikam na JButton, czy błąd nie powinien być taki, że obiekt lub metoda już nie istnieje, a nie metoda, która jest wywoływana pomyślnie i daje błąd w działaniu pliku?

Mój następny pomysł był taki, że być może, gdy JButton próbował zadzwonić foo.CheckFile() i znalazłem to foo już nie istniał, stworzył nowy Foo, jakoś pominąłem jego __init__ i poszedł prosto do niego CheckFile(). Jednak nie wydaje się, aby tak było. Jeśli zmienię Foo.__init__ aby pobrać parametr, zapisz go w self.myNumi wydrukuj go CheckFile(), wartość, którą przekazuję, gdy tworzę instancję początkową, zawsze tam jest. Wydaje się, że to sugeruje foo w ogóle nie wychodzi z zakresu, co stawia mnie z powrotem tam, gdzie zacząłem !!!

EDYTOWAĆ: Poprawiono pytanie z odpowiednimi informacjami z komentarzy i usunięto wiele z tych komentarzy.


12
2017-08-09 05:48


pochodzenie


Czy druga aplikacja pisząca do pliku data.txt otwiera wyłącznie plik? - arunkumar
Myślę, że jest całkiem jasne, że system zbierania śmieci Jython jest tym, co Cię tu potknęło. Python z jego przeliczaniem nie wpadłby na ten problem, jako że słabym refem byłby jedyny sposób na zrobienie tego file być zamknięte, ale potem Foo również zostaną zabici. Dokładny opis tego, co się tutaj dzieje, powinien być interesujący ... - Chris Morgan
czy ktoś to duplikował? - andrew cooke
aby zapisać kogoś, kto to sugeruje (to była odpowiedź, którą usunąłem) - nie wydaje się prawdopodobne, że jest tak, ponieważ plik jest w trybie tekstowym. istnieje pewne przesunięcie w poszukiwaniu plików tekstowych, ale koniec pliku powinien być w porządku (ograniczenie polega na uniknięciu przeskakiwania do środka wielobajtowego znaku). - andrew cooke


Odpowiedzi:


* Pierwsza, częściowa odpowiedź (dodano do pytania) *

Myślę, że właśnie to wymyśliłem. Po foo = Foo(), nie pozostawiając kodu, aby moduł był zajęty, wydaje się, że obiekt przestał istnieć, mimo że aplikacja nadal działa, a okno Swing robi coś.

Jeśli to zrobię:

foo = Foo()
while True:
    pass

Wtedy wszystko działa tak, jak bym się spodziewał.

Wciąż jednak jestem zdezorientowany, jak w ogóle dzwoniono do foo.CheckFile (). Jeśli problem polegał na tym, że foo.myFile wychodził poza zakres i był zamknięty, to w jaki sposób foo.CheckFile () mógł zostać wywołany przez JButton?

Może ktoś inny może zapewnić lepszą odpowiedź.


4
2017-08-09 05:59



Dla wyjaśnienia, jest to "Wstępne rozwiązanie" wspomniane w pytaniu. To nie odpowiada na pytanie "Dlaczego wciąż jestem zagubiony", na co naprawdę zasługuje nagroda agfa. - Cam Jackson
Czy próbowałeś przenieść wszystko z __init__ do a run metoda, a następnie from javax.swing import SwingUtilities i SwingUtilities.invokeLater(Foo()) w zasięgu globalnym? (Jeśli nie masz racji, to się zgadzam, opiszę to jako odpowiedź). - agf
Właśnie dowiedziałem się o SwingUtilities dzisiaj, więc to jest coś, na co zajrzę. Ale będzie musiało poczekać do poniedziałku rano, to sprawa pracy: P - Cam Jackson
Sprawienie, by Foo odziedziczyło po JFrame, nie robiło różnicy. Szybko próbowałem użyć SwingUtilities, ale nie udało mi się jeszcze go uruchomić. Kod w pytaniu to całe źródło, więc zachęcamy do samodzielnego wykonania pracy, jeśli wiesz, jak działa SwingUtilities. - Cam Jackson
Po odkryciu, że powinienem używać SwingUtilities do uruchamiania rzeczy na EDT (przeszedłem wiele tutoriali Swinga, które zupełnie nie wspominają o tym), poświęcałem czas, aby dowiedzieć się, jak to działa. Niestety, nie miało to znaczenia. Wciąż nie ma na to realnego rozwiązania, poza domniemaną zgadywanką Brandona, która, jak podejrzewam, jest prawdopodobnie poprawna. - Cam Jackson


Myślę, że problem powstaje z partycjonowania pamięci dwa typy w Javie, sterty i bez sterty. Twoja instancja klasy foo zostaje zapisany w pamięci sterty podczas jej metody CheckFile jest ładowany do obszaru metody pamięci pozagiełdowej. Po zakończeniu działania skryptu nie ma już żadnych odniesień do foo więc zostanie oznaczony do usuwania śmieci, podczas gdy interfejs Swing nadal się odwołuje CheckFile, więc zostanie oznaczony jako w użyciu. Zakładam to foo.myFile nie jest uważany za statyczny, więc jest również przechowywany w pamięci sterty. Jeśli chodzi o interfejs Swing, prawdopodobnie nadal jest śledzony jako używany, o ile okno jest otwarte i aktualizowane przez menedżera okien.


Edycja: twoje rozwiązanie użycia a while True Pętla jest poprawna, moim zdaniem. Użyj go do monitorowania zdarzeń, a gdy okno się zamknie lub odczytana zostanie ostatnia linia, wyjdź z pętli i pozwól, aby program się zakończył.


Edycja 2: alternatywne rozwiązanie - spróbuj foo dziedzicz z JFrame aby Swing utrzymywał stały wskaźnik w swojej głównej pętli, dopóki okno jest otwarte.


2
2017-08-12 11:57



@agf: Jest to odpowiedź na pytanie, dlaczego tak się dzieje, co było jednoznaczne. Myślę, że rozwiązanie tego, jak tego uniknąć, znajduje się właśnie w jego obszarze "Wstępne rozwiązanie". Musi utworzyć główną pętlę systemu dla programu, który monitoruje aktualizacje (odczytuje linie z pliku lub zdarzenia niszczenia okna), a kiedy wszystko jest gotowe, wychodzi z pętli, a odśmiecanie wykonuje swoją pracę.
@agf: Zobacz komentarz CamJacksona na temat własnej odpowiedzi; nie chodzi tylko o znalezienie rozwiązania pozwalającego uniknąć problemu, ale o to, dlaczego tak się dzieje.
Swing nie obsługuje automatycznie głównej pętli? Wydaje się to bardzo, bardzo standardową rzeczą do wykonania zestawu narzędzi GUI. Ponadto żaden z przykładów Jython lub Java Swing nie ma wyraźnej pętli głównej. On chce lepszego rozwiązania, i ja też (dlatego ustawiam nagrodę). - agf
@agf: Myślę, że Swing obsługuje główną pętlę, więc przyznaję, że to trochę dziwne. Nie współpracowałem zbyt wiele z Jythonem, więc nie jestem ekspertem, ale może lepiej by było foo dziedzicz z JFrame. Kiedy zaczyna się główna pętla Swinga, powinna zachować trwałe odniesienie foo dopóki okno nie zostanie zamknięte.
Jakoś nie mogę uwierzyć, że przycisk może zawierać odnośnik do pliku BoundMethod CheckFile bez utrzymywania żywej instancji. BoundMethods mają odwołanie do ich instancji. - Jürgen Strobel