У меня есть файл, который слишком велик для размещения в памяти, из которого мне нужно удалить определенные символы (если быть точным, управляющие символы). Моя текущая функция выглядит так:
$old = fopen($file, 'r');
$new = fopen($tmpFile, 'w');
while (!feof($old)) {
fwrite($new, preg_replace('/[^\P{Cc}\t\r\n]/u', '', fgets($old)));
}
rename($tmpFile, $file);
В большинстве случаев это работает нормально. Однако возможная проблема заключается в том, что fgets
читает всю строку. Некоторые файлы, которые я обрабатываю, представляют собой буквально огромные однострочные файлы, которые по-прежнему вызывают проблемы с памятью.
Это можно исправить с помощью fread
, с размером блока, скажем, 8192. Однако теперь текст, который я загружаю preg_replace
, может быть обрезанными многобайтовыми символами.
Я думал, как мне fread
сохранить многобайтовые символы, но пока не нашел хорошего решения. Любая помощь была бы потрясающей.
Возможное решение
Хотя я решил проблему другим способом, мне все еще любопытен мой исходный вопрос: как сделать mb-safe fread
? Я думаю, что такая функция могла бы работать:
- Прочитать кусок байтов с помощью
fread
- Проверьте последний байт, проверьте, является ли он частью многобайтовой последовательности. Если нет, остановитесь здесь.
- Продолжайте читать байты, пока последний байт не станет частью многобайтовой последовательности или не завершит текущую последовательность.
Шаг 2, вероятно, мог бы использовать некоторую логику вроде этой, но я не настолько разбираюсь в юникоде, как умею.
fgetc
является двоичным, а не многобайтовым. Он все равно будет разбиваться на многобайтовые символы. - person Peter Kruithof   schedule 17.10.2014