За последние 24 часа нас посетили 22906 программистов и 1243 робота. Сейчас ищут 788 программистов ...

Создание текстового файла большого размера

Тема в разделе "PHP для новичков", создана пользователем leekav, 20 янв 2018.

  1. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Код (Text):
    1. <?php
    2.  
    3.     ini_set('max_execution_time', 3600);
    4.     ini_set('memory_limit', -1);
    5.     ini_set('upload_max_filesize', -1);
    6.     $fp = fopen("filenew.txt", "w+");
    7.  
    8.     function generateKey($length = 8){
    9.       $chars = '0123456789';
    10.       $numChars = strlen($chars);
    11.       $string = '';
    12.       for ($i = 0; $i < $length; $i++) {
    13.         $string .= substr($chars, rand(1, $numChars) - 1, 1);
    14.       }
    15.       return $string;
    16.     }
    17.  
    18.  
    19.     $text = array();
    20.     $countsum = 0;
    21.     while ($countsum < 1073741824){
    22.         do{
    23.             $genKey = generateKey(rand(1, 4000));
    24.             $genVal = generateKey(rand(1, 4000));
    25.             $sum = strlen($genKey) + strlen($genVal);
    26.         }    while ($sum > 4000);
    27.  
    28.         $text[$genKey] = $genVal;
    29.         $countsum += $sum + 2;
    30.         echo "$countsum<br>";
    31.     };
    32.  
    33.     ksort($text);
    34.  
    35.  
    36.  
    37. foreach ($text as $key => $val) {
    38.     fwrite($fp, "$key\t$val\x0A");
    39. }
    40.     fclose($fp);
    41. ?>
    Изучаю PHP второй день.
    Нужно получить текстовый файл размером 1 ГБ. Генерируется долго, но в конце выдает файл размером всего около 50 КБ. В чем может быть причина? Пытался найти какие-либо ограничения, но не нашёл.
    Использовал OpenServer.
     
  2. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    А точно "w+" ? Может "a+" ?
    Я не вникал в суть кода, но вроде как до запись это "a+".
     
  3. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    1. тебе не нужен ду-вайл внутри вайла потому что в функции генерации у тебя и так есть цикл. Переделай логику.
    2. тебе не нужна переменная-буфер - ты можешь сразу писать блоки в файл. Это будет быстро так как у пыха есть буфер записи, который будет накапливать байты перед сбросом в файл.
    --- Добавлено ---
    ну и собственно ошибка в логике: ты в ду-вайле что-то там до какого-то лимита делаешь, а потом записываешь один раз но только текущее значение переменных, а не всё что было нажито непосильным трудом ду-вайла.
     
  4. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Точно, потому что мне не надо дописывать что-то в существующий файл.

    Какая именно переменная-буфер не нужна? Ду-вайл использовал, так как элемент массива не должен превышать 4000 символа, а ключ и значение может быть размером до 4000.
    Возможно ошибаюсь, но если бы он из-за ду-вайла записывал один раз, то в файле был бы один элемент массива, а так очень часто лимит доходит до 69000 байтов, реже до 110000
     
  5. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    $text
    И? Ты в теле этого ду-вайла генерируешь две строки, каждая из которых у тебя по длине рандомна. И если они у тебя длиннее 4К то ты уходишь на следующий раунд. ЗАЧЕМ? Если у тебя лимит в 4К то ты можешь придумать рандомное число, сделать одну строку равную этому числу, сделать вторую строку равную 4К-минус-это-число. Всё. Без ду-вайла, регистрации и СМС.
     
  6. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Переделал до такого
    Код (Text):
    1. <?php
    2.  
    3.     ini_set('max_execution_time', 3600);
    4.     ini_set('memory_limit', -1);
    5.     ini_set('upload_max_filesize', -1);
    6.     $fp = fopen("filenew.txt", "w+");
    7.  
    8.     function generateKey($length = 8){
    9.       $chars = '0123456789';
    10.       $numChars = strlen($chars);
    11.       $string = '';
    12.       for ($i = 0; $i < $length; $i++) {
    13.         $string .= substr($chars, rand(1, $numChars) - 1, 1);
    14.       }
    15.       return $string;
    16.     }
    17.  
    18.  
    19.     $text = array();
    20.     $countsum = 0;
    21.     while ($countsum < 1048576){
    22.         $genKey = generateKey(rand(1, 4000));
    23.         $lenVal = 4000 - strlen($genKey);
    24.         $genVal = generateKey(rand(1, $lenVal));
    25.         $sum = strlen($genKey) + strlen($genVal);
    26.  
    27.         $text[$genKey] = $genVal;
    28.         $countsum += $sum + 2;
    29.         echo "$countsum<br>";
    30.     };
    31.  
    32.     ksort($text);
    33.  
    34.  
    35.  
    36. foreach ($text as $key => $val) {
    37.     fwrite($fp, "$key\t$val\x0A");
    38. }
    39.     fclose($fp);
    40. ?>
    По идее файл должен получаться размером около 1 мегабайта, а выходит около 320 килобайт, хотя countsum выходит верный.
    С меньшим количеством все выходит верно
     
  7. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    Давай по новой, Миша, всё хуйня

    объявили значение переменной от 1 до 4К. это будет длина ключа.
    объявили строку этой длины. это будет ключ.
    объявили строку длины 4К-минус-значение-длины-ключа.
    всё

    разница? ты объявляешь строку и потом получаешь её длину что чуть более накладно чем сразу знать длину строки и заказать себе такую строку. ну и по моей логике вторая строка сразу добивает до 4К а в твоём алгоритме она почему-то рандом от 1 до частного. хотя это может быть и правильно - тебе, как говорится, виднее в этом моменте.

    ну и ещё раз: откажись от переменной для накопления. сразу пиши в файл.
     
  8. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Спасибо, теперь заработало после того как убрал второй rand. В условии задачи надо, чтобы длина было до 4к, а не ровно, поэтому это было более подходяще.
    Переменная для накопления это какая, countsum?
     
  9. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    так видно?
     
  10. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Да
    --- Добавлено ---
    Уточнение. Как мне отсортировать по ключу, если я сразу буду писать в файл?
     
  11. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    Уточнение. А зачем сортировка по ключу?
     
  12. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Такое условие задачи. Потом нужно по файлу использовать бинарный поиск
     
  13. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    Ясненько... Какие-то ещё условия задачи, о которых мы не знаем?
     
  14. leekav

    leekav Новичок

    С нами с:
    20 янв 2018
    Сообщения:
    13
    Симпатии:
    0
    Есть менее критические, такие как, формат файла, размер файла, лимит записей. Все это уже указал в коде
     
  15. Okto

    Okto Новичок

    С нами с:
    19 авг 2017
    Сообщения:
    12
    Симпатии:
    9
    Создать файл заданного размера можно например вот так:

    PHP:
    1. <?php
    2. // Размер файла в килобайтах
    3. const SIZE_KB = 1024 * 10; // 10 мегабайт
    4. const FILE_NAME = 'test.log';
    5.  
    6. // Строка длиной в 1 килобайт
    7. $content = implode(array_fill(0, 1024, '0'), '');
    8. // print strlen($content); // 1024B = 1KB
    9.  
    10. for ($i = 0; $i < SIZE_KB; $i++) {
    11.     file_put_contents(FILE_NAME, $content, FILE_APPEND | LOCK_EX);
    12. }
    Запуск в терминале:
    Код (Text):
    1.  
    2. $ php test.php
    3. $ du -sh test.log
    4. 11M    test.log
     
  16. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    @Okto задача заполнить текстовый файл осмысленными байтами, а не однотипным сидом. Садись, два.