Zjištění chyby při neúspěchu fwrite()

A. F.

Zjištění chyby při neúspěchu fwrite()
« kdy: 30. 06. 2018, 15:18:47 »
Ahoj.

Načítám celkem velký objem dat (několik giga) po kouskách o velikosti typicky 2096 bajtů. A následně ho zapisuju do souboru v tempu:
Kód: [Vybrat]
$tmpdir = sys_get_temp_dir();
$tmpname = tempnam($tmpdir, 'app-');
$handle = fopen($tmpname, 'a');
 
// velikost $s je obvykle 2096 bajtů
function write($s)
{
    $len = strlen($s);
    $wrote = fwrite($handle, $s);
    if ($len !== $wrote) {
        echo "\n\nERROR: Nesedí počet zapsaných bytů. C1 {$wrote} ~ {$len}\n\n"; // "419 ~ 2096"
        var_dump(error_get_last()); // nic
 
        $wrote2 = fwrite($handle, substr($s, $wrote));
        if ($wrote2 !== ($len - $wrote)) {
            echo "\n\n{$s}\n\n"; // zde vidím, že to není poslední záznam. Je to uřízlé uprostřed textu.
            throw new RuntimeException('Nesedí počet zapsaných bytů. C2 ' . "{$wrote2} ~ " . ($len - $wrote) ); // "0 ~ 1677"
        }
    }
}

Celé mi to chcípne na tom, že nesedí počet zapsaných bajtů. Je možné, že mi třeba došlo místo v tempu, nebo tak něco. Ale vadí mi, že mi to nevypíše žádnou chybu.

Otázka tedy zní, jak zjistím, co se stalo?

Děkuji za odpověď.


l

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #1 kdy: 30. 06. 2018, 15:35:04 »
Nevládnu PHP, ale nepomohlo by tohle?

https://stackoverflow.com/questions/9473474/php-fwrite-doesnt-finish-writing-string-data-to-file-why#9473840

sice se člověk nedozví, kde to zkrachovalo, ale funkce, zmíněná v odkazu údajně garantuje přepis celého řetězce.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #2 kdy: 30. 06. 2018, 15:45:53 »
Funkce fwrite negarantuje, že zapíše všechny znaky. Musíte si posouvat ukazatel v řetězci a opakovat funkci tak dlouho, dokud nezapíše vše. Pokud by došlo k chybě, vrací fwrite FALSE.

Kit

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #3 kdy: 30. 06. 2018, 16:27:31 »
Kód: [Vybrat]
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);

A. F.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #4 kdy: 30. 06. 2018, 16:38:19 »
Funkce fwrite negarantuje, že zapíše všechny znaky. Musíte si posouvat ukazatel v řetězci a opakovat funkci tak dlouho, dokud nezapíše vše. Pokud by došlo k chybě, vrací fwrite FALSE.

Nechápu, jak to souvisí s mojí otázkou?


Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #5 kdy: 30. 06. 2018, 16:42:54 »
Nechápu, jak to souvisí s mojí otázkou?
Máte ten kód špatně. Porovnáváte počet zapsaných bajtů s počtem bajtů k zapsání, a když nesouhlasí, považujete to za chybu. Ale ona to chyba není, počet zapsaných bajtů může být v rozmezí 0 až počet bajtů k zapsání. fwrite prostě zapíše tolik bajtů, kolik zrovna zapsat může, a vy si musíte zkontrolovat, zda už zapsal všechno, a když ne, tak to otočit v cyklu a zapsat další část. Podívejte se na dokumentaci fwrite, tammáte hned v první poznámce příklad, jak má zápis do souboru vypadat správně.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #6 kdy: 30. 06. 2018, 16:47:18 »
Nechápu, jak to souvisí s mojí otázkou?
Máte ten kód špatně. Porovnáváte počet zapsaných bajtů s počtem bajtů k zapsání, a když nesouhlasí, považujete to za chybu. Ale ona to chyba není, počet zapsaných bajtů může být v rozmezí 0 až počet bajtů k zapsání. fwrite prostě zapíše tolik bajtů, kolik zrovna zapsat může, a vy si musíte zkontrolovat, zda už zapsal všechno, a když ne, tak to otočit v cyklu a zapsat další část. Podívejte se na dokumentaci fwrite, tammáte hned v první poznámce příklad, jak má zápis do souboru vypadat správně.

Přečtěte si prosím nejdříve ten kód, dobře?
« Poslední změna: 30. 06. 2018, 16:49:52 od BoneFlute »

A. F.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #7 kdy: 30. 06. 2018, 16:50:39 »
Kód: [Vybrat]
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #8 kdy: 30. 06. 2018, 16:53:15 »
Přečtěte si prosím nejdříve ten kód, dobře?
Nejprve si vy velmi pomalu přečtěte, co jsem vám napsal ve svém prvním komentáři. Máte tam vysvětlené, jak funguje funkce fwrite a proč máte ten kód špatně. Pak si přečtěte dokumentaci funkce fwrite, abyste to lépe chápal, odkaz jsem vám dával.

Kód: [Vybrat]
    $len = strlen($s);
    $wrote = fwrite($handle, $s);
    if ($len !== $wrote) {
        echo "\n\nERROR: Nesedí počet zapsaných bytů. C1 {$wrote} ~ {$len}\n\n"; // "419 ~ 2096"
Konkrétně tady jsou špatně ty poslední dva řádky, protože to, že se zapsalo méně bajtů, než kolik jich bylo k dispozici, není chyba, je to standardní chování funkce fwrite.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #9 kdy: 30. 06. 2018, 16:55:19 »
Kód: [Vybrat]
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.

Klidně to zkuste, ale ničemu to nepomůže, protože třetí parametr funkce fwrite je nepovinný, a pokud není uveden, zapisuje se celý řetězec. Tedy uvedený kód je ekvivaletní s tímhle:

Kód: [Vybrat]
$wrote = fwrite($handle, $s);
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.

Kit

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #10 kdy: 30. 06. 2018, 17:22:20 »
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.

V dokumentaci je napsáno přesně to, co jsem psal, tedy že třetí parametr je v takových případech nutný.

A. F.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #11 kdy: 30. 06. 2018, 17:32:11 »
Kód: [Vybrat]
$len = strlen($s);
$wrote = fwrite($handle, $s, $len);
To by bylo hloupé, ale zkusím to.

Klidně to zkuste, ale ničemu to nepomůže, protože třetí parametr funkce fwrite je nepovinný, a pokud není uveden, zapisuje se celý řetězec. Tedy uvedený kód je ekvivaletní s tímhle:

Kód: [Vybrat]
$wrote = fwrite($handle, $s);
Nebývá špatné přečíst si dokumentaci, pak se nemusíte ptát na věci, které jsou tam napsané.

Děkuji za příspěvek. Stále nechápu jak by mi mohl alespoň vzdáleně pomoci s mým problémem. Opakování zápisu je použito už v tom kódu, nevím tedy proč mi to doporučujete. Cožpak jste ten kód nečetl, než jste psal svou radu?

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #12 kdy: 30. 06. 2018, 17:33:31 »
V dokumentaci je napsáno přesně to, co jsem psal, tedy že třetí parametr je v takových případech nutný.
Vy jste napsal jenom kus kódu, žádné vysvětlení, natož něco o „takových případech“. Ty hranaté závorky kolem parametru $length v definici funkce označují, že je parametr nepovinný, pak je to ještě zopakované u samotného parametru: „If the length argument is given…“. Pokud narážíte na to, že přítomnost parametru $length zároveň znamená,že s ebude ignorovat volba magic_quotes_runtime, my nevíme ani co chce zapisovat ani jak má tuto volbu nastavenou.

Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #13 kdy: 30. 06. 2018, 17:38:23 »
Stále nechápu jak by mi mohl alespoň vzdáleně pomoci s mým problémem.
Váš problém je, že si myslíte, že došlo k chybě, ve skutečnosti k žádné chybě nejspíš nedošlo. Zda došlo k chybě otestujete tak, že návratovou hodnotu funkce fwrite() porovnáte s hodnotou FALSE.

Opakování zápisu je použito už v tom kódu
Ne, není. Jak jste přišel na to, že při druhém volání se zapíše vše? Volání se musí opakovat tak dlouho, dokud nejsou zapsaná všechna data. Používají se k tomu cykly.

Cožpak jste ten kód nečetl, než jste psal svou radu?
Přestaňte pořád hledat chyby u jiných, když je ta chyba jenom ve vašem kódu. Četl jste tu poznámku s příkladem v dokumentaci fwrite(), kterou jsem odkazoval? Vidíte tam ten cyklus? Připadá vám, že takový cyklus máte ve svém kódu?

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Zjištění chyby při neúspěchu fwrite()
« Odpověď #14 kdy: 30. 06. 2018, 18:33:33 »
Je mi líto, ale žádné úžasné řešení asi neexistuje.

Funkce fwrite() je jen alias na php_stream_write() a ten nijak zvlášť neřeší důvod nezápisu.
Funkce file_put_contents() sice zařve, že se nepovedlo zapsat ale přičinu, "possibly out of free disk space" si bohapustě vycucá z prstu. Je fakt, že to bude nejčastější příčina, protože práva etc si zjistíš už při fopen().