Подтвердить что ты не робот

Чтение очень больших файлов в PHP

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!";
}

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

4b9b3361

Ответ 1

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

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

Если ни одна из вышеперечисленных проблем не является вашей проблемой, вы можете изучить 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);
}

Edit

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

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

Ответ 2

Сделал 2 теста с файлом 1,3 ГБ и файлом 9,5 ГБ.

1,3 ГБ

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

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

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

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

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

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

9,5 ГБ

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

• Функция 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().

Ответ 6

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

это устанавливает ограничение на память до 12 МБ

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

Ответ 7

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

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

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