Binární zápis do souboru

webhope

Re:Binární zápis do souboru
« Odpověď #15 kdy: 11. 12. 2013, 17:05:55 »
Dík za pomoc. Už jsem to otevřel v Notepad++ (je třeba pluxin HEX EDITOR). a zjistil jsem, že tam opravdu žádný BOM není ani ty nuly tam nejsou (vedle těch zapsaných bajtů). Takže opravdu je to chyba zobrazení PSPadu, který asi předpokládá nějaké formátování nebo co. Jinak jestli tu někdo používáte NOtepad++ tak se chci zeptat jestli nevíte jak nastavit pozadí aby bylo černé a jak zjistit pozici aktuálního bajtu.  To nejde jinak než vypočítat? Mám tam 1f0 + 3 byty se rovná 499 bajtů takže mi to sedí.


petr

Re:Binární zápis do souboru
« Odpověď #16 kdy: 11. 12. 2013, 22:29:53 »
Doufám tedy že ti to dělá, co chceš, protože

Citace
... chová se to tak, že když zapisuji např. dvě čísla v hex je to  78 a 64 tak hex editor to zobrazuje jako 7800 6400 .
Citace
... Tudíž když posouvám fseek po jednom a pak zapisuji výsledek by měl být dva bajty např "FFFF" a ne "FF00 FF00".

Jenže v tom kódu seekuješ o 2 bajty, ne o jeden...

Když např. přidáš 1.120.100.60 do prázdného souboru, prvních 8 bajtů bude
78 00 64 00 00 00 00 00
seekuješ to o 2 bajty, viz úryvek tvého kódu, co jsem vložil do minulé odpovědi.
Když potom přidáš třeba 1.14.205.60, tak to bude
78 0E 64 CD 00 00 00 00
protože první bajt testuješ na \x00 a přesuneš se v cyklu o bajt dál.
Když dál přidáš třeba opět 1.120.100.60, tak vyjde
78 0E 64 CD 78 00 64 00

Další věc je, že to takhle hledá konec dat po 1 bajtů (vždy fseek a fread), což asi moc efektivní nebude a další věc že se ti při různých příležitostech budou přepisovat data:
Nejvýznamnější bajt v IP ti určuje offset * 250. Ale do těch 250 bajtů zapisuješ druhý i třetí bajt IP adresy. Takže rozsah adres 2.x.x.x ti bude přepisovat druhou polovinu záznamů pro rozsah 1.x.x.x. Navíc ve smyčce hledáš konec data testováním na hodnotu \x00; co když bude IP adresa x.0.x.x nebo x.x.0.x ? Přijdeš o její záznam.

Já když jsem to viděl, tak jsem ihned vzdal snahu porozumět tomu, v sítích se nijak nevyznám, myslel jsem si kdovíjakou magii neprovádíš a že to je nad moje schopnosti / čas. Teď si nejsem jist, když tě mate to posunování o bajt.

Možná jsi to už úplně přepracoval.... tak snad ti to funguje jak očekáváš.

K té metodě reset() jsem chtěl celou dobu říct jen to, že je buď chybně pojmenovaná nebo nedělá co má. Na funkčnost nemá vliv, ale až zapomeneš na implementační detaily, můžeš nasekat chyby tím, že budeš předpokládat že metoda reset() "resetuje" výstupní soubor a ona přitom zatím jen vytvoří nový soubor, pokud dosud neexistuje. Pokud existuje, nijak se ho nedotkne, takže jakýpak reset? Buď bych ji přejmenoval třeba na init() nebo v ní vytvářej soubor vždy (mód "wb") - existenci souboru stejně kontroluješ mimo ní a voláš ji jen když neexistuje.

webhope

Re:Binární zápis do souboru
« Odpověď #17 kdy: 12. 12. 2013, 11:35:32 »
Petře, co se týče toho fseek o dva bajty, tak to bylo myslím jen v té testovací části. Tu když odstraníš, tak pak se to dělá jinak.

No to je právě na zváženou. Mohl bych načíst celý řetězec po 750 bytech, respektive tři řetězce po 250 bytech (tohle ještě musím upravit, není to číslo dělitelné třema). A v tom pomocí smyčky hledat v RAM ce. Nebo hledat na disku po jednotlivých bajtech, což asi máš pravdu by bylo pomalejší, ale zase se nemusí načítat 750 bajtů, protože on s největší pravděpodobností načte pouze několik bajtů. Není to tak že by poslední tři čísla IP byly za sebou uložené. Ony jsou uložené tak, že všechny druhé čísla (n2x) z ip=n1x.n2x.n3x.n4x jsou uložené za sebou. Tzn n21,n22,n23 atd. tedy pokud v souboru jsou na stejném "řádku" zapsány tři IP:
124.5.100.1
124.8.10.14
124.9.18.254
tak fakticky načte pouze 5 bajtů. Ale pokaždé se při tom použije fseek. Jestli myslíš, že je to pomalé tak to budu načítat po celém řádku o velikosti 750 bajtů.

Data se přepisovat nemohou protože pokud je tam bajt který není \x00 tak se tam nic nepíše, jde se dál a zapíše se až narazí na \x00.
Proto považuji zbytečné odpovídat na zbytek tvých otázek, protože z logiky věci vyplývá, že k žádnému přepisu nemůže dojít.

Nakonec pokud by došlo místo tak se to celé vyresetuje a pojede se od nuly (nový soubor). Reset zde znamená smazání souboru a vygenerování nového.

webhope

Re:Binární zápis do souboru
« Odpověď #18 kdy: 12. 12. 2013, 11:37:29 »
Čili ten testovací kód byl tento:
Kód: [Vybrat]
// TEST
// die(); test first
$result = fseek($fh, $i+2);
fwrite($fh, chr($arr[2]), 1);
die($arr[1]." ".$arr[2]." ".$arr[3]. " result $result");
// END TEST

To celé příjde vymazat. Mám pocit, že tě to zmátlo.

webhope

Re:Binární zápis do souboru
« Odpověď #19 kdy: 12. 12. 2013, 12:14:07 »
Citace
Nejvýznamnější bajt v IP ti určuje offset * 250. Ale do těch 250 bajtů zapisuješ druhý i třetí bajt IP adresy.
Ne není to tak jak píšeš.
První číslo v IP určuje pozici, tedy "číslo řádku".
Kód: [Vybrat]
$arr[0]="120";
$this->segmentLength = 250; // toto nutno opravit na 249
$this->rowLength = 3*$this->segmentLength; // máme 3*250;
$segmentBegin = ($arr[0]-1)*$this->rowLength;
$segmentBegin = (120-1)*750;
$segmentBegin = 119*750;
Zápis tedy bude probíhat do řádku číslo 120. Tak ve starém kódu. V novém skriptu jsem ale vytvořil hlavičku o délce 750 bajtů, takže tam to nebude posunuté.


webhope

Re:Binární zápis do souboru
« Odpověď #20 kdy: 12. 12. 2013, 13:25:07 »
Ještě si dovolím požádat o radu. V nové verzi, jak jsem již zmínil přibyla hlavička. Ve třetí části je uložený název serveru, který chci blokovat. pro začátek jsem tam uložil slovo localhost;

Nyní kód, který by měl sestavit slovo $word obsahující "localhost".

Kód: [Vybrat]
for($n=$this->h1+$this->h2; $n<$this->header_size; $n++):
$word=$byte="";
fseek( $fh  , $n );echo "n is $n;";
                         // && $byte!=";"
while ( $byte=fread($fh,1) ) //  && ord($byte)!=0
     {
echo $byte;
$word.=$byte;
echo ":$word==".$_SERVER["HTTP_HOST"]."<br>".ord($byte);
if ( $word==$_SERVER["HTTP_HOST"] )
 return false; // this domain is blocked
endfor;

Tohle není dodělané. Vypíše to slovo localhost; a následující znaky které jsou nula. Dalo by se říct, že toto funguje, ale chci vypsat jen slovo localhost. Tak na konec podmínky while přidám:
 && $byte!=";"

a výsledek je ten, že to vypíše pouze písmeno "l", tedy jeden znak, protože cyklus je hned přerušen.
Zkoušel jsem tedy i  && $byte!=59
a && bindec($byte)!=59
nic z toho ale nefunguje :-( vždycky se cyklus hned přeruší  :o

and

Re:Binární zápis do souboru
« Odpověď #21 kdy: 12. 12. 2013, 15:14:31 »
Proc to vlastne davas do binaniho souboru? Kdyby to byl text ci csv, uz bys to mel hotovy a asi by to bylo i rychlejsi na zpracovani...

webhope

Re:Binární zápis do souboru
« Odpověď #22 kdy: 12. 12. 2013, 15:53:54 »
and: to si nemyslím, že by to bylo rychlejší. Pokud vezmeš v úvahu, že v souboru je zaznamenáno min. 120 IP, ale prakticky tak 200-500 IP (postupně jak se plní kontejner a podíváš se kolik kroků potřebuješ na zjištění jestli tam ta IP je nebo není, tak já myslím, že toto je rychlejší. Jinak totiž porovnání každé IP představuje porovnat tak kolem 14-15 znaků. Tady se ti za tu dobu porovnají min. 3 IP, ale je to samozřejmě různé, bude to záviset od toho jaká IP tam v tom kontejneru bude. Uvedu příklad. Když tam budu ukládat čínské proxy servery, tak ty mohou existovat pod např. 182.165.14 bude třeba 20 IP. Ale to nevadí. Protože uživatel co má IP 124. na tuto adresu vlastně vůbec neskočí. Ten skočí na řádek 124, kde zjistí, že žádná IP není a tudíž ho není třeba blokovat. Kdežto pokud to bude někdo s adresou 182.165.14 tak je blokovaný v nové verzi hned (protože 182.165.14 by se uložilo do hlavičky takže to není třeba ani zapisovat do řádku, když se to opakuje). Ale kdyby tam ta hlavička nebyla tak jako podle staré verze, tak přečte dejme tomu 60 bajtů a ví že je blokovaný (proxy je blokované).

Dal by se stejný proncip aplikovat i na seznam IP blokovaných uživatelů (ne proxy), ale jelikož tam by to bylo neomezené, musel by ten řádek mít dynamickou délku (to už mám taky vymyšlené takže asi to zavedu). Zkrátka mě to baví to vymýšlet. Užitečnost by byla samozřejmě až od většího počtu adres, jinak rychlost při krátkém seznamu zanedbatelná. To s tou dynamickou délkou bych řešil pomocí hlavičky. Do hlavičky se dá zapsat, kolikátý řádek má jakou délku. Délka by se dala zvětšit podle potřeby. Je fakt, je to zase o něco složitější, ale jen trošičku. Zase platí, čím více adres tam je (a pokud mu dojde vymezené místo) tím více musí přečíst bajtů z hlavičky, aby mohl rozšířit daný řádek. Zní to složitě? Vlastně je to jen o tom načíst správný počet bajtů před aktuálním řádkem a od následujícího řádku až do konce souboru, vygenerovat správnou délku aktuálního řádku, zaměnit řetězec (dosadit staré data), a nakonec poslučovat tyto tři části a zapsat to do nového souboru (nebo je zapsat do nového souboru v módu append, to by asi bylo lepší).

and

Re:Binární zápis do souboru
« Odpověď #23 kdy: 12. 12. 2013, 16:27:16 »
Nez PHP nacte, vyhodnoti, preskoci atd. radky v binarnim souboru, tak o trva.
Nacteni cele struktury do pameti a dotazani se bude radove rychlejsi diky tomu, ze operace se budou dit na urovni C/C++ kodu a ne na urovni PHP.
Nedavno jsem udelal zkusenost, ze pouziti sqlite3 jako storage je rychlejsi, nez uchovavat pointery do souboru na nacitani z nich a jejich cteni. Rozdil zhruba 2x.

Dvakrat mer a jednou rez - vyzkousej oba pristupy a posli vysledky, co je rychlejsi!

Nicmene na hrani je to urcite zajimavy material  ;)

webhope

Re:Binární zápis do souboru
« Odpověď #24 kdy: 12. 12. 2013, 17:07:55 »
and:
Jistě že to vyhodnocení kódu trvá. Vem si, že dnešní webové stránky většinou využívají třídy hlavně RS apod. na to, abys tam mohl mít přihlášené uživatele nebo vkládat články, dávat komentáře, atd. Kolik tříd se musí načíst a o jak složité objekty se jedná? V porovnání s nimi je moje třída opravdu banální, že je zbytečné to měřit. Ale taky si uvědom, že když použiješ například funkci file() nebo explode() tak tyto funkce fakticky parsují soubor a vytvářejí objekt (i když v php se tomu říká pole), což je podle mého názoru podobné (ne-li stejné?) jako vyhodnocení vlastní třídy a sestavení objektu (instance). Na sestavení vlastní třídy mě příjde lákavé to že si můžeš vytvořit vlastní metody, které si pojmenuješ přesně podle toho co potřebuješ. Tedy kdyby chtěl někdo například ukládat nějaké záznamy do mysql tabulky, ale ty by ses to rozhodl udělat binárně takže si ušetříš čas s připojováním k mysql a komplikace typu (nevím proč mi to hází mysql chybu, nevím proč se mi nezobrazují správně znaky, přišel jsem o data kvůli převodu z jedné tabulky do druhé, atd.) tak by to svůj smysl mohlo mít, pokud nemáš dva miliony uživatelů. Přístup máš zajištěný jedinečný, protože nikdo jiný než daný uživatel dané místo v souboru přepisovat nebude, zálohování velice snadno zkopíruješ soubor s tabulkou přes ftp manažer. To by mělo své výhody.

and

Re:Binární zápis do souboru
« Odpověď #25 kdy: 12. 12. 2013, 21:40:39 »
and:
Jistě že to vyhodnocení kódu trvá. Vem si, že dnešní webové stránky většinou využívají třídy hlavně RS apod. na to, abys tam mohl mít přihlášené uživatele nebo vkládat články, dávat komentáře, atd. Kolik tříd se musí načíst a o jak složité objekty se jedná? V porovnání s nimi je moje třída opravdu banální, že je zbytečné to měřit. Ale taky si uvědom, že když použiješ například funkci file() nebo explode() tak tyto funkce fakticky parsují soubor a vytvářejí objekt (i když v php se tomu říká pole), což je podle mého názoru podobné (ne-li stejné?) jako vyhodnocení vlastní třídy a sestavení objektu (instance). Na sestavení vlastní třídy mě příjde lákavé to že si můžeš vytvořit vlastní metody, které si pojmenuješ přesně podle toho co potřebuješ. Tedy kdyby chtěl někdo například ukládat nějaké záznamy do mysql tabulky, ale ty by ses to rozhodl udělat binárně takže si ušetříš čas s připojováním k mysql a komplikace typu (nevím proč mi to hází mysql chybu, nevím proč se mi nezobrazují správně znaky, přišel jsem o data kvůli převodu z jedné tabulky do druhé, atd.) tak by to svůj smysl mohlo mít, pokud nemáš dva miliony uživatelů. Přístup máš zajištěný jedinečný, protože nikdo jiný než daný uživatel dané místo v souboru přepisovat nebude, zálohování velice snadno zkopíruješ soubor s tabulkou přes ftp manažer. To by mělo své výhody.

Nikde v tvem textu nevidim to rychlostni srovnani, jen kupu dohadu...
Neni to tim, ze si fakt jen hrajes a opravdu efektivni reseni nehledas?

webhope

Re:Binární zápis do souboru
« Odpověď #26 kdy: 12. 12. 2013, 22:20:33 »
and

Citace
Nacteni cele struktury do pameti a dotazani se bude radove rychlejsi diky tomu, ze operace se budou dit na urovni C/C++ kodu a ne na urovni PHP.
Nedavno jsem udelal zkusenost, ze pouziti sqlite3 jako storage je rychlejsi, nez uchovavat pointery do souboru na nacitani z nich a jejich cteni. Rozdil zhruba 2x.

Ok, tedy nebudu to číst po jednom bajtu, ale po celém řádku/segmentu. Tím pádem se ten rozdíl smaže. Během toho co jsem vypisoval smyčku hlavičky o délce 449 bajtů to jelo děsně pomalu, ale bylo to nejspíš tím, že tam bylo echo $bajt (echovat jednotlivé stringy v cyklu vůbec není efektivní). Já to srovnání zatím nemám, ale mohu si to udělat později až dodělám třídu.

Když máš zkoušenost sqlite, zkoušel si jak velký je rozdíl v porovnání s mysql při provozování stránek? A je těžké předělat RS dělaný na mysql do sqlite? Nebo je to skoro stejné? Těma pointerama si myslel jako že uchováváš id jednotlivých záznamů? To já id právě neukládám, ale vypočítávám pozici což by mělo být rychlejší. Ale těžko říct jak by celá stránka reagovala, to bych musel celé předělat z RS pro mysql na RS pro sqlite.

webhope

Re:Binární zápis do souboru
« Odpověď #27 kdy: 12. 12. 2013, 23:01:23 »
Hele tak dělal jsem test, jo, a teda nevím jestli to měřím špatně nebo co, ale mě to vrací čas nula. Pokud to chceš změřit, tak první bajt nastavuju $i=449; poslední bajt $i=749;

Kód: [Vybrat]
public function checkDomain()
{
if ( !$this->FRWBHandler )
    $this->FRWBHandler = @fopen($this->file,"r+b");
    $fh =& $this->FRWBHandler;

    // read header block 3 - domains;
$t2=time();
$sentence="";
for($n=$this->h1+$this->h2; $n<$this->header_size; $n++):
$word=$byte="";
fseek( $fh  , $n );echo "n is $n;";
while($byte=fread($fh,1) && $byte<>";" ):
$word.=$byte;
if ($word=="localhost")
{
       die();
}
endwhile;
$sentence.=$word;
$word="";
    endfor;
    $t1=time();
    echo "sentence:".strlen($sentence).";";
    die("time:".($t1-$t2));
}

Je sice pravda, že v té hlavičce není nic jiného než nuly, ale podle mě to nemá žádný vliv na rychlost.

webhope

Re:Binární zápis do souboru
« Odpověď #28 kdy: 12. 12. 2013, 23:16:12 »
Mám tam chybu, má tam být
Kód: [Vybrat]
while( ($byte=fread($fh,1)) && ... podmínky )ale ono to stejně nejde otestovat, protože se to zacykluje. Nejlepší je na test cyklus while vypustit a dostaneš rozdíl v čase nula milisekund.

petr

Re:Binární zápis do souboru
« Odpověď #29 kdy: 13. 12. 2013, 04:56:33 »
Petře, co se týče toho fseek o dva bajty, tak to bylo myslím jen v té testovací části. Tu když odstraníš, tak pak se to dělá jinak.
Moje chyba, přehlédl jsem ten testovací kód, který tam nepatří. Já komentáře smazal, když jsem reformátoval kód :) Ale problém s hledáním konce dat testováním na hodnotu \0 tam pořád vidím. Adresy a.0.x.x, pro které je nejvyšší bajt "a" stejný, se ti budou přepisovat, ne?

Problém s rychlostí snad ani není ve čtení ze souboru a seekování, stejně bude v paměti, ale ve smyčkách. Pomocí smyčky hledáš konec dat (navíc chybně testováním na hodnotu \0, která může být součástí záznamu) a smyčkou také testuješ zda je IP blokována. Data nemáš na úrovni stejně významných bajtů IP adresy nijak tříděna. To přece mohou být stovky průchodů, když bude tabulka více zaplněna.

Přelétl jsem další komentáře a prošel podrobněji ten (původní) kód a teprve teď mi došlo, k čemu ten kód má vlastně sloužit: k jednoduchém ukládání a vyhledávání JEDNOTLIVÝCH IP adres, tedy žádná magie, žádné intervaly, žádné podsítě. Proč tedy ty IP adresy jednoduše neukládáš do databáze třeba jako 32bit unsigned integer do jednoho indexovaného sloupce? Neřešilo by to vše, co potřebuješ?