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