Вопрос

fopen терпит неудачу, когда я пытаюсь прочитать файл очень среднего размера в PHP. A 6 meg file заставляет его задыхаться, хотя файлы меньшего размера вокруг 100k все просто отлично.я читал, что иногда необходимо перекомпилировать PHP с помощью -D_FILE_OFFSET_BITS=64 установите флажок, чтобы читать файлы размером более 20 гигабайт или что-то нелепое, но разве у меня не должно быть проблем с файлом размером 6 мегабайт?В конце концов, мы захотим читать файлы размером около 100 мегабайт, и было бы неплохо иметь возможность открывать их, а затем читать построчно с помощью fgets, как я могу делать с файлами меньшего размера.

Каковы ваши приемы / решения для чтения и выполнения операций с очень большими файлами в PHP?

Обновить:Вот пример простого кодового блока, который завершается с ошибкой в моем файле размером 6 мегабайт - PHP, похоже, не выдает ошибку, он просто возвращает false.Может быть, я делаю что-то крайне глупое?

$rawfile = "mediumfile.csv";

if($file = fopen($rawfile, "r")){  
  fclose($file);
} else {
  echo "fail!";
}

Еще одно обновление:Спасибо всем за вашу помощь, это действительно оказалось чем-то невероятно глупым - проблема с разрешениями.Мой маленький файл необъяснимым образом имел права на чтение, в то время как файл большего размера - нет.Дох!

Это было полезно?

Решение

Вы уверены, что это fopen это сбой, а не настройка тайм-аута вашего скрипта?Значение по умолчанию обычно составляет около 30 секунд или около того, и если чтение вашего файла занимает больше времени, это может привести к сбою.

Еще одной вещью, которую следует учитывать, может быть ограничение памяти в вашем скрипте - чтение файла в массив может привести к сбою, поэтому проверьте свой журнал ошибок на наличие предупреждений о памяти.

Если ни то, ни другое из вышеперечисленного не является вашей проблемой, вы могли бы рассмотреть возможность использования fgets читать файл построчно, обрабатывая по ходу работы.

$handle = fopen("/tmp/uploadfile.txt", "r") or die("Couldn't get handle");
if ($handle) {
    while (!feof($handle)) {
        $buffer = fgets($handle, 4096);
        // Process buffer here..
    }
    fclose($handle);
}

Редактировать

PHP, похоже, не выдает ошибку, он просто возвращает false .

Это путь к $rawfile правильно относительно того, где запущен скрипт?Возможно, попробуйте указать здесь абсолютный путь к имени файла.

Другие советы

Провел 2 теста с файлом 1,3 ГБ и файлом 9,5 ГБ.

1,3 ГБ

Использование fopen ()

Этот процесс использовал 15555 мс для своих вычислений.

Он потратил 169 мс на системные вызовы.

Использование file ()

Этот процесс использовал 6983 мс для своих вычислений.

Он потратил 4469 мс на системные вызовы.

9,5 ГБ

Использование fopen ()

Этот процесс использовал 113559 мс для своих вычислений.

Он провел 2532 мс в системных вызовах.

Использование file ()

Этот процесс использовал 8221 мс для своих вычислений.

Он потратил 7998 мс на системные вызовы.

Кажется, file () быстрее.

Ну, вы можете попробовать использовать функцию readfile, если вы просто хотите вывести файл.

Если это не так - может быть, вам следует подумать о дизайне приложения, почему вы хотите открывать такие большие файлы по веб-запросам?

Я использовал fopen, чтобы открыть видеофайлы для потоковой передачи, используя php-скрипт в качестве сервера потокового видео, и у меня не было проблем с файлами размером более 50/60 МБ.

• Тот самый fgets() функция работает нормально до тех пор, пока объем текстовых файлов не превысит 20 Мбайт и скорость синтаксического анализа значительно не снизится.

• Тот самый file_ get_contents() функция дает хорошие результаты до 40 Мбайт и приемлемые результаты до 100 Мбайт, но file_get_contents() загружает весь файл в память, так что это не масштабируемо.

• Тот самый file() функция не работает с большими текстовыми файлами, потому что эта функция создает массив, содержащий каждую строку текста, таким образом, этот массив сохраняется в памяти, а используемая память становится еще больше.
На самом деле, файл размером 200 МБ я смог разобрать только с помощью memory_limit установлено значение 2 ГБ, что было неподходящим для файлов объемом более 1 ГБ, которые я намеревался проанализировать.

Если вам нужно проанализировать файлы размером более 1 ГБ, а время анализа превысило 15 секунд, и вы хотите избежать загрузки всего файла в память, вам нужно найти другой способ.

Мое решение состояло в том, чтобы разбирать данные на произвольные небольшие фрагменты.Этот код является:

$filesize = get_file_size($file);
$fp = @fopen($file, "r");
$chunk_size = (1<<24); // 16MB arbitrary
$position = 0;

// if handle $fp to file was created, go ahead
if ($fp) {
   while(!feof($fp)){
      // move pointer to $position in file
      fseek($fp, $position);

      // take a slice of $chunk_size bytes
      $chunk = fread($fp,$chunk_size);

      // searching the end of last full text line
      $last_lf_pos = strrpos($chunk, "\n");

      // $buffer will contain full lines of text
      // starting from $position to $last_lf_pos
      $buffer = mb_substr($chunk,0,$last_lf_pos);

      ////////////////////////////////////////////////////
      //// ... DO SOMETHING WITH THIS BUFFER HERE ... ////
      ////////////////////////////////////////////////////

      // Move $position
      $position += $last_lf_pos;

      // if remaining is less than $chunk_size, make $chunk_size equal remaining
      if(($position+$chunk_size) > $filesize) $chunk_size = $filesize-$position;
      $buffer = NULL;
   }
   fclose($fp);
}

Используемая память - это только $chunk_size и скорость немного меньше, чем та, которая получается с file_ get_contents().Я думаю, PHP Group должна использовать мой подход, чтобы оптимизировать свои функции синтаксического анализа.

*) Найдите тот get_file_size() функция здесь.

Если проблема вызвана превышением лимита памяти, попробуйте установить более высокое значение (это может сработать или нет в зависимости от конфигурации php).

это устанавливает предел памяти в 12 Мб

ini\_set("memory_limit","12M");

для меня fopen () работает очень медленно с файлами размером более 1 МБ, file () намного быстрее.

Просто пытаясь прочитать строки по 100 за раз и создать пакетные вставки, fopen () занимает 37 секунд, а file () - 4 секунды. Это должен быть шаг string-> gt; array , встроенный в file ()

Я бы попробовал все варианты обработки файлов, чтобы увидеть, какие из них лучше всего подойдут для вашего приложения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top