PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Sehr große Datei in großen Schritten auslesen.



tibrandt
23-03-2011, 07:54
Hallo an das Forum,

ich brauche Eure Hilfe, der Groschen will bei mir nicht fallen:
Ich habe eine sehr große Datei mit „über“ 100000 Zeilen. Die Daten muss ich Zeilenweise auslesen und in eine DB einlesen.
Meine Lösung, diese Komplett in ein Array zu pumpen, funktioniert, ist aber wegen der Größe der Datei sehr langsam.
Deshalb möchte ich in 1000 Zeilen schritten das einlesen vornehmen:
Programmablauf soll sein, 1000 Zeilen einlesen, diese verarbeiten um denn die nächsten 1000 einzulesen, bis das Ende der Datei erreicht ist.

Mein Lösungsansatz ohne Schritte beginnt hier:



unset TEMPO
ZEILENNUM=1
for ((p=1; $p<=$(wc -l $import | awk '{print $1}'); p++));do
TEMPO[ZEILENNUM]=$(head -n$p $import | tail -n1)
ZEILENNUM=$(($ZEILENNUM+1))
done

Es ist bestimmt ganz einfach, ich sehe es aber leider nicht.

Danke!

Gruß
Tino Brandt

msi
23-03-2011, 09:11
bash ist für performance der komplett falsche ansatz.

> for ((p=1; $p<=$(wc -l $import | awk '{print $1}'); p++));do


bei jedem schleifendurchlauf wrid immer wieder von neuem die anzahl
der zeilen gelesen, das ist höchst becsheiden

> TEMPO[ZEILENNUM]=$(head -n$p $import | tail -n1)

für jede zeile wird die datei neu aufgemacht uns
für jede zeile muss das progrmam head die ganze datei
bis zu der zeile durchlaufen lassen.

Lösung: KEIN BASH

tibrandt
23-03-2011, 09:27
Hallo,

klar ist die Bash dafür nicht so optimal. Aber wenn ich sehe, was diese an Tonnen Logfiles verarbeitet.

Der Programm-Ansatz sollte nur zeigen, in welche Richtung ich will. Wenn ich Daten einer ganzen Datei einlese, mache ich das über eine Funktion wie z.B.


function transf()
{
ZEILENNUM=1
TRANF=$(cat "$1" | tr "'" ' ')
OLDIFS=$IFS
IFS=$'\n'
for foo in ${TRANF}; do
MEM[ZEILENNUM]=$foo
ZEILENNUM=$(($ZEILENNUM+1))
done
IFS=$OLDIFS
}


über
transf "datei.csv" bekomme ich diese in einem Rutsch eingelesen, das dauert 10 sec.

Aber trotzdem habe ich jetzt noch keinen Lösungsansatz für meine Teilschritte.

Danke!

msi
23-03-2011, 09:43
wie bereits geschrieben, bash ist der falsche ansatz,
verwende eine programmiersprache wie
perl, php, c, python, ...

tibrandt
23-03-2011, 09:50
Wie gesagt, ich verarbeitet mit der bash schon jahrelang Dateien, es funktioniert.

Meine Frage war eigentlich keine Glaubensfrage sondern ich suche eine ganz einfache Hilfe für mein Problem.

Danke, ich versuche mir hilfe bei einem anderem Forum zu suchen!

msi
23-03-2011, 10:18
Wie gesagt, ich verarbeitet mit der bash schon jahrelang Dateien, es funktioniert.

Meine Frage war eigentlich keine Glaubensfrage sondern ich suche eine ganz einfache Hilfe für mein Problem.

Danke, ich versuche mir hilfe bei einem anderem Forum zu suchen!

hier gehts nicht um glauben sondern um performance oder?
du kannst das ganze natürlich schon mit bash umsetzen.
dein ansatz funktioniert ja soweit du kannst folgendes zum füllen verwenden:

hier beispielhalber der code (syntax stimmt wahrsch nicht)

TEMPO[`expr $ZEILENNUM mod 1000`]=$(head -n$p $import | tail -n1)
ZEILENNUM=$(($ZEILENNUM+1))

if [ `expo $ZEILENNUM mod 1000` -eq 0 ]; then
#hier verarbeiten
fi


also vom prinzip her füllts du deine tempo liste immer mit ca 1000 einträgen
und wenn die ca 1000 einträge drinnen sind springt die if schleife an und du kannst an der entspr. stelle die daten verarbeiten.
wenn deine for schleife weiterläuft überschreibt sie die alten inhalte
mod ist modulo, das kennst du ja wahrsch.

die lösung ist trotzdem beschissen lahm, mit ner richtigen sprache, die nicht
wie wild forkt und die datei zick mal öffnet und durchläuft bist du um größenordnungen schneller..

tibrandt
23-03-2011, 10:29
Super danke, so einen Ansatz kann ich gebrauchen.
Ich weis wie lahm das ist, ich muss diese Datei aber nur alle paar Woche mal einlesen. Da wollte ich nicht alles neu mit einer anderen Sprache programmieren. Bei meinen anderen kleinern Dateien funktioniert das auch.
Ich brauche nur diese kleine Anpassung!

Nochmal Danke für die Hilfe.