Autor Zpráva
Kall Ell
Profil *
Dobrý den, mám dotaz. Potřebuji načíst soubor csv pomocí php do sql databaze. Problém je, že je ten soubor hodně velký. Na menší soubor mě script normálně funguje. Ale já potřebuji načíst soubor o velikosti 128MB s 930 tisíc řádků. Je to jednorázové načtení. Nastavil jsem na serveru délku scriptu na 90s, víc bych to nerad nastavoval. 200 tisíc řádků to zvládne pak vyhazuje error o překročení délky scriptu. Chtěl bych ten soubor načíst třeba na třikrát, ale nepřišel jsem na to, jak nastavit načítání ze souboru od určitého řádku. Poradíte?
Joker
Profil
Kall Ell:
V CSV bývají data uložená po řádcích, takže by mělo jít ten soubor rozdělit třeba po 100 000 řádcích a mělo by to normálně fungovat.

Chtěl bych ten soubor načíst třeba na třikrát
Poznámka: Pokud máte 930 000 řádků a jedním cyklem zvládnete zpracovat maximálně 200 000, tak ho natřikrát asi nezpracujete.
Kall Ell
Profil *
Jasný tak bych to nějak chtěl udělat, ale jak mám nastavit, aby mě soubor načítal od řádku 200000 dál? S tím mám problém. Když načtu prvních 200K tak mě funkce fTell($soubor) vyhodí, že je ukazacel na pozici 28469534. Pomocí funkce fSeek($soubor, '28469534') nastavím ukazatel na místo kde zkončil. Po dalším spuštění scriptu pokracuje od toho místa, ale funkce fTell($soubor) mě vrací stále stejnou hodnotu 28469534, takže se dál jak je 400K nedostanu. Existuje nějaká proměná, která by ukazatel nastavila na potřebný řádek? fseek posune ukazatel o daný počet znaků v souboru, což je pro mě nepoužitelný, protože každý řádek má jiný počet znaků.
nightfish
Profil
Kall Ell:
funkce fTell($soubor) mě vrací stále stejnou hodnotu 28469534
to moc nedává smysl - mohlo by to být voláním funkce ftell na nesprávném místě

druhou možností je rozsekat soubor na více souborů (v nějakém textovém editoru, který nemá problémy s velkými soubory) a každý zpracovávat samostatně
Kall Ell
Profil *
Ha, sakra, jsem idiot, to mě nenapadlo. To bude asi nejrychlejší. Nic méně by mě to stejně zajímalo, proč to dělá. Přikládám ten script asi to bude lepší. Zatím není hotový. Zatím jsem udělal jen script, který má za úkol projít celej soubor a zjistit, kolik mají jednotlivá pole maximálně znaků. Abych mohl vytvořit tabulku v DB. pozdeji nahradím počítání znaku, zápisem do db.

$pocet_radku = 0;
echo ("nacteni dat z csv souboru do tabulky<p>");
$fp = fopen ("zdroje/cenik.csv","r");
while($data = fgetcsv ($fp, 10000, ";")) {
      $num = count($data);
      $kontrola = fSeek($fp, '1481');
      $pocet_radku++;
      if ($data[0] == 'destinace') {
         // tohle je nacteni prvniho radku, kde je popis sloupcu
         // soubor obsahuje cenik exportovany z jine databaze
         for ($c=0; $c<$num; $c++) {
            $popis_sloupcu[$c] = $data[$c];
            $pocet_znaku[$c] = '0';
         }
      }
      else {
         if ($pocet_znaku[1] < strlen($data[1])) {
             $pocet_znaku[1] = strlen($data[1]);}
         for ($c=0; $c<$num; $c++) {
            if ($pocet_znaku[$c] < strlen($data[$c])) {
               $pocet_znaku[$c] = strlen($data[$c]);
            }
         }
      }
      if ($pocet_radku == 200000) {
         print "<br> pozice v souboru zustala na: ". fTell($fp) . "<br>";
         break;
      }
}
foreach ($pocet_znaku as $klic => $hodnota){
   print "sloupec: ". $popis_sloupcu[$klic] ." ma nejvice znaku: $hodnota<br>";
}
print "<br>pocet radku je $pocet_radku<br>";
fclose ($fp);
nightfish
Profil
vidím správně, že se na řádku 6 při každém průchodu cyklem nastaví pozice v souboru na 1481. bajt?
Kall Ell
Profil *
Jsem idiot, prošel jsem to tolikrat, že mě taková blbost unikla. Víc očí víc vidí. Dík za postřeh.
Nox
Profil
Nebylo by lepší použít něco jako http://dev.mysql.com/doc/refman/5.1/en/load-data.html ? Nevim, ptám se, funkce vypadá určená přímo na toto (ikdyž možná může být problém s posláním tak velkýho souboru...)
TomášK
Profil
LOAD DATA INFILE, na které odkazuje Nox, je podstatně rychlejší než hromadný INSERT - pokud si dobře pamatuju, tak asi 10x. Určitě bych ji použil, pokud je to možné.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0