Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1540to1544
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Speicherfehler nach 65.527 Zugriffen auf Clipboard

Speicherfehler nach 65.527 Zugriffen auf Clipboard
22.02.2017 20:13:20
Zwenn
Hallo zusammen,
zur Abwechslung habe ich mal ein Problem, bei dem ich nicht weiter komme.
Ich habe ein Makro geschrieben, um Hashwerte zu Dateien zu berechnen und zusammen mit ein paar anderen Bezugswerten in eine Tabelle zu schreiben. Das Ganze wird anschließend in eine Datenbank importiert. Insgesamt handelt es sich bei mir um 3 Mio. Bilder, die gehasht werden müssen, die zu 1,5 Mio. Datensätzen gehören. Die Datensätze sind auf 11 Tabellen aufgeteilt, von März 2016 bis Januar 2017 sind alle Datensätze für einen Monat jeweils in einer Tabelle, in einer eignen Arbeitsmappe gespeichert.
Die Berechnung des Hashwertes erfolgt über das Konsoplenprogramm ReHash
Download: http://rehash.sourceforge.net/
Anleitung: http://rehash.sourceforge.net/rehash.html
Ich rufe ReHash auf der Konsole (cmd) über den Windows Scripting Host auf. Das mache ich, weil man dem Aufruf über den WSH einen Parameter mitgeben kann, damit das Makro wartet, bis der Aufruf beendet wurde. So spare ich mir das Brimborium die Process ID überwachen zu müssen.
Die Ausgabe von ReHash leite ich mit | Clip an die Windows Zwischenablage um. Auf die Zwischenablage greife ich dann mit der Funktion von Peter Haserodt aus dem Jahr 2004 zu:

Public Function HoleTextVonZwischenablage() As String
' Benötigt einen Verweis auf die Microsoft Forms 2.0 Objektlibrary
' (Sollten Sie diese nicht so einfach finden, einfach eine Userform
' einfügen und dann wieder entfernen)
' Peter Haserodt 2004
'Quelle: http://www.online- _
excel.de/excel/singsel_vba.php?f=28
Dim oData As New DataObject
'Fehlerbehandlung für meinen Anwendungsfall nicht notwendig
'On Error Resume Next ' Brutal um falsche Formate abzuwürgen, gibt dann einen Leerstring
oData.GetFromClipboard
HoleTextVonZwischenablage = oData.GetText
'Test, weil nach 65.527 Zugriffen auf diese Funktion ein Speicherfehler kommt, die sich  _
immer auf den Zugriff auf das Clipboard bezieht
Set oData = Nothing
End Function
Der Plan ist natürlich alle Bilder, die zu einer Arbeitsmappe gehören, in einem Rutsch zu hashen. Aber nach exakt 65.527 berechneten Bildern, bricht das Makro mit folgender Fehlermeldung ab:
Userbild
Es passiert immer bei dieser Anzahl, ich habe bereits 5 Monatstabellen so durchgerechnet. Nur muss ich immer manuell eingreifen und Excel nach der Fehlermeldung neu starten. Bis zu dem Fehler vergehen ziemlich genau 3 Stunden, die das Makro klaglos seinen Dienst verrichtet. (Die Zeit kommt zusammen, weil die Bilder noch auf der Platte verschoben werden und zusätzlich noch Tests auf das Vorhandensein von PDF Dateien, mit anschließender Verschiebung auf der Platte bei erfolgreicher Prüfung, durchgeführt werden.)
Ich dachte zunächst, es handelt sich um ein Problem mit dem Konstrukt, cmd innerhalb des WSH aufzurufen und das ganze noch an clip.exe zu koppeln. Deshalb habe ich nach je 1.000 Schleifendurchläufen auf alle externen Programme, die das Makro verwendet, taskkill angewendet. Das brachte aber gar nix. Dann habe ich das DataObject in der Funktion oben mit set nothing bei jedem Aufruf zusätzlich zurückgesetzt. Auch das hat nix gebracht.
Der Arbeitsspeicher ist übrigens nicht mal ansatzweise voll. Zwar verwende ich Excel nur in der 32 Bit Version, aber die 65.527 sehen ja sehr nach einem 16 Bit Adressraum aus. Das kann natürlich auch Zufall sein, weil es ja nicht genau 65.536 sind.
Ich habe im Internet nix zu diesem Problem gefunden. Hat jemand von Euch eine Idee? Vielleicht durch einen anderen Zugriff auf die Ausgabe von ReHash. Vielleicht kann auch jemand etwas zu dem Speicherfehler selbst sagen, bzw. woher er kommt.
Viele Grüße,
Zwenn

8
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Speicherfehler nach 65.527 Zugriffen auf Clipboard
23.02.2017 16:08:02
Michael
Hallo Zwenn,
hast Du mal versucht, die Ausgabe direkt aus der Shell abzugreifen?
Hier eine kleine "Testumgebung": https://www.herber.de/bbs/user/111705.xlsm
Ich hatte leider nicht recht aufgepaßt (d.h. eine Abbruchmöglichkeit bzw. Anzeige alle 100 oder so eingebaut) und meinen Rechner eine gute halbe Stunde mit 70.000 Aufrufen lahmgelegt, aber es läuft durch!
Schöne Grüße,
Michael
Nachtrag
23.02.2017 16:31:47
Michael
also, mit CMD geht's auch mit Pipe (>):
Sub WShellTest4()
Dim objShell As Object
Dim strResult$, strExec$, max$
Dim a, i&, j&, si$
Dim t0 As Single
t0 = Timer
Set objShell = CreateObject("WScript.Shell")
strExec = "cmd /C " & ThisWorkbook.Path & "\WShellIO.exe Var1 Var2 Var3 Var(n)_"
For i = 1 To bis
si = CStr(i)
'    max = strExec & si & " >" & si & ".txt" ' eine Datei pro Aufruf, aber wozu?
max = strExec & si & " >mein.txt"   ' einlesen und wegschreiben...
Debug.Print max
objShell.Run max, 0, True
'  MsgBox objExec.StdOut.Readall
'    o(i) = objExec.StdOut.Readall
Next
Set objShell = Nothing
MsgBox bis & " in " & (Timer - t0) * 1000 & " ms."
End Sub

Das Dumme ist halt (nach meinem Kenntnisstand), daß .run die StdOut nicht zurückgeben kann, .exec aber schon. Verblüffenderweise ist zeilenweises Einlesen (Sub xxx1) schneller als das Abgreifen von .readall (Sub xxx2).
Ätzend bei .exec ist wiederum, daß man die "Fenstertechnik" nicht beeinflussen kann.
Die obige .run-Version schreibt in eine Textdatei: das ist sicher langsamer als die Zwischenablage, die sollte aber wiederum langsamer sein als .exec mit (aus Sub WShellTest())
  For i = 1 To bis
Set objExec = objShell.Exec(strExec & i)
j = 0
While (Not objExec.StdOut.AtEndOfStream)
j = j + 1
o(i & ":" & j) = objExec.StdOut.ReadLine()
Wend
Next

Ohnehin ist sicher alles weniger aufwendig als Deine sonstigen Kopieraktionen...
Na dann, viel Spaß beim Basteln.
Gruß,
M.
Anzeige
AW: Nachtrag
28.02.2017 16:31:39
Zwenn
Hallo Michael,
nachdem der Beitrag nun schon fast aus der Liste gerutscht ist, möchte ich es nicht versäumen mich noch für Deinen Lösungsansatz zu bedanken. Leider hatte ich noch keine Gelegenheit mich näher damit zu beschäftigen, werde das aber auf jeden Fall noch machen, weil ich diesem "Mysterium" gerne auf die Spur kommen will.
Noch als kurzes Update für Dich:
Das Fernstudium geht im April ins zweite Semster. Es ist sehr anstrengend und frisst erwartungsgemäß sehr viel Zeit. Ich kann es aber trotzdem empfehlen, wenn man ernsthaft vor hat sich noch weiter zu entwickeln oder einfach neugierig auf ein Fach ist. Ich habe mich jedenfalls bei erster Gelegenheit für das zweite Semster zurück gemeldet und die Kurse Datenstrukturen und Einführung in die OOP mit Java belegt. Ob ich OOP schaffe weiß ich noch nicht, weil auch Mathe noch auf dem Plan steht. Wenn nicht, ist das aber nicht schlimm. Belegte Kurse zahlt man als Wiederholer nicht noch einmal, solange sie nicht grundlegend überarbeitet werden.
Viele Grüße,
Zwenn
Anzeige
AW: Nachtrag
28.02.2017 16:42:43
Michael
Hallo Zwenn
freut mich, daß Du Dich noch gemeldet hast.
Naja, Lust hätte ich schon, aber im Moment steht mir zu viel Zeug "vor der Nase" für ein Studium...
Du bist ja ein heller Kopf, so daß Du mit meiner "Testumgebung" zurecht kommen wirst (interessant ist der Button1, mit dem ich die 70.000 getestet habe). Falls nicht, kannst mir auch gerne mal ne mail senden...
Frohes Schaffen & schöne Grüße,
Michael
bitte noch lesen
28.02.2017 17:41:39
Michael
Hi Zwenn,
im Prinzip ist Antons Vorschlag ja einer derer, der in der "Testumgebung" läuft.
Aber der Hinweis ist mir gestern schon eingefallen:
In der ReHash-Doku steht ja:
If you would like to hash all jpg and jpe files in 'C:\web\', use this:
rehash C:\web\*.jp[eg]

D.h., Du kannst "mindestens" verzeichnisweise arbeiten, wenn nicht mit einer Dateiliste (habe nicht weiter gelesen, aber z.B. 7zip kann eine Textdatei mit Dateinamen verarbeiten, deren Namen man als Parameter übergibt).
Das hätte den Vorteil, daß die Aufrufe von rehash minimiert werden (d.h. Du erhältst mit 1 Aufruf eine größere Anzahl von Zeilen in STDOUT). Alle weiteren Aktionen solltest Du ja auch von einem Array aus getrennt von rehash erledigen können (also in einer weiteren Schleife).
Gruß,
M.
Anzeige
AW: bitte noch lesen
28.02.2017 19:15:15
Zwenn
Hallo Michael,
grundsätzlich hast Du recht und ich weiß, dass ReHash mehrere Dateien in einem Rutsch bearbeiten kann. Diese Möglichkeit habe ich aber für meine Problemstellung bei der Makro-Planung ausgeschlossen, weil es sowohl Bilder gibt, die nicht benötigt werden, wie auch Bilder, die da sein sollten, es aber nicht sind. Um das abzufangen, müsste ich also mein Makro anders konzipieren, als ich es jetzt gemacht habe.
Zur Erklärung:
Die Bilder stammen von einer französischen Handelsplattform und gehören zu Angeboten, die ich mit einem anderen Makro seit einem Jahr auslese. Zu jedem Angebot wird ein Datensatz in einer Excel-Tabelle gebildet. Unter anderem steht in einer Spalte, wieviele Bilder zu einem Angebot gehören.
Dadurch, dass ich die Bilder selbst abspeichere, kenne ich den genauen Aufbau der Dateinamen und bilde diese Namen mit dem Makro zum Hashen einfach nach. Die Bilder selbst liegen zusammen mit den generierten PDF Dateien zu jedem Angebot in einem Verzeichnis, das mit der AccountID des jeweiligen Verkäufers benamt ist. Inzwischen sind es über 540 Tsd. Verzeichnisse, von denen manche mehr als 1.000 Dateien enthalten, andere wiederum nur 2 Dateien.
Durch unvorhersehbare Fehler beim Auslesen der Handelsplattform, kommt es immer wieder dazu, dass Angebote doppelt ausgelesen werden und deshalb auch Bilder doppelt gespeichert werden. Es kann auf der anderen Seite auch vorkommen, dass Bilder leider nicht gespeichert werden. Diese Fehler im Datenbestand sind z.B. zurückzuführen auf Wartungsarbeiten der Handelsplattform und damit verbunden eine schlechte Erreichbarkeit der Angebote oder auch Internet-Verbindungsprobleme von unserer Seite aus. Das Auslesemakro läuft durch, macht eine halbe Stunde Pause und startet den Auslesevorgang dann von vorne. Es hat etwas gedauert, bis das stabil lief.
Das Ganze will ich bei Gelegenheit mal auf Python und dem direkten Speichern in eine Datenbank umstellen. Aber "bei Gelegenheit" ergibt sich im Moment leider nicht. Excel ist für die anfallenden Datenmengen und die damit verbundene Auswertung zum Teil überfordert. Auf der anderen Seite aber im Moment natürlich sehr bequem. Python, weil es hervorragende Bibliotheken zur Datenanalyse "mitbringt". Aber das nur am Rande.
Du kannst anhand dieser etwas abstrakten Erklärung vielleicht nachvollziehen, dass eine Dateiliste wenig Sinn macht. Vielmehr nehme ich mir einen Datensatz vor und lasse eine For Schleife mit sovielen Durchläufen laufen, wie das Angebot Bilder haben soll. Matcht ein Name, wird der Hash berechnet, matcht er nicht, wird das nicht vorhandene Bild übersprungen.
Wie ich schon erwähnte, werden alle Bilder, die gehasht werden, auch in eine neue Verzeichnisstruktur verschoben. Dadurch bleiben die doppelt ausgelesenen Bilder in der alten Verzeichnisstruktur zurück und ich habe am Ende einen sauberen Datenbestand. Auch die PDF Dateien werden auf vorhandensein geprüft und in die neue Struktur verschoben. Für beide Dateitypen schreibe ich zu jedem Angebot in die Tabelle, ob sie vorhanden waren oder nicht. Auf diese Weise habe ich noch eine kleine Qualitätskontrolle für das Auslesemakro geschaffen.
Im Auslesemakro lief ursprünglich mal eine Funktion mit, die für alle Bilder direkt einen MD5 Hash berechnet hat. Allerdings hat diese leider oft einen Überlauf-Fehler erzeugt und das Auslesemakro unterbrochen. Deshalb habe ich die Berechnung der Hashwerte wieder deaktiviert und "schlage mich nun damit rum", Hashwerte für alle 3. Mio Bilder nachträglich zu berechnen. (Sind inzwischen alle berechnet)
Ich brauche die, um festzustellen, ob ein Bild von mehr als einem Account verwendet wurde. Ist das der Fall und es ist ein selbst aufgenommenes Bild, verwendet jemand mehr als einen Account zum Verkaufen. Ist auf solchen Bildern Neuware abgebildet, könnte es sich um Diebstahlware handeln, die in größeren Mengen verkauft wird, wobei die Menge aber über mehrere Accounts verschleiert werden soll.
Durch die Dauer des Auslesens und damit dem Vorliegen aller relevanten Angebote, kann eine Aussage darüber getroffen werden, ob man da mal Kontakt aufnimmt und das Ganze ggf. bei der französischen Polizei zur Anzeige bringt. Das entscheidet aber am Ende unser Kunde.
Das ist ein Analysevektor von mehreren, die wir zum Aufspüren von Produkt- und Markenpiraterie sowie Hehlerware auf Handelsplattformen im Internet verwenden. Es gibt natürlich auch sehr viel einfachere, bzw. weniger aufwändige.
Viele Grüße,
Zwenn
Anzeige
Speicherfehler nach 65.527 Zugriffen auf Clipboard
23.02.2017 16:09:04
Anton
Hallo Zwenn,
vielleicht kannst du die Ausgabe von ReHash direkt auslesen, etwa so(ungetestet):
  Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec("rehash ") 'anpassen
msgbox objExec.StdOut.ReadAll
mfg Anton
AW: Speicherfehler nach 65.527 Zugriffen auf Clipboard
28.02.2017 16:34:17
Zwenn
Hallo Anton,
auch vielen Dank an Dich und Deinen vorgeschlagenen Lösungsansatz. Der sieht interessant aus und ich werde mal versuchen mit ihm zu arbeiten. Bisher fehlte mir leider die Zeit, mich nochmal ernsthaft mit meinem kleinen Problem zu beschäftigen.
Viele Grüße,
Zwenn

Links zu Excel-Dialogen

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige