Speicher Fehler mit openpyxl und große Daten zeichnet sich
Habe ich ein Skript geschrieben, das zu Lesen hat viel von excel-Dateien aus einem Ordner (rund 10.000). Dieses Skript lädt die excel-Datei (einige von Ihnen hat mehr als 2000 Zeilen) und liest eine Spalte count die Anzahl der Zeilen (Prüfung und so). Wenn die Anzahl der Zeilen ist nicht gleich einer gegebenen Zahl ist, schreibt er die Warnung im log.
Das problem kommt, wenn das Skript liest mehr als 1000 excel-Dateien. Es ist dann, wenn er wirft, Speicher-Fehler, und ich weiß nicht, wo das problem sein könnte. Vorher das Skript Lesen zwei csv-Datei mit 14.000 Zeilen und speichert Sie in einer Liste. Diese Listen enthalten eine identificator für die excel-Datei und die jeweilige Anzahl der Zeilen. Wenn die Anzahl der Zeilen ist nicht gleich der Anzahl der Zeilen der excel-Datei hat, schreibt er die Warnung. Könnte das problem sein, die Lektüre dieser Listen?
Ich bin mit openpyxl laden Sie die Arbeitsmappen, muss ich schließen Sie vor dem öffnen der nächsten?
Dies ist mein code:
# -*- coding: utf-8 -*-
import os
from openpyxl import Workbook
import glob
import time
import csv
from time import gmtime,strftime
from openpyxl import load_workbook
folder = ''
conditions = 0
a = 0
flight_error = 0
condition_error = 0
typical_flight_error = 0
SP_error = 0
cond_numbers = []
with open('Conditions.csv','rb') as csv_name: # Abre el fichero csv donde estarán las equivalencias
csv_read = csv.reader(csv_name,delimiter='\t')
for reads in csv_read:
cond_numbers.append(reads)
flight_TF = []
with open('vuelo-TF.csv','rb') as vuelo_TF:
csv_read = csv.reader(vuelo_TF,delimiter=';')
for reads in csv_read:
flight_TF.append(reads)
excel_files = glob.glob('*.xlsx')
for excel in excel_files:
print "Leyendo excel: "+excel
wb = load_workbook(excel)
ws = wb.get_sheet_by_name('Control System')
flight = ws.cell('A7').value
typical_flight = ws.cell('B7').value
a = 0
for row in range(6,ws.get_highest_row()):
conditions = conditions + 1
value_flight = int(ws.cell(row=row,column=0).value)
value_TF = ws.cell(row=row,column=1).value
value_SP = int(ws.cell(row=row,column=4).value)
if value_flight == '':
break
if value_flight != flight:
flight_error = 1 # Si no todos los flight numbers dentro del vuelo son iguales
if value_TF != typical_flight:
typical_flight_error = 2 # Si no todos los typical flight dentro del vuelo son iguales
if value_SP != 100:
SP_error = 1
for cond in cond_numbers:
if int(flight) == int(cond[0]):
conds = int(cond[1])
if conds != int(conditions):
condition_error = 1 # Si el número de condiciones no se corresponde con el esperado
for vuelo_TF in flight_TF:
if int(vuelo_TF[0]) == int(flight):
TF = vuelo_TF[1]
if typical_flight != TF:
typical_flight_error = 1 # Si el vuelo no coincide con el respectivo typical flight
if flight_error == 1:
today = datetime.datetime.today()
time = today.strftime(" %Y-%m-%d %H.%M.%S")
log = open('log.txt','aw')
message = time+': Los flight numbers del vuelo '+str(flight)+' no coinciden.\n'
log.write(message)
log.close()
flight_error = 0
if condition_error == 1:
today = datetime.datetime.today()
time = today.strftime(" %Y-%m-%d %H.%M.%S")
log = open('log.txt','aw')
message = time+': El número de condiciones del vuelo '+str(flight)+' no coincide. Condiciones esperadas: '+str(int(conds))+'. Condiciones obtenidas: '+str(int(conditions))+'.\n'
log.write(message)
log.close()
condition_error = 0
if typical_flight_error == 1:
today = datetime.datetime.today()
time = today.strftime(" %Y-%m-%d %H.%M.%S")
log = open('log.txt','aw')
message = time+': El vuelo '+str(flight)+' no coincide con el typical flight. Typical flight respectivo: '+TF+'. Typical flight obtenido: '+typical_flight+'.\n'
log.write(message)
log.close()
typical_flight_error = 0
if typical_flight_error == 2:
today = datetime.datetime.today()
time = today.strftime(" %Y-%m-%d %H.%M.%S")
log = open('log.txt','aw')
message = time+': Los typical flight del vuelo '+str(flight)+' no son todos iguales.\n'
log.write(message)
log.close()
typical_flight_error = 0
if SP_error == 1:
today = datetime.datetime.today()
time = today.strftime(" %Y-%m-%d %H.%M.%S")
log = open('log.txt','aw')
message = time+': Hay algún Step Percentage del vuelo '+str(flight)+' menor que 100.\n'
log.write(message)
log.close()
SP_error = 0
conditions = 0
Den if-Anweisungen die end-sind für die Prüfung und schriftlicher Warnung protokolliert.
Ich verwende windows xp mit 8 gb RAM und intel xeon w3505 (zwei cores, 2,53 GHz).
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die default-Implementierung von openpyxl speichern alle zugegriffen Zellen in den Speicher. Ich schlage vor, Sie verwenden die Optimierte reader (link - https://openpyxl.readthedocs.org/en/latest/optimized.html) statt
Code:-
Beim laden einer Arbeitsmappe übergeben
use_iterators = True
. Dann auf das Blatt und Zellen, wie:Dies reduziert den Speicherbedarf um 5-10%
UPDATE: In der version 2.4.0
use_iterators = True
option entfernt wird. In neueren Versionenopenpyxl.writer.write_only.WriteOnlyWorksheet
wird eingeführt, dumping große Mengen von Daten.Nicht getestet, der code unten nur kopiert aus dem obigen link.
Dank @SdaliM für die Informationen.
Mit den letzten Versionen von openpyxl muss man laden und Lesen riesige Quell-Arbeitsmappe mit
read_only=True
argument, und create /write große Ziel-Arbeitsmappe mitwrite_only=True
- Modus:https://openpyxl.readthedocs.io/en/latest/optimized.html
Als @anuragal sagte
Anderen Weg, um dieses riesige problem mit dem Arbeitsspeicher, während die Schleife wird jede Zelle Teile und herrsche" -. Der Punkt ist, nach dem Lesen genug Zelle, speichern Sie die excel-von
wb.save()
, dann die letzten Werte werden aus dem Speicher entfernt werden.Dieser Ansatz für mich gearbeitet, kopieren von Daten aus einer SQLite-DB in die entsprechenden Arbeitsblätter für jede Tabelle Einige Tische haben > als 250.000 Zeilen und ich lief in einem Speicher-Fehler aus OpenPyXL. Der trick ist, um inkrementell speichern alle 100K Zeilen und dann die Arbeitsmappe erneut öffnen - dies scheint die Speichernutzung zu verringern. Ich tun etwas sehr ähnlich zu dem, was @sakiM ist dabei oben. Hier ist ein Teil von meinem code, der dies tut: