PHP
Обработка файлов
Поиск…
Синтаксис
- int readfile (строка $ filename [, bool $ use_include_path = false [, resource $ context]])
параметры
параметр | Описание |
---|---|
имя файла | Чтение имени файла. |
use_include_path | Вы можете использовать необязательный второй параметр и установить его в ИСТИНА, если вы хотите также искать файл в include_path. |
контекст | Ресурс контекстного потока. |
замечания
Синтаксис имени файла
Большинство имен файлов, переданных в функции в этом разделе:
- Строки в природе.
- Имена файлов могут передаваться напрямую. Если передаются значения других типов, они передаются в строку. Это особенно полезно с
SplFileInfo
, которое является значением в итерацииDirectoryIterator
.
- Имена файлов могут передаваться напрямую. Если передаются значения других типов, они передаются в строку. Это особенно полезно с
- Относительный или абсолютный.
- Они могут быть абсолютными. В Unix-подобных системах абсолютные пути начинаются с
/
, например/home/user/file.txt
, тогда как в Windows абсолютные пути начинаются с диска, напримерC:/Users/user/file.txt
- Они также могут быть относительными, что зависит от значения
getcwd
и может быть измененоchdir
.
- Они могут быть абсолютными. В Unix-подобных системах абсолютные пути начинаются с
- Принимать протоколы.
- Они могут начинаться со
scheme://
для указания обертки протокола для управления. Например,file_get_contents("http://example.com")
извлекает контент с сайта http://example.com .
- Они могут начинаться со
- Slash-совместимый.
- Хотя
DIRECTORY_SEPARATOR
в Windows - это обратная косая черта, и система по умолчанию возвращает обратную косую черту по умолчанию, разработчик все еще может использовать/
в качестве разделителя каталогов. Поэтому для совместимости разработчики могут использовать/
как разделители каталогов во всех системах, но имейте в виду, что значения, возвращаемые функциями (например,realpath
), могут содержать обратную косую черту.
- Хотя
Удаление файлов и каталогов
Удаление файлов
Функция unlink
удаляет один файл и возвращает, была ли операция успешной.
$filename = '/path/to/file.txt';
if (file_exists($filename)) {
$success = unlink($filename);
if (!$success) {
throw new Exception("Cannot delete $filename");
}
}
Удаление каталогов с рекурсивным удалением
С другой стороны, каталоги должны быть удалены с помощью rmdir
. Однако эта функция удаляет только пустые каталоги. Чтобы удалить каталог с файлами, сначала удалите файлы в каталогах. Если каталог содержит подкаталоги, может потребоваться рекурсия .
Следующий пример сканирует файлы в каталоге, рекурсивно удаляет файлы-члены / каталоги и возвращает количество удаленных файлов (не каталогов).
function recurse_delete_dir(string $dir) : int {
$count = 0;
// ensure that $dir ends with a slash so that we can concatenate it with the filenames directly
$dir = rtrim($dir, "/\\") . "/";
// use dir() to list files
$list = dir($dir);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($dir . $file)) {
unlink($dir . $file);
$count++;
} elseif(is_dir($dir . $file)) {
$count += recurse_delete_dir($dir . $file);
}
}
// finally, safe to delete directory!
rmdir($dir);
return $count;
}
Удобные функции
Прямой прямой ввод-вывод
file_get_contents
и file_put_contents
предоставляют возможность чтения / записи из / в файл в / из строки PHP за один раз.
file_put_contents
также могут использоваться с флагом FILE_APPEND
чтобы добавить, а не FILE_APPEND
и перезаписать файл. Он может использоваться вместе с LOCK_EX
для получения эксклюзивной блокировки файла при переходе к записи. Флаги битмаски могут быть объединены с |
бит-OR.
$path = "file.txt";
// reads contents in file.txt to $contents
$contents = file_get_contents($path);
// let's change something... for example, convert the CRLF to LF!
$contents = str_replace("\r\n", "\n", $contents);
// now write it back to file.txt, replacing the original contents
file_put_contents($path, $contents);
FILE_APPEND
удобен для добавления файлов журнала, в то время как LOCK_EX
помогает предотвратить состояние гонки при записи файлов из нескольких процессов. Например, чтобы записать в файл журнала о текущем сеансе:
file_put_contents("logins.log", "{$_SESSION["username"]} logged in", FILE_APPEND | LOCK_EX);
CSV IO
fgetcsv($file, $length, $separator)
fgetcsv
анализирует строку из проверки открытых файлов для полей csv. Он возвращает поля CSV в массиве с успехом или FALSE
при сбое.
По умолчанию он будет читать только одну строку файла CSV.
$file = fopen("contacts.csv","r");
print_r(fgetcsv($file));
print_r(fgetcsv($file,5," "));
fclose($file);
contacts.csv
Kai Jim, Refsnes, Stavanger, Norway
Hege, Refsnes, Stavanger, Norway
Выход:
Array
(
[0] => Kai Jim
[1] => Refsnes
[2] => Stavanger
[3] => Norway
)
Array
(
[0] => Hege,
)
Чтение файла прямо в stdout
readfile
копирует файл в выходной буфер. readfile () не представляет проблем с памятью, даже при отправке больших файлов, сам по себе.
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
Или из указателя файла
В качестве альтернативы, чтобы найти точку в файле, чтобы начать копирование в stdout, вместо этого используйте fpassthru
. В следующем примере последние 1024 байта копируются в stdout:
$fh = fopen("file.txt", "rb");
fseek($fh, -1024, SEEK_END);
fpassthru($fh);
Чтение файла в массив
file
возвращает строки в переданном файле в массиве. Каждый элемент массива соответствует строке в файле, а новая строка все еще прикреплена.
print_r(file("test.txt"));
test.txt
Welcome to File handling
This is to test file handling
Выход:
Array
(
[0] => Welcome to File handling
[1] => This is to test file handling
)
Получение информации о файле
Проверьте, является ли путь каталогом или файлом
Функция is_dir
возвращает, является ли аргумент каталогом, а is_file
возвращает, является ли аргумент файлом. Используйте file_exists
чтобы проверить, есть ли это.
$dir = "/this/is/a/directory";
$file = "/this/is/a/file.txt";
echo is_dir($dir) ? "$dir is a directory" : "$dir is not a directory", PHP_EOL,
is_file($dir) ? "$dir is a file" : "$dir is not a file", PHP_EOL,
file_exists($dir) ? "$dir exists" : "$dir doesn't exist", PHP_EOL,
is_dir($file) ? "$file is a directory" : "$file is not a directory", PHP_EOL,
is_file($file) ? "$file is a file" : "$file is not a file", PHP_EOL,
file_exists($file) ? "$file exists" : "$file doesn't exist", PHP_EOL;
Это дает:
/this/is/a/directory is a directory
/this/is/a/directory is not a file
/this/is/a/directory exists
/this/is/a/file.txt is not a directory
/this/is/a/file.txt is a file
/this/is/a/file.txt exists
Проверка типа файла
Используйте filetype
для проверки типа файла, который может быть:
-
fifo
-
char
-
dir
-
block
-
link
-
file
-
socket
-
unknown
Передача имени файла в filetype
файла напрямую:
echo filetype("~"); // dir
Обратите внимание, что filetype
возвращает false и запускает E_WARNING
если файл не существует.
Проверка читаемости и возможности записи
Передача имени файла в функции is_writable
и is_readable
проверяет, доступен ли файл для записи или чтения.
Функции возвращают false
изящно, если файл не существует.
Проверка времени доступа к файлу / изменения времени
Использование filemtime
и fileatime
возвращает метку времени последней модификации или доступа к файлу. Возвращаемое значение - это отметка времени Unix - подробности см. В разделе Работа с датами и временем .
echo "File was last modified on " . date("Y-m-d", filemtime("file.txt"));
echo "File was last accessed on " . date("Y-m-d", fileatime("file.txt"));
Получить части пути с помощью fileinfo
$fileToAnalyze = ('/var/www/image.png');
$filePathParts = pathinfo($fileToAnalyze);
echo '<pre>';
print_r($filePathParts);
echo '</pre>';
В этом примере будет выводиться:
Array
(
[dirname] => /var/www
[basename] => image.png
[extension] => png
[filename] => image
)
Который может использоваться как:
$filePathParts['dirname']
$filePathParts['basename']
$filePathParts['extension']
$filePathParts['filename']
параметр | подробности |
---|---|
$ путь | Полный путь к файлу, который нужно разобрать |
$ опция | Один из четырех доступных опций [PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION или PATHINFO_FILENAME] |
- Если параметр (второй параметр) не передается, ассоциативный массив возвращается, иначе возвращается строка.
- Не подтверждает, что файл существует.
- Просто анализирует строку на части. В файле не выполняется проверка (нет проверки типа mime и т. Д.).
- Расширение - это просто последнее расширение
$path
. Путь к файлуimage.jpg.png
будет.png
даже если это технически файл.jpg
. Файл без расширения не возвращает элемент расширения в массиве.
Минимизировать использование памяти при работе с большими файлами
Если нам нужно проанализировать большой файл, например, CSV более 10 Мбайт, содержащий миллионы строк, некоторые используют функции file
или file_get_contents
и заканчивают тем, что memory_limit
параметр memory_limit
с помощью
Допустимый размер памяти XXXXX байт исчерпан
ошибка. Рассмотрим следующий источник (top-1m.csv имеет ровно 1 миллион строк и составляет около 22 Мбайт)
var_dump(memory_get_usage(true));
$arr = file('top-1m.csv');
var_dump(memory_get_usage(true));
Эти результаты:
int(262144)
int(210501632)
потому что интерпретатору необходимо было держать все строки в $arr
массиве, поэтому он потреблял ~ 200 Мбайт ОЗУ. Обратите внимание, что мы ничего не сделали с содержимым массива.
Теперь рассмотрим следующий код:
var_dump(memory_get_usage(true));
$index = 1;
if (($handle = fopen("top-1m.csv", "r")) !== FALSE) {
while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) {
file_put_contents('top-1m-reversed.csv',$index . ',' . strrev($row[1]) . PHP_EOL, FILE_APPEND);
$index++;
}
fclose($handle);
}
var_dump(memory_get_usage(true));
которые выходят
int(262144)
int(262144)
поэтому мы не используем один лишний байт памяти, а анализируем весь CSV и сохраняем его в другом файле, изменяя значение второго столбца. Это потому, что fgetcsv
читает только одну строку, а $row
перезаписывается в каждом цикле.
Файл ввода-вывода с потоком
Открытие потока
fopen
открывает дескриптор потока файлов, который может использоваться с различными функциями для чтения, записи, поиска и других функций поверх него. Это значение относится к типу resource
и не может быть передано другим потокам, сохраняющим свою функциональность.
$f = fopen("errors.log", "a"); // Will try to open errors.log for writing
Второй параметр - это режим файлового потока:
Режим | Описание |
---|---|
r | Открыть в режиме только для чтения, начиная с начала файла |
r+ | Открыть для чтения и записи, начиная с начала файла |
w | открыт только для записи, начиная с начала файла. Если файл существует, он очистит файл. Если он не существует, он попытается создать его. |
w+ | открыт для чтения и записи, начиная с начала файла. Если файл существует, он очистит файл. Если он не существует, он попытается создать его. |
a | откройте файл только для записи, начиная с конца файла. Если файл не существует, он попытается создать его |
a+ | откройте файл для чтения и записи, начиная с конца файла. Если файл не существует, он попытается создать его |
x | создавать и открывать файл только для записи. Если файл существует, вызов fopen не будет завершен |
x+ | создавать и открывать файл для чтения и записи. Если файл существует, вызов fopen не будет завершен |
c | откройте файл только для записи. Если файл не существует, он попытается его создать. Он начнет писать в начале файла, но не удалит файл перед записью |
c+ | откройте файл для чтения и записи. Если файл не существует, он попытается его создать. Он начнет писать в начале файла, но не удалит файл перед записью |
Добавление t
за режим (например, a+b
, wt
и т. Д.) В Windows приведет к переводу окончаний строки "\n"
на "\r\n"
при работе с файлом. Добавьте b
за режим, если это не предназначено, особенно если это двоичный файл.
Приложение PHP должно закрывать потоки, используя fclose
когда они больше не используются для предотвращения Too many open files
ошибок Too many open files
. Это особенно важно в программах CLI, поскольку потоки закрываются только тогда, когда среда выполнения отключается - это означает, что на веб-серверах это может быть необязательно (но все же должно быть , как практика предотвращения утечки ресурсов), чтобы закрыть потоки если вы не ожидаете, что процесс будет работать в течение длительного времени и не откроет много потоков.
чтение
Использование fread
будет считывать заданное количество байтов из указателя файла или до тех пор, пока не будет выполняться EOF.
Линии чтения
Использование fgets
будет читать файл до тех пор, пока не будет достигнут EOL, или данная длина будет считана.
Как fread
и fgets
будут перемещать указатель файла во время чтения.
Чтение всего остального
Использование stream_get_contents
будет stream_get_contents
все оставшиеся байты в потоке в строку и вернуть ее.
Настройка позиции указателя на файл
Первоначально после открытия потока указатель файла находится в начале файла (или в конце, если используется режим a
). Использование функции fseek
переместит указатель файла на новую позицию относительно одного из трех значений:
-
SEEK_SET
: это значение по умолчанию; смещение позиции файла будет относиться к началу файла. -
SEEK_CUR
: смещение позиции файла будет относительно текущей позиции. -
SEEK_END
: смещение позиции файла будет относиться к концу файла. Передача отрицательного смещения является наиболее распространенным использованием для этого значения; он переместит позицию файла в указанное количество байт до конца файла.
rewind
- это удобный ярлык для fseek($fh, 0, SEEK_SET)
.
Использование ftell
покажет абсолютную позицию указателя файла.
Например, следующий скрипт читает пропускает первые 10 байт, читает следующие 10 байт, пропускает 10 байтов, читает следующие 10 байт, а затем последние 10 байтов в файле .txt:
$fh = fopen("file.txt", "rb");
fseek($fh, 10); // start at offset 10
echo fread($fh, 10); // reads 10 bytes
fseek($fh, 10, SEEK_CUR); // skip 10 bytes
echo fread($fh, 10); // read 10 bytes
fseek($fh, -10, SEEK_END); // skip to 10 bytes before EOF
echo fread($fh, 10); // read 10 bytes
fclose($fh);
Пишу
Использование fwrite
записывает предоставленную строку в файл, начинающийся с текущего указателя файла.
fwrite($fh, "Some text here\n");
Перемещение и копирование файлов и каталогов
Копирование файлов
copy
копирует исходный файл в первом аргументе к месту назначения во втором аргументе. Разрешенное место назначения должно быть в каталоге, который уже создан.
if (copy('test.txt', 'dest.txt')) {
echo 'File has been copied successfully';
} else {
echo 'Failed to copy file to destination given.'
}
Копирование каталогов с рекурсией
Копирование каталогов во многом аналогично удалению каталогов, за исключением того, что для copy
файлов используется вместо unlink
, тогда как для каталогов используется mkdir
вместо rmdir
, в начале вместо того, чтобы быть в конце функции.
function recurse_delete_dir(string $src, string $dest) : int {
$count = 0;
// ensure that $src and $dest end with a slash so that we can concatenate it with the filenames directly
$src = rtrim($dest, "/\\") . "/";
$dest = rtrim($dest, "/\\") . "/";
// use dir() to list files
$list = dir($src);
// create $dest if it does not already exist
@mkdir($dest);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($src . $file)) {
copy($src . $file, $dest . $file);
$count++;
} elseif(is_dir($src . $file)) {
$count += recurse_copy_dir($src . $file, $dest . $file);
}
}
return $count;
}
Переименование / Перемещение
Переименование / перемещение файлов и каталогов намного проще. Целые каталоги могут быть перемещены или переименованы в один вызов, используя функцию rename
.
rename("~/file.txt", "~/file.html");
rename("~/dir", "~/old_dir");
rename("~/dir/file.txt", "~/dir2/file.txt");