Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP]parsowanie pliku txt, Jak odczytać wybrany zakres linii z pliku txt ?
fiasko
post 2.11.2012, 21:20:17
Post #1





Grupa: Zarejestrowani
Postów: 243
Pomógł: 1
Dołączył: 1.06.2010

Ostrzeżenie: (0%)
-----


Mam plik baza.txt, który waży 45 MB i chcę z niego odczytać 100 linii zawrtości zaczynając odczyt od linii onumerze 10000.

Jakiej funkcji użyć do odczytu i jak czytać ?

Dodam tylko, że file() deklaruje mi tyle pamięci, że nie da się załadować tak dużego pliku do pamięci .
Go to the top of the page
+Quote Post
Spawnm
post 2.11.2012, 21:22:18
Post #2





Grupa: Moderatorzy
Postów: 4 069
Pomógł: 497
Dołączył: 11.05.2007
Skąd: Warszawa




Nie da się od linii o numerze 10000.
Zainteresuj się sqlite na przyszłość.
Go to the top of the page
+Quote Post
abort
post 2.11.2012, 21:33:14
Post #3





Grupa: Zarejestrowani
Postów: 590
Pomógł: 107
Dołączył: 25.10.2011

Ostrzeżenie: (0%)
-----


Możesz to zrobić, ale weź pod uwagę, że jeśli chcesz robić to co chwilę, to będzie to strasznie nieefektywne i dobijające system. Zainteresuj się funkcjami: fopen i fread.
Idea jest prosta:
1. poprzez fopen otwierasz plik w trybie do odczytu
2. w pętli odczytujesz kolejne linie (i nie zapisujesz ich nigdzie!!!), których będzie u Ciebie 9999.
3. Wewnętrzny wskaźnik pliku stoi na linii 10000.
4. Czytasz linię i zachowujesz
5. punkt 4 powtarzasz tak długo, jak długo potrzebujesz
6. Zamykasz plik

Ale fakt faktem, Spawnm ma rację: jakaś baza SQL by się już bardzo przydała, choćby sqlite.
Go to the top of the page
+Quote Post
zegarek84
post 2.11.2012, 21:50:33
Post #4





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


Cytat(Spawnm @ 2.11.2012, 21:22:18 ) *
Nie da się od linii o numerze 10000.
Zainteresuj się sqlite na przyszłość.

wiem, że żartowałeś by nie podać starej funkcji gdzie przy tamtym podejściu też można złe nawyki sobie wyrobić, też jej nie podam choć łatwo jej nazwę będzie wywnioskować co ją się stosuje do uchwytu pliku... po za tym jakoś SQLite też jest moim faworytem...

Z biblioteki SPL klasa
SplFileObject
metody:
SplFileObject::seek(int)
SplFileObject::fgets() | SplFileObject::current()


znajomość i umiejętne zastosowanie tych funkcji pozwala na szybie wrzucenie danych do bazy przy minimalnym zużyciu pamięci... dodatkowo jeśli chodzi o odczyt baaaaardzo dużych plików XML to hasło do google "SAX PHP" - choć mógłbym dać klasę w dokumentacji PHP ale masz też hasło na przykłady - jednak by dobrze wykorzystać ją poprogramuj se paradoksalnie w JavaScript by umiejętnie stosować technikę programowania zdarzeniowego lub w C++ a dokładniej w bibliotece QT

// EDIT
nie odświeżyłem sobie i widzę, że dostałeś linka do tych funkcji ;p
// edit 2
a jednak nie - po staremu to fgets (pobiera linię pliku i przewija wskaźnik dalej - ale skorzystaj z obiektowego podejścia i z biblioteki SPL) itd... za dużo tego dobrego miodziku ;D

Ten post edytował zegarek84 2.11.2012, 21:55:03


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
fiasko
post 2.11.2012, 22:23:00
Post #5





Grupa: Zarejestrowani
Postów: 243
Pomógł: 1
Dołączył: 1.06.2010

Ostrzeżenie: (0%)
-----


wygenerowałem dla testów plik z 1500000 linii kodu.


odczytuję to tak :

<?php
$file = new SplFileObject('baza.txt');
for($i=1000000;$i<=1000200;$i++){
$file->seek($i);
echo $file->current().'<br>';
}


?>
[/php]

i działa za wolno sad.gif

Ten post edytował fiasko 2.11.2012, 22:23:24
Go to the top of the page
+Quote Post
zegarek84
post 2.11.2012, 22:33:03
Post #6





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


przewinięcie do tak dużego pliku gdzie są nie regularne długości wersów trochę potrwa - 1 milion pomijając inne warunki to co najmniej sprawdzenie i zliczenie miliona znaków "\n" co musi minimalnie zająć pół sekundy (plus porównanie innych znaków) - w końcu patrzysz od początku pliku... tą techniką którą Ci wskazałem jesteś w stanie odczytywać baaaardzo duże pliki dosyć wydajnie - całość możesz wrzucić do jakiejkolwiek bazy danych, choćby płaskiej bazy danych jak SQLite gdzie każdy wiersz możesz mieć zindeksowany i dostęp do poszczególnych wierszy będzie szybszy...

ps. przecież interesowały Cię wielkości 100 razy mniejsze ;p - 10000 to nie to samo co milion ;D

Ten post edytował zegarek84 2.11.2012, 22:38:30


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
fiasko
post 2.11.2012, 23:02:55
Post #7





Grupa: Zarejestrowani
Postów: 243
Pomógł: 1
Dołączył: 1.06.2010

Ostrzeżenie: (0%)
-----


interesują mnie jeszcze większe bo będę dostawać pliki z 50 mln linii smile.gif W każdej linii mam jeden obiekt poddany serializacji. Będę odczytywać w CRON po 10000 rekordów na minutę jeszcze inne ciężkie operacje dotyczące tych obiektów.

Na bazie nie będę z tym pracować bo musiałbym pracować na setkach tabel. Tu będzie tak, że przerobiony plik nie będzie mi już potrzebny.

ok

teraz jest idealnie smile.gif
  1. <?php
  2. $file = new SplFileObject('baza.txt');
  3. $file->seek(1000000);
  4. $start = 10;
  5. $ile = $start + 100;
  6.  
  7. for($i=$start;$i<=$ile;$i++){
  8. echo $file->current().'<br>';
  9. $file->next();
  10. }
  11.  
  12.  
  13. ?>


Ten post edytował fiasko 2.11.2012, 23:03:18
Go to the top of the page
+Quote Post
zegarek84
post 2.11.2012, 23:06:14
Post #8





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


Cytat(fiasko @ 2.11.2012, 22:54:30 ) *
interesują mnie jeszcze większe bo będę dostawać pliki z 50 mln linii smile.gif W każdej linii mam jeden obiekt poddany serializacji. Będę odczytywać w CRON po 10000 rekordów na minutę jeszcze inne ciężkie operacje dotyczące tych obiektów.

Na bazie nie będę z tym pracować bo musiałbym pracować na setkach tabel. Tu będzie tak, że przerobiony plik nie będzie mi już potrzebny.

gdyby długość linii była stała można by to zrobić optymalniej, ale pomińmy tą kwestię (w końcu nie będziemy tu implementować bazy danych ;p)... wspomniałeś, że to co obrobione to nie potrzebne i będziesz miał to na zasadzie kolejki... więc by następnym razem nie przewijać pliku tak daleko przy nieregularnych liniach to nie mógłbyś tą techniką pociąć ten plik na wiele mniejszych po te 10000 linii kodu?? i w myśl zasady 100|1000 plików na katalog (nie pamiętam jaka liczba była optymalna) - więc musiałbyś sobie jakiś system nazewnictwa wystosować - obrobisz to to to usuwasz i tniesz następny plik... a przy kolejnej kolejce nie musisz tak daleko przewijać - to tylko propozycja...

//edit
czyli fseek przewijało za każdym razem od początku pliku - zaczynałem pisać w poprzednim poście, byś korzystał z fseek raz a potem z fgets (miks current i next ^^) ale zaraz to skasowałem bo zdawało mi się to niedorzeczne ;p - a już jakiś czas nie miałem potrzeby obróbki duuuużych plików ;p

Ten post edytował zegarek84 2.11.2012, 23:12:15


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
Crozin
post 2.11.2012, 23:30:26
Post #9





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Wygląda na to, że masz do obrobienia duży plik i z jakiegoś powodu uznałeś, że lepszym rozwiązaniem będzie robienie tego "po trochu, co chwilę" (cron) zamiast za jednym razem - dlaczego?
Go to the top of the page
+Quote Post
zegarek84
post 2.11.2012, 23:39:04
Post #10





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


w sumie też dobre pytanie, chyba, że nie ma dostępu ko konsoli ;] - w konsoli ma się znacznie mniejsze ograniczenia, a najważniejsze to to czasowe ;]... wspomniał o obiektach zserializowanych - po drodze może mieć jeszcze multum operacji... raz miałem też nietypowy problem oprócz tego, iż pliki XML były duże, ale nie mogłem mieć pewności, czy dane w bazie znajdują się, no i po swojemu musiałem implementować "iloraz"|"iloczyn" na bazie - już tych "fachowych" określeń|nazw nie jestem pewien ;p... w każdym bądź razie techniki programowania zdarzeniowego to potężne narzędzie optymalizacyjne w dowolnym języku ;D

Ten post edytował zegarek84 2.11.2012, 23:40:07


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
fiasko
post 3.11.2012, 00:43:53
Post #11





Grupa: Zarejestrowani
Postów: 243
Pomógł: 1
Dołączył: 1.06.2010

Ostrzeżenie: (0%)
-----


Będę wykonywać operacje na obiektach, które w ścisłej kolejności zostały wygenerowane do pliku. Obiektami są dane przefiltrowane pod różnym kontem. Każdy taki plik stanowi unikalną kolejkę zadań na której pracuje moja aplikacja.

Zwyczaje musiałem wygenerować kolejkę zadań według której pracują procesy CRON.

Wcześniej pracowałem na bazie i nie byłem wstanie zapisać 5 mln rekordów zanim nie przekroczę limitu czasu serwera na wykonanie skryptu.

Wpadłem więc na pomysł aby agregować te dane w zmiennej i zapisać na koniec do jednego pliku. W sumie mógłbym trzymać w bazie tego typu rzeczy, ale za jakiś czas nie wyobrażałbym sobie wielkości bazy smile.gif

Dzięki temu teraz będę mógł szybko pracować na tych obiektach zgodnie z oczekiwaną kolejnością.
Go to the top of the page
+Quote Post
zegarek84
post 3.11.2012, 01:11:07
Post #12





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


Cytat(fiasko @ 3.11.2012, 00:43:53 ) *
Wcześniej pracowałem na bazie i nie byłem wstanie zapisać 5 mln rekordów zanim nie przekroczę limitu czasu serwera na wykonanie skryptu.

jeśli obrabiasz duże ilości danych to nie prościej wykupić jakiś najtańszy VPS byś miał dostęp do PHP spod konsoli?? nie miałbyś takich limitów czasowych - ale fakt, przynajmniej spojrzałeś innym okiem by zrobić to optymalniej... lub te dane mógłbyś obrabiać na lokalnej maszynie a dopiero potem wyniki przesłać na serwer...
Cytat(fiasko @ 3.11.2012, 00:43:53 ) *
Wpadłem więc na pomysł aby agregować te dane w zmiennej i zapisać na koniec do jednego pliku.

co to znaczy, że agregujesz dane w zmiennej?? czy te dane są przyrostowe i zwiększają tą zmienną z upływem czasu?? tzn. potrzebna pamięć skryptu rośnie stale zapewne... czemu danych nie zapisujesz na bieżąco do pliku linia po linii?? SplFileObject::fwrite, a plik otwórz z modyfikatorem "a"...

swoją drogą trochę interesowałem się strumieniowymi bazami danych (nastawionymi na określone zdarzenia) i gdyby nie brak czasu to miałem pisać prostą implementację na swoje potrzeby bez implementacji języka SQL, z tym, że to raczej Cię nie interesuje gdyż to już programowanie sieciowe ;]


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
Crozin
post 3.11.2012, 02:47:29
Post #13





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


A nie możesz po prostu wyłączyć limitu czasu wykonywania skryptu? (patrz: set_time_limit)

Nie mniej jednak, jeżeli już przetwarzasz ten plik w porcjach przy użyciu CRON-a, możesz w jakimś pomocniczym pliku zapisać sobie informację o tym ile już rekordów (zserializowanych obiektów) przetworzyłeś oraz ile bajtów zajmowały one w pliku. Dzięki temu przy ponownym uruchomieniu skryptu będziesz mógł natychmiast przeskoczyć w odpowiednie miejsce (fseek/SplFileObject::fseek).

Ten post edytował Crozin 3.11.2012, 02:47:52
Go to the top of the page
+Quote Post
zegarek84
post 3.11.2012, 12:31:49
Post #14





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


co racja to racja, będzie szybciej, ale liczyć nie musi
SplFileObject::ftell - Returns the position of the file pointer which represents the current offset in the file stream.
analogiczna funkcja do proceduralnego uchwytu ftell


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 25.04.2025 - 05:35