1GB Text Datei auslesen

03/16/2015 09:49 Lee Ki-Hwan#1
Hallo,
ich versuche nun seid knapp ner Woche eine *.txt Datei auszulesen die größer als 1GB ist. (ca. 1,2GB)

Ich habe ziemlich viel gegoogelt und verstehe auch natürlich woran es scheitert, es ist eine Log datei und die Lese ich ein, line by line, und wenn man halt 1000 von String objecten hat, dann füllt das eben den Speicher und es kommt zur OutOfMemory exception.

Nun gibt es einen weg wie ich diese Datei einlesen kann?
- Ich muss alle Strings in eine ArrayList<String> einfügen damit man sich die Logs im Programm auch ansehen kann .

Ich habe schon ziemlich vieles probiert, allerdings kommt mir nicht in den Sinn wie ich diese Daten verarbeiten kann.

MfG B.I.G
03/16/2015 11:27 dowhile#2
Du kannst die maximale Größe vom Heap erhöhen (siehe z.B. [Only registered and activated users can see links. Click Here To Register...] ).
Besser ist es aber, wenn du einfach nicht die gesamte Datei auf einmal einliest. Möchten sich deine Benutzer wirklich 1 GB Logs anschauen? Das klingt nach ziemlich viel - sicher, dass Logs von vor einer Woche noch interessant sind?
03/16/2015 11:28 snow#3
Klingt so als müsstest du den Heap vergrößern, der einfachste Weg dürfte über die Argumente für die JVM sein: [Only registered and activated users can see links. Click Here To Register...]

e: zu spät
03/16/2015 12:03 Lee Ki-Hwan#4
Ja das ist ein Request-Log, und die Kunden möchten sich eben angucken was innerhalb 1 Woche verkauft wurde, welcher Mitarbeiter eingeloggt war zu der Zeit und etliches zeug mehr..

Muss man dann nicht den Heap auf jedem PC erhöhen damit meine Anwendung dann läuft?
03/16/2015 13:07 dowhile#5
Ja, das muss man. Du kannst den Benutzer aber nicht direkt deine jar starten lassen, sondern stattdessen irgendeine Starter-Datei mitliefern, die dann Java mit den richtigen Parametern startet.
Hast du schon überlegt bei so vielen Daten eine Datenbank anstatt einer Logdatei zu nutzen? Das wäre auch eine Möglichkeit.
03/16/2015 13:47 Lee Ki-Hwan#6
Quote:
Originally Posted by dowhile View Post
Ja, das muss man. Du kannst den Benutzer aber nicht direkt deine jar starten lassen, sondern stattdessen irgendeine Starter-Datei mitliefern, die dann Java mit den richtigen Parametern startet.
Hast du schon überlegt bei so vielen Daten eine Datenbank anstatt einer Logdatei zu nutzen? Das wäre auch eine Möglichkeit.
Ja, das hat mir eben auch einer Empfohlen bei der Arbeit, allerdings muss dies Local sein und ohne Externe tools verlaufen, bin echt am verzweifeln wie ich das Lösen soll, hätte nicht gedacht das ich bei quasi so einer kleinigkeit an meine grenzen stöße, lol.

€: Zu der DB, ich muss ja den Request-Log irgendwie in eine Datenbank kriegen und das am besten auch per Programm, sonst sehe ich da auch wieder schwarz :p .
03/16/2015 14:05 dowhile#7
Quote:
Originally Posted by The Notorious B.I.G View Post
Ja, das hat mir eben auch einer Empfohlen bei der Arbeit, allerdings muss dies Local sein und ohne Externe tools verlaufen, bin echt am verzweifeln wie ich das Lösen soll, hätte nicht gedacht das ich bei quasi so einer kleinigkeit an meine grenzen stöße, lol.

€: Zu der DB, ich muss ja den Request-Log irgendwie in eine Datenbank kriegen und das am besten auch per Programm, sonst sehe ich da auch wieder schwarz :p .
Es gibt Datenbanken, für die du keine externe Programme brauchst (also nur eine Library einbinden musst). Auf Android nutzt man zum Beispiel sqlite, viele Java Anwendungen nutzen wohl [Only registered and activated users can see links. Click Here To Register...] (das habe ich noch nie verwendet).
Dann müsstest du die Log Datei bei Änderungen parsen (zum Beispiel mit regulären Ausdrücken, wenn die Logs einfach genug aufgebaut sind) und das neu hinzugekommene in die DB aufnehmen.
03/16/2015 15:19 _Roman_#8
Also SQLite kann ich auch empfehlen, vor kurzem erst benutzt. Brauchst dafür lediglich die Library (in meinem Fall Qt) und dann kannst du bequem Befehle wie "SELECT * FROM table" etc. aus dem Programm ausführen.

Wie läuft das denn bei dir ab, wird der Log einfach nur einmal ausgegeben? Dann könntest du doch immer wieder den gleichen String benutzen, also quasi in einer Schleife die aktuelle Zeile im String speichern, ausgeben und dann so weiter. Bin mir nur nicht sicher, wie lang der Vorgang jedes Mal dauern würde, wenn man ihn wiederholt, da er ja die Datei nochmal auslesen würde. Oder rede ich hier gerade nur Mist :/
03/16/2015 17:26 supercracker13#9
Eine Andere Möglichkeit wäre es die Datei nur Stückweise einzulesen. Also den Teil der gerade benötigt wird. Am besten die große Datei in mehrere kleinere Teilen und somit etwas Übersicht schaffen.

Also ich würde es folgendermaßen lösen:
Beim Programmstart wird die Datei geladen. Wenn sie eine bestimme Größe überschreitet (zb 100 MB) wird sie eingeteilt, das eine Datei maximal 100MB hat. Man kann sich ja dann einfach den ersten und letzten Log von der Datei speichern und demnach das ganze anzeigen lassen. Damit kann man schneller etwas suchen und man muss keine 1,2 GB in den Arbeitsspeicher laden :D
03/17/2015 09:28 Lee Ki-Hwan#10
Der Log wird ausgelesen und es wird in eine Listview gepackt. (IP - TIME - USER).
Ich habe mehrere Filter gemacht also Datum Filter, IP Filter, User Filter ect. pp.
Aber am Anfang wird eben der ganze Log angezeigt bzw. ausgelesen.
Einlesen -> ArrayList.
Und bei der Suchfunktion wird noch eine ArrayList angelegt die, dann das zu suchende beinhaltet..
Komplizierte scheissem aber werde mich heute mit SQLITE befassen, danke für die Zahlreichen antworten!
03/17/2015 15:12 MrSm!th#11
Quote:
Originally Posted by The Notorious B.I.G View Post
Der Log wird ausgelesen und es wird in eine Listview gepackt. (IP - TIME - USER).
Ich habe mehrere Filter gemacht also Datum Filter, IP Filter, User Filter ect. pp.
Aber am Anfang wird eben der ganze Log angezeigt bzw. ausgelesen.
Einlesen -> ArrayList.
Das ist ungeschickt. Such mal nach "lazy loading". Du solltest nur den Teil (und vielleicht ein bisschen mehr, damit das Scrollen flüssig abläuft) laden, der gerade benötigt wird. Der Benutzer kann (und will) sich ohnehin nicht ein ganzes Gigabyte an Logs auf einmal ansehen, sondern wird sie wohl eher nach und nach durchgehen oder nach bestimmten Kriterien filtern. Schon alleine, weil gar nicht alles gleichzeitig auf den Bildschirm passt.
Für eine begrenzte Anzeige die gesamten Daten im Speicher zu halten, ist Speicherverschwendung.
Eine Datenbank würde das Problem auch nicht lösen, wenn du am Ende wieder den gesamten Inhalt in einem Listview anzeigen willst.
03/18/2015 08:26 Lee Ki-Hwan#12
Waren ja erstmal auch nur 22Mb, da gings noch haha.

Eine Log-Zeile sieht wie folgt aus:
Code:
[Sun, 01 Feb 15 00:00:05 +0100]	0	GET	/apidevice/CENSORED/employeelist/key/CENSORED	multiuser=0	{"module":"apidevice","controller":"CENSORED","action":"employeelist","key":"CENSORED	"}
Ich werde mal einfach versuchen nur das was nötig ist zu Laden, dennoch mach ich mir sorgen wenn dies auch zuviel wird.

Das Problem ist ja selbst wenn ich es so machen will nur über einen Filter zu suchen, dann muss ich trotzdem durch die ganze Log-File iterieren um die ergebnisse zu sammeln und der BufferedReader macht das eben nicht mit.
03/18/2015 10:56 NotEnoughForYou#13
Wieso nicht auf Seiten splitten und dann immer nur den speziellen Teil des Files auslesen.
03/18/2015 16:14 Lee Ki-Hwan#14
Ich hab überlegt die Datei in 4 Teile aufzuteilen.
1 GB / 4 = 250mb pro Einheit.

Aber ich weiss nicht genau in was ich speichern soll, ArrayList ist glaub ich nicht so schlau.
Wäre für jede hilfe dankbar :p
Achja und mit der Datenkbank hab ichs auch versucht, wenn ich ein Thread mach blockiert die DB und ohne Thread dauert es viel zu lange, auch so dauerts ewig.
03/18/2015 21:56 supercracker13#15
Also ich würde das nicht alles in ein array speichern, sondern mit ner schleife einfach die große datei abgehen und dann direkt die Ergebnisse in die kleine schreiben. Ein bisschen könnte man buffern (Vlt so 20 Stück, jeden selbst überlassen). Man muss dann einfach die neue datei im Auge behalten und zb nach jedem mal speichern überprüfen ob die Datei die maximale Größe übersteigt. Wenn ja wird ne neue Datei angelegt. Da mann das dann nach jedem speichern macht hat man auch nicht das Problem das ein teil abgeschnitten wird.

Dann zum filtern:
Da kann man dann einfach die kleinen Dateien durchforsten oder direkt die große (aber nicht alles laden, sondern immer nur ein bisschen)
Das filtern Dauer zwar eine zeit, aber bei 1,2gb ist das zu erwarten.