Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [PHP] Jak odczytać dużego CSV ?
Agape
post 17.12.2015, 11:13:14
Post #1





Grupa: Zarejestrowani
Postów: 384
Pomógł: 13
Dołączył: 16.06.2006

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


Mam plik csv który zajmuje 140 MB, serwer nie daje rady jest "Out of memory" i zastanawiam sie czy nie da sie jakos partiami wczytywac pliku zeby tylko jego czesc byla w pamieci a pozniej kolejna czesc odczytac i przerobic ? Ewentualnie jakis inny sposob, jestem w kropce, juz 2 godziny nad tym siedze ... w komentarzach w manualu znalazlem klase CsvImporter która niby to robi, ale jak odczytam przed tym plikiem jakis jeszcze wczesniej, to tez mam "Out of memory". Moze daloby sie przerobic jakos ta klase zeby nie zajmowala tyle pamieci ?

  1. <?php
  2. class CsvImporter
  3. {
  4. private $fp;
  5. private $parse_header;
  6. private $header;
  7. private $delimiter;
  8. private $length;
  9. //--------------------------------------------------------------------
  10. function __construct($file_name, $parse_header=false, $delimiter="\t", $length=8000)
  11. {
  12. $this->fp = fopen($file_name, "r");
  13. $this->parse_header = $parse_header;
  14. $this->delimiter = $delimiter;
  15. $this->length = $length;
  16. // $this->lines = $lines;
  17.  
  18. if ($this->parse_header)
  19. {
  20. $this->header = fgetcsv($this->fp, $this->length, $this->delimiter);
  21. }
  22.  
  23. }
  24. //--------------------------------------------------------------------
  25. function __destruct()
  26. {
  27. if ($this->fp)
  28. {
  29. fclose($this->fp);
  30. }
  31. }
  32. //--------------------------------------------------------------------
  33. function get($max_lines=0)
  34. {
  35. //if $max_lines is set to 0, then get all the data
  36.  
  37. $data = array();
  38.  
  39. if ($max_lines > 0)
  40. $line_count = 0;
  41. else
  42. $line_count = -1; // so loop limit is ignored
  43.  
  44. while ($line_count < $max_lines && ($row = fgetcsv($this->fp, $this->length, $this->delimiter)) !== FALSE)
  45. {
  46. if ($this->parse_header)
  47. {
  48. foreach ($this->header as $i => $heading_i)
  49. {
  50. $row_new[$heading_i] = $row[$i];
  51. }
  52. $data[] = $row_new;
  53. }
  54. else
  55. {
  56. $data[] = $row;
  57. }
  58.  
  59. if ($max_lines > 0)
  60. $line_count++;
  61. unset($row);
  62. }
  63. return $data;
  64. }
  65. //--------------------------------------------------------------------
  66.  
  67. }
  68. ?>


--------------------
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 11)
kapslokk
post 17.12.2015, 11:19:55
Post #2





Grupa: Zarejestrowani
Postów: 965
Pomógł: 285
Dołączył: 19.06.2015
Skąd: Warszawa

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


http://stackoverflow.com/questions/5249279...5249971#5249971
Go to the top of the page
+Quote Post
Agape
post 17.12.2015, 11:22:29
Post #3





Grupa: Zarejestrowani
Postów: 384
Pomógł: 13
Dołączył: 16.06.2006

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


Widziałem to rozwiązanie, tylko problem jest taki że ... nie do końca je rozumiem ... funkcja pobiera część pliku i go obrabia i idzie dalej, to wiem z opisu, ale gdzie wkleic swoj kod. Bylbym wdzieczny za wskazanie miejsca albo wytlumaczenie tego dokladniej


--------------------
Go to the top of the page
+Quote Post
kapslokk
post 17.12.2015, 11:37:56
Post #4





Grupa: Zarejestrowani
Postów: 965
Pomógł: 285
Dołączył: 19.06.2015
Skąd: Warszawa

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


  1. call_user_func_array($callback,array(fread($handle,$chunk_size),&$handle,$i));


Jeśli jako $callback przekazesz nazwe funkcji stworzonej przez siebie to zostanie ona wykonana z parametrami z array(fread($handle,$chunk_size),&$handle,$i))

Ten post edytował kapslokk 17.12.2015, 11:39:32
Go to the top of the page
+Quote Post
Damonsson
post 17.12.2015, 11:39:09
Post #5





Grupa: Zarejestrowani
Postów: 2 355
Pomógł: 533
Dołączył: 15.01.2010
Skąd: Bydgoszcz

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


http://php.net/manual/en/class.splfileobject.php
Go to the top of the page
+Quote Post
Forti
post 17.12.2015, 12:20:39
Post #6





Grupa: Zarejestrowani
Postów: 655
Pomógł: 73
Dołączył: 2.05.2014

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


Ja parsuje kilka plików .csv po 300-400MB każdy. PHP nie daje rady smile.gif

Zaciągnąłem node.js, wielowątkowość i czas na jeden plik:

PHP - 20-30 minut
node.js - 20-30 sekund

cóż.. nie do wszystkiego PHP się nadaje wink.gif fakt ze tam jest coś więcej niż czytanie, jest jeszcze mapowanie i parsowanie odpowiednio, ale mimo wszystko..


--------------------
Overwatch24 - najbardziej zaawansowany Polski portal Overwatch od fanów dla fanów.

Fachowo.co

Behance.net/fachowo
Go to the top of the page
+Quote Post
phpion
post 17.12.2015, 12:58:46
Post #7





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Nie prościej wrzucić dane do bazy danych (chociażby do tabeli tymczasowej) za pomocą LOAD DATA? Poleci to migusiem, a co potem z tymi danymi zrobisz (przeformatujesz, przeniesiesz do właściwej struktury) to już Twoja sprawa, a całość i tak robisz na poziomie bazy danych.
Go to the top of the page
+Quote Post
Agape
post 17.12.2015, 13:01:36
Post #8





Grupa: Zarejestrowani
Postów: 384
Pomógł: 13
Dołączył: 16.06.2006

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


Musiałbym to robić ręcznie, a zalozenie jest takie zeby to zautomatyzowac. Mam pare takich plikow ktore musze aktualizowac raz na jakis czas i beda dochodzic nowe.


--------------------
Go to the top of the page
+Quote Post
phpion
post 17.12.2015, 13:13:55
Post #9





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Ale co byś musiał robić ręcznie?
Go to the top of the page
+Quote Post
DarkAbso
post 17.12.2015, 15:16:12
Post #10





Grupa: Zarejestrowani
Postów: 60
Pomógł: 10
Dołączył: 17.11.2011

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


Rozwiązanie, które podał @phpion wygląda najsensowniej (przynajmniej z mojej perspektywy). Od razu również dziękuje za ten pomysł (zoptymalizuje dzięki temu projekt). smile.gif
Go to the top of the page
+Quote Post
phpion
post 18.12.2015, 10:51:30
Post #11





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Dodam tylko jeszcze, że osobiście z dane z pliku wrzucam do tabeli tymczasowej o wszystkich kolumnach tekstowych. Dopiero potem przekształcam dane (np. w CSV mam liczbę jako 200 000,50 co przekształcam na 200000.50), zmieniam typy kolumn na właściwe (z tekstowych na np. numeryczne), usuwam nieprawidłowości w danych (np. potencjalne naruszenia kluczy obcych) itd. Dopiero mając w ten sposób obrobione dane przenoszę je do tabel właściwych.
Go to the top of the page
+Quote Post
Agape
post 22.12.2015, 09:30:05
Post #12





Grupa: Zarejestrowani
Postów: 384
Pomógł: 13
Dołączył: 16.06.2006

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


@phpion dzięki za super solucje. W wolnym czasie sprawdzę, ale rozwiazanie wydaje sie najlepsze. Rozumiem ze pozniej z tymczasowej pobierasz dane przez php, obrabiasz i przerzucasz partiami. Super.

@phpion jeszcze raz dzięki za takie rozwiązanie, właśnie je testuje, ale mam problem z jednym. W bazie mam powiedzmy 10 kolumn a w csv powiedzmy 25, jak teraz przypisac odpowiednie wartosci do kolumn ?
  1. LOAD DATA LOCAL INFILE "'.realpath(dirname(__FILE__).'/../../csv/plik.csv').'"
  2. INTO TABLE `tabela_z_csv`
  3. FIELDS TERMINATED BY ";"
  4. OPTIONALLY ENCLOSED BY "\""
  5. LINES TERMINATED BY "\r\n"
  6. IGNORE 1 LINES

nizej moge dac liste kolumn, ale to sa kolumny w bazie danych, moge wiec jakas ominac, ale jak uzywajac SET przypisac odpowiednie kolumny z csv do odpowiednich kolumn do bazy danych ? Troche dla mnie nie zrozumiale uzywanie @ w tym poleceniu :/


--------------------
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.07.2025 - 09:47