-
metrik
Доброго времени суток.
Дано: текстовый файл большого размера (от 100 мб например).
Задача: например заменить, удалить, дописать например где нибудь в середине файла.
Вопрос выглядит просто, но до сих пор не нашел изящного решения.
Какие пути решения были предприняты:
- Использовать классические методы работы через file, file_get_contents и т.п.;
- Использовать команду оболочки , например "grep" (хотя это уже не совсем по теме);
- Использовать второй файл в качестве буфера, в который можно формировать новое готовое состояние исправляемой информации.
Итого по пунктам:
- работает медленно и съедает очень много памяти - не вариант;
- Не вариант, по той причине, что код может выполняться и на "виндовой" машине. Работает быстро, использовать получается только на удаление строк.
- Файл читаю построчно через feof. Поиск данных проводится более менее с приемлемой скоростью и память не ест как в случае с п.1. Но зато рождает второй большой файл.. и если изменений много и они не последовательны , то опять сам процесс очень долгий по продолжительности
Кто что посоветует, кто сталкивался?
-
Distructor
- Администратор
Как вариант, если структура файла позволяет, то хранить его данные в СУБД.
Но если обязательно в файлах, то имхо лучше средствами ос делать
для примера
- замена подстроки в файле
- для linux
Код: Выделить всё
sed -i 's/что ищем/на что меняем/' /path/source.file
- для windows (bat-файл)
Код: Выделить всё
@echo off
setlocal enabledelayedexpansion
Set infile=source.file
set outfile=result.file
:: "что ищем" "на что меняем"
call :1 "PROG_DIR" "DIR_PROG"
call :1 "PROG_NAME" "NAME_PROG"
exit /b
:1
for /f "tokens=1* delims=]" %%a in ('find /v /n "" ^<"%infile%"') do (
if not "%%b"=="" (set line=%%b) else (set line=not)
set newline=!line:%~1=%~2!
set newline=!newline:not=!
echo.!newline!>>%outfile%
)
set infile=%outfile%
goto :eof
- удаление (ищем целую строку, соответствующую искомой)
Код: Выделить всё
sed -i '/^Ваша строка$/d' /path/source.file
причем sed есть и под windows (
http://gnuwin32.sourceforge.net/packages/sed.htm) //
Описание использования
-
metrik
Distructor писал(а):Как вариант, если структура файла позволяет, то хранить его данные в СУБД.
Но если обязательно в файлах, то имхо лучше средствами ос делать
...
причем sed есть и под windows
Спасибо за ответ, приму к сведению. Наверное лучшее решение тогда действительно перегонять данные в БД.
Хотя это опять же не является изящным решением (требует лишних манипуляций по перегону информации в БД, а в остальных случаях стороннего ПО) и не отвечает на вопрос поставленный в заголовке и описании ("работа с большими файлами
силами ПХП").
-
Distructor
- Администратор
metrik писал(а): и не отвечает на вопрос поставленный в заголовке и описании ("работа с большими файлами силами ПХП").
Код: Выделить всё
<?php
$result = exec("sed -i 's/что ищем/на что меняем/' /path/source.file");
кстати так и не упоминалось, что за данные в файле?
если нормальный csv, то в MySQL можно импортировать
одной командой Код: Выделить всё
LOAD DATA INFILE '/tmp/source.txt' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
обратная операция делается аналогично
Код: Выделить всё
SELECT * INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' FROM test;
если нужно решение без использования вызова внешних программ и использования БД, то вариант с feof оптимальный.
-
metrik
Вот и работаю по 3му варианту. Хочу немного удивился, что нет в PHP функций для внесения или замены данных в файле по смещению указателя
Distructor писал(а):кстати так и не упоминалось, что за данные в файле?
Идентификаторы и цены с разделителем
-
Distructor
- Администратор
metrik писал(а):Идентификаторы и цены с разделителем
стоит попробовать вариант с БД.
импорт, актуализация и экспорт должны выполняться как минимум раз в 10 быстрее чем вариант с чтением файла.
а если не будет необходимости каждый раз грузить файл (т.е. если следующую актуализацию файла надо делать относительно прошлой),
то выигрыш будет еще больше.