2015-07-14 23 views
5

Chcę móc odczytać plik programu Excel w języku Python, pozostawić skrypt Python uruchomiony, robiąc coś innego po zakończeniu odczytu, i móc edytować plik Excel w innym w międzyczasie. Używam Pythona 2.7 i Openpyxl.Openpyxl nie zamyka skoroszytu programu Excel w trybie tylko do odczytu

Obecnie wygląda następująco:

from openpyxl import load_workbook 

def get_excel_data(): 
    OESwb = load_workbook(filename = OESconfigFile, data_only=True, 
          read_only=True) 
    ws = OESwb.get_sheet_by_name('MC01') 
    aValue = ws['A1'].value 
    return aValue 

val = get_excel_data() 

Po uruchomieniu funkcji, plik Excel jest nadal zamknięte dla dostępu z innych procesów (to daje błąd „«filename»jest aktualnie w użyciu Spróbuj ponownie później. ") nawet wtedy, gdy nie chcę już czytać tego w Pythonie.

Jak mogę zamknąć plik z mojego skryptu? Próbowałem OESwb.close(), ale daje błąd "" Workbook "obiekt nie ma atrybut" zamknij "". Znalazłem this post, ale wydaje się, że to nie pomaga.

EDYTOWANIE: Wygląda na to, że OESwb.save ("filename.xlsx") działa, ale tylko jeśli read_only = False. Idealnym rozwiązaniem byłoby jednak zamknięcie pliku i pozostanie w trybie tylko do odczytu. Wygląda na to, że jest to błąd z openpyxl, ponieważ powinien zamknąć plik po zakończeniu load_workbook.

+0

próbowałeś 'OESwb.save()'? – Jeremy

+0

To nie jest błąd. W trybie tylko do odczytu plik obsługi musi być otwarty. Wszelkie zmiany w pliku nie zostałyby zauważone przez openpyxl, więc nie ma sensu próbować edytować pliku w Excelu podczas czytania go za pomocą openpyxl. –

+1

Nie rozumiem, dlaczego obsługa plików musi być otwarta w trybie tylko do odczytu? Nie chodzi o to, że chcę przeczytać zmiany w pliku po jego przeczytaniu, chcę odczytać plik jako tylko do odczytu, a następnie móc go edytować, aby inne procesy mogły odczytać zmiany. Niezależnie od tego, zmodyfikowałem swój kod, aby usunąć tylko do odczytu, używać tylko iteratorów i danych, a następnie zapisać plik, aby go zamknąć. Nie przetestowałem jeszcze, czy plik zostanie zamknięty bez zapisania go, jeśli tylko do odczytu nie jest włączony. – wordsforthewise

Odpowiedz

1

Aby zamknąć, wierzę, trzeba zapisać plik:

OESwb.save('filename.xlsx') 

nadzieję, że to pomaga.

+0

Działa to, jeśli nie jest w trybie tylko do odczytu, ale plik powinien zostać zamknięty mimo to po load_workbook. Otwierając na ten temat problem na bitbucku, może uda mi się go naprawić, jeśli uda mi się go rozwiązać. – wordsforthewise

+0

to nie działa dla mnie. Jestem w trybie odczytu/zapisu, a zapisanie nadal pozostawia plik otwarty. To duży problem dla mnie ... – clg4

+0

@wordsforthewise openpyxl przesyła zawartość z pliku, zamiast ładować go do pamięci naraz, więc nie, może 't close after load_workbook, ponieważ nadal czyta zawartość ze skoroszytu. – sage88

2

Stwierdziłem również, że jest to problem, i myślę, że to dziwne, że skoroszytów nie mają ścisłej metody.

Rozwiązaniem, które wymyśliłem, był menedżer kontekstu, który "zamknął" plik dla mnie, tak że nie zapisywałam nic w moim kodzie za każdym razem, gdy czytałam arkusz kalkulacyjny.

@contextlib.contextmanager 
def load_worksheet_with_close(filename, *args, **kwargs): 
    ''' 
    Open an openpyxl worksheet and automatically close it when finished. 
    ''' 
    wb = openpyxl.load_workbook(filename, *args, **kwargs) 
    yield wb 
    # Create path in temporary directory and write workbook there to force 
    # it to close 
    path = os.path.join(tempfile.gettempdir(), os.path.basename(filename)) 
    wb.save(path) 
    os.remove(path) 

Aby go użyć:

with load_worksheet_with_close('myworkbook.xlsx') as wb: 
    # Do things with workbook 
+0

Może rozważyć połączenie rozwiązania kontekstowego z metodą @ user5859387, aby uniknąć konieczności zapisywania i usuwania! – CodeJockey

0

Można spróbować:

wb = None 

aby zwolnić zasoby i załadować go ponownie tak szybko, jak trzeba to jeszcze raz, w tej samej lub innej zmiennej.

+0

Próbowałem tego, ale nie działał. – lodebari

+1

@lodebari działa tylko wtedy, gdy nie masz innych zmiennych powiązanych z tym skoroszytem w pamięci. Na przykład, jeśli masz = skoroszyt() i b = a, ustawienie a = Brak jest niewystarczające, aby Python automatycznie zbierał śmieci. Musisz również ustawić b = Brak. –

0

Użyj OESwb._archive.close() Spowoduje to zamknięcie dodatkowego uchwytu pliku ZipFile, który był otwarty w trybie 'read_only=True'. Należy pamiętać, że po zamknięciu nie można było odczytać więcej danych z OESwb. Należy również pamiętać, że jest to obejście problemu i można usunąć _archive w przyszłej wersji.

2

Próbowałem wszystkich tych rozwiązań do zamykania pliku xlsx w trybie tylko do odczytu i żaden nie wydaje się wykonywać zadania. I w końcu skończyło się używając pliku w-mem:

with open(xlsx_filename, "rb") as f: 
    in_mem_file = io.BytesIO(f.read()) 

wb = load_workbook(in_mem_file, read_only=True) 

może nawet ładują się szybciej i nie trzeba się martwić o zamknięcie czegokolwiek.

1

Z jakiegoś drakońskiego powodu, stackoverflow pozwoli mi opublikować odpowiedź, ale nie mam wystarczająco dużo "przedstawiciela" do komentowania lub głosowania - więc oto jesteśmy.

Przyjęta odpowiedź wb._archive.close() nie działa dla mnie. Możliwe, że to dlatego, że używam trybu tylko do odczytu. Może działać poprawnie w trybie "normalnym".

bmiller „s odpowiedź jest tylko odpowiedź, że pracował dla mnie, a także:

with open(xlsx_filename, "rb") as f: 
    in_mem_file = io.BytesIO(f.read()) 

wb = load_workbook(in_mem_file, read_only=True) 

I jak powiedział, to jest szybciej przy załadunku open() kontra jedynie przy użyciu tylko do odczytu.

Mój kod roboczych na podstawie odpowiedzi bmiller za:

import os 

xlsx_filename=r'C:/location/of/file.xlsx') 
with open(xlsx_filename, "rb") as f: 
    in_mem_file = io.BytesIO(f.read()) 

wb = openpyxl.load_workbook(in_mem_file, read_only=True) 
+0

może potwierdzić, że to działa również dla mnie, dziękuję – citizen2077