web-dev-qa-db-fra.com

Openpyxl ne ferme pas le classeur Excel en mode lecture seule

Je veux être capable de lire un fichier Excel en Python, de laisser le script Python actif et de faire autre chose une fois la lecture terminée, et de pouvoir éditer le fichier Excel dans un autre processus entre-temps. J'utilise Python 2.7 et OpenPyxl.

Actuellement, il ressemble à:

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()

Une fois la fonction exécutée, le fichier Excel est toujours verrouillé pour l'accès aux autres processus (il indique l'erreur "Le nom du fichier est en cours d'utilisation. Réessayez plus tard"), même si je ne souhaite plus le lire en Python.

Comment puis-je fermer le fichier à partir de mon script? J'ai essayé OESwb.close () mais cela donne l'erreur "L'objet 'Workbook' n'a pas d'attribut 'close'". J'ai trouvé ce post mais cela ne semble pas aider.

EDIT: Il semble que OESwb.save ('filename.xlsx') fonctionne, mais seulement si read_only = False. Cependant, il serait idéal de pouvoir fermer le fichier tout en restant en mode lecture seule. Il semble que ce soit un bogue avec openpyxl car il devrait fermer le fichier une fois que load_workbook est terminé.

7
wordsforthewise
wb._archive.close()

Fonctionne aussi avec use_iterator.

11
user5859387

Pour certaines raisons draconiennes, stackoverflow me permettra de poster une réponse, mais je n'ai pas assez de «représentants» pour commenter ou voter - nous y sommes donc.

La réponse acceptée de wb._archive.close() n'a pas fonctionné pour moi. C'est peut-être parce que j'utilise le mode lecture seule. Cela peut fonctionner correctement en mode "normal".

La réponse de bmiller est la seule qui a également fonctionné pour moi:

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

wb = load_workbook(in_mem_file, read_only=True)

Et comme il l'a dit, est plus rapide lors du chargement avec open () par rapport à l'utilisation uniquement en lecture seule.

Mon code de travail basé sur la réponse de bmiller:

import openpyxl
import io

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)
7
Patrick Conwell

J'ai essayé toutes ces solutions pour fermer un fichier xlsx en mode lecture seule et aucune ne semble faire l'affaire. J'ai finalement utilisé un fichier in-mem:

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

wb = load_workbook(in_mem_file, read_only=True)

Peut même charger plus rapidement et pas besoin de s'inquiéter de la fermeture de quoi que ce soit.

6
bmiller

Pour vos informations les plus récentes, openpyxl 2.4.4+ fournit la méthode Workbook.close(). Vous trouverez ci-dessous des références.

http://openpyxl.readthedocs.io/fr/stable/changes.html?highlight=close#id86
https://bitbucket.org/openpyxl/openpyxl/issues/673

2
Leonard2

J'ai également trouvé que c'était un problème et pense qu'il est étrange que les classeurs n'aient pas de méthode proche.

La solution que j'ai proposée est un gestionnaire de contexte qui "ferme" le fichier pour que je ne mette pas de sauvegarde inutile dans mon code chaque fois que je lis un tableur.

@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)

Pour l'utiliser:

with load_worksheet_with_close('myworkbook.xlsx') as wb:
    # Do things with workbook
2
Jeffrey Magedanz

Use OESwb._archive.close() Ceci fermera le descripteur de fichier ZipFile supplémentaire qui était maintenu ouvert en mode 'read_only=True'. Sachez qu'après la fermeture vous ne pourrez plus lire les données de OESwb. ceci est une solution de contournement et _archive pourrait être supprimé dans une future version.

1
stovfl

Pour fermer, je pense que vous devez sauvegarder le fichier:

OESwb.save('filename.xlsx')

J'espère que cela t'aides. 

1
jharrison12

Tu peux essayer:

wb = None

pour libérer les ressources et les recharger dès que vous en avez besoin, dans la même variable ou dans une autre.

0
MASR