Подсчёт ошибок в большом логе за бюджет времени
Напишите numberOfErrors($errorCode), считающий строки большого log.txt, у которых второе поле (через ;) равно $errorCode. Файл слишком велик, чтобы загрузить в память, а скан должен остановиться по бюджету 100 мс.
<?php
class LogController {
public function numberOfErrors(int $errorCode): Response {
// ваш код здесь
}
}
Допишите реализацию.
Читайте файл построчно через fgets в цикле — память остаётся постоянной независимо от размера файла. Для каждой строки explode(';', ...) и сравнивайте поле с $errorCode. Считайте время через microtime(true) и break при превышении 100 мс. Важно fclose дескриптор (в эталоне он утекает) и учитывать, что бюджет даёт частичный результат.
- ✗Загрузка всего файла (
file,file_get_contents) вместо потока, что раздувает память - ✗Забыть
fclose, утекая файловый дескриптор (этот изъян есть в эталоне) - ✗Считать частичный результат по бюджету времени полным числом совпадений
- →Почему
fgetsпотребляет память константно, аfile()— пропорционально размеру файла? - →Как сделать частичный результат честным — вернуть флаг, что скан был прерван?
Большой файл нельзя грузить целиком — file() и file_get_contents() держат весь объём в памяти. Потоковое чтение через fgets забирает по одной строке, поэтому потребление памяти константно.
<?php
public function numberOfErrors(int $errorCode): Response {
$startAt = microtime(true);
$f = fopen('/log.txt', 'rb');
$count = 0;
while (($line = fgets($f)) !== false) {
$parts = explode(';', $line);
if (isset($parts[1]) && (int) $parts[1] === $errorCode) {
$count++;
}
if ((microtime(true) - $startAt) * 1000 > 100) {
break;
}
}
fclose($f); // эталон забывает это — дескриптор утекает
return new Response(json_encode(['found_errors' => $count]), 200);
}
Два честных замечания на собеседовании: исходный фрагмент не закрывает дескриптор (fclose), а отсечка по времени делает результат частичным — стоит вернуть флаг, что скан прерван.