Sehr große Datei in Teilschritten auslesen

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:
Code:
unset TEMPO
ZEILENNUM=1
for ((p=1; $p

Hallo,

Probier mal was in der Form

cat $yourfile; while read i; do (tue was mit $i hier); done

Das ganze hilft natuerlich nichts, wenn du trotzdem noch jede Zeile in einer Variable speichern willst - du solltest das ganze sofort weiterverarbeiten.

Gruesse,
Moritz

OT, nur als Anregung.
Hallo!

Ich weiß, es ist nicht gefragt. Es ist nur als Anregung gedacht, weil ich da was von extremen Laufzeiten las und ich Shell-Skripte immer unglaublich kryptisch finde (allerdings vielleicht nur mein Problem).

Das folgende Python2-Script liest alle Zeilen ein und teilt sie dann in 1000er-Blöcke ein.

fi = open("ttt.csv") 
lines = fi.readlines() # 200.000 Zeilen einlesen
fi.close()

print lines[111111] # Testausgabe: irgendein Element

# 1000er-Bloecke erzeugen
i=0
while(1):
 part = lines[i:i+1000] # 1000 Zeilen aus zeilen in part kopieren
 if part == []: break # da war nichts mehr, also fertig
 # hier jetzt was Sinnvolles damit den 1000 Zeilen machen
 print part[0],part[-1] # Testausgabe: 1. und letzte Zeile des Blocks
 i += 1000

Dauer: keine Sekunde. Gut, der eigentliche Datenbankimport wird der Flaschenhals sein. Aber für viele DBs gibt es ja Python2-Lösungen.

Fortranner

Hallo tibrandt,

Ich habe eine sehr große Datei mit „über“ 100000 Zeilen. Die
Daten muss ich Zeilenweise auslesen und in eine DB einlesen.

Ich möchte die Lösung von Moritz noch etwas ausbauen und vorschlagen, die Zeile schon beim einlesen aufzuspalten, etwa so:

IFS=':' # Feldtrenner nach Bedarf
while read -a FELD; do
 echo "'${FELD[2]}'" # mach irgendwas mit den einzelnen Elementen
done 

lässt sich auch in eine Funktion auslagern:



    function tu\_was()
    {
    local IFS=':'
    set -- $\* # liest die ganze als Parameter übergebene Zeile neu ein und splittet sie auf
    # jetzt die Verarbeitung, z.B. 
     [$# -eq X] ... # tatsächlich die geforderten X Variablen in der Zeile?
     ORT=$4 # Feld-Nr. 4 dem Ort zuteilen, usw. ...
    }



Allerdings möchte ich auch Fortranner zustimmen. Da es sich wohl um eine CSV-Datei handelt, würde ich eine passende Erweiterung dafür nehmen. Da gibt es eigentlich für jede Skriptsprache eine CSV-Erweiterung, die die Datei parst und passend aufbereitet zum Einpflegen in die (MySQL?)-DB bereitstellt.
Diese Lösungen sind in der Regel schneller als ein handgestricktes bash-Skript und trotzdem sehr transparent.

Viele Grüße
Marvin

Noch ne Anregung
Hi,
wenn du es denn unbedingt mit der Bash machen willst, könntest du die Datei auch vorher in hanlichere Portionen (Teildateien) zerlgen, Genau dfür gibt es ja das split-Kommando:

SPLIT(1) User Commands SPLIT(1)

NAME
 split - split a file into pieces

SYNOPSIS
 split [OPTION]... [INPUT [PREFIX]]

DESCRIPTION
 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
 size is 1000 lines, and default PREFIX is `x'. With no INPUT, or when
 INPUT is -, read standard input.

 Mandatory arguments to long options are mandatory for short options
 too.

 -a, --suffix-length=N
 use suffixes of length N (default 2)

 -b, --bytes=SIZE
 put SIZE bytes per output file

 -C, --line-bytes=SIZE
 put at most SIZE bytes of lines per output file

 -d, --numeric-suffixes
 use numeric suffixes instead of alphabetic

 -l, --lines=NUMBER
 put NUMBER lines per output file

 --verbose
 print a diagnostic just before each output file is opened

 --help display this help and exit

 --version
 output version information and exit

 SIZE may be (or may be an integer optionally followed by) one of fol‐
 lowing: KB 1000, K 1024, MB 1000\*1000, M 1024\*1024, and so on for G, T,
 P, E, Z, Y.

Das könnte dann den Vorteil haben, dass du einen Wiederaufsetzpunkt hast, wenn die DB nach dem 53000 Insert sich über fehlenden Platz o.ä. beschwert und abbricht… (Naja, 100.000 ist aber auch nicht wirklich viel)

gruss
bernhard

Danke, „split“ war die Lösung.

Gruß
tibrandt