Чат PHP-разработчиков
Работа с файлами в PHP

Учимся работать с файлами в PHP

В данном уроке мы рассмотрим несколько способов работы с файлами в PHP, а также поговорим о преимуществах и недостатках каждого из них.

Построчное чтение из файла

Для начала давайте научимся читать файлы. Давайте создадим текстовый файл file.txt и запишем в него следующий текст:

Код доступен только после покупки курса PHP для начинающих.

Давайте теперь считаем его с помощью программы на языке php. Создайте файл files.php и запишите в него следующий код:

Код доступен только после покупки курса PHP для начинающих.

Если вы сейчас запустите этот скрипт, то увидите на экране четверостишие из файла.

Построчное чтение файла на PHP

Давайте теперь разберём по шагам нашу программу.

  1. Функция fopen открывает файл. Первым аргументом указывается путь до файла, вторым аргументом указывается режим для работы с файлом. В нашем случае это 'r' – чтение (от read). Ознакомьтесь с другими режимами работы в документации по функции. Данная функция возвращает ресурс — это еще один тип данных, с которым мы ранее не работали. Ресурс в PHP – это ссылка на какой-то внешний ресурс (файл, база данных и т. п.). Работа с ресурсами происходит с помощью специальных функций. Более детально о ресурсах вы можете прочитать тут.
  2. В цикле for четыре раза вызывается функция fgets. Эта функция считывает строку из файла и перемещает текущий курсор на следующую строку (курсор можете представить себе как обычный курсор в текстовом редакторе, который просто перемещается в момент считывания данных из файла). Если снова вызвать эту функцию, она сделает то же самое для следующей строки. Возвращает эта функция считанную строку (string).
  3. Ресурс закрывается с помощью функции fclose. Делать это следует всегда, несмотря на то, что PHP по завершении работы программы сделает это сам. Дело в том, что если открыть файл в блокирующем режиме (например, для записи, в режиме 'w'), то он будет недоступен для других процессов, они будут ждать, пока предыдущий ресурс освободит этот файл.

Как вы понимаете, для чтения не очень удобно использовать цикл for с указанием конкретного числа строк, которые необходимо считать. Для этого можно использовать функцию feof – она возвращает true, если достигнут конец файла, и false – если нет.

На вход в качестве аргумента она принимает ресурс файла. Программа, переписанная с использованием функции feof будет выглядеть следующим образом:

Код доступен только после покупки курса PHP для начинающих.

Цикл будет выполняться до тех пор, пока не достигнут конец файла. При этом функция fgets каждый раз сдвигает курсор на следующую строку. Как только курсор достигнет конца файла, цикл завершится. Таким образом мы не привязаны к числу строк и можем читать файл не задумываясь об этом.

Построчная запись в файл

Теперь запишем данные в файл. Для того чтобы открыть файл для записи используется та же функция fopen, только в качестве режима работы указывается 'w' (от write).

А для записи в файл строки используется функция fputs(). Первым аргументом указывается ресурс, а вторым — строка, которую необходимо записать в файл. Давайте в качестве примера напишем программу, которая запишет в файл file2.txt числа от 1 до 100.

Код доступен только после покупки курса PHP для начинающих.

Константа PHP_EOL содержит в себе символ переноса строки. При этом для разных операционных систем (Windows или Unix-подобных) эти символы будут разными.

Дозаписываем в конец файла

При этом если сейчас запустить программу снова, то старые данные в файле file2.txt перезапишутся новыми. Для того, чтобы сохранить содержимое файла и дозаписать данные в конец, нужно использовать режим работы с файлом “a” (от append – присоединять, добавлять).

Код доступен только после покупки курса PHP для начинающих.

Если мы запустим этот скипт дважды, то в файле file3.txt будет две строки “abc”.

Читаем файл целиком

В PHP также имеется возможность прочитать весь файл за раз. Для этого используется функция file_get_contents().

Код доступен только после покупки курса PHP для начинающих.

Данный код выведет всё то же четверостишие, только без переноса строк.

Чтение файла целиком на PHP

Так произошло потому, что в самом первом примере мы добавляли тег <br> после каждой прочитанной строки. Если же мы откроем исходный код страницы, то увидим, что на самом деле переносы строк в исходном коде сохранены.

Исходник прочитанного файла

Запись в файл данных целиком

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

Код доступен только после покупки курса PHP для начинающих.

Если снова запустить этот код, файл перезапишется. Для того, чтобы дополнить файл у этой функции есть третий аргумент — режим работы с файлом. Для дозаписи в конец файла следует использовать константу FILE_APPEND.

Код доступен только после покупки курса PHP для начинающих.

Какой способ выбрать

Данные способы отличаются в первую очередь тем, что когда мы считываем файл целиком, или записываем в него много данных за раз, нам приходится хранить в оперативной памяти больше данных, чем если бы мы работали по отдельности с каждой строкой. Если данных не слишком много, об этом можно не беспокоиться. Однако, если вы читаете файл размером 10 Гб, а на компьютере, на котором выполняется скрипт, всего 4Гб оперативной памяти, то его получится считать только построчно. При попытке загрузить его целиком программа упадёт с ошибкой о нехватке памяти.

Домашнее задание
  1. Напишите программу, которая выводит свой собственный код.
    Сделайте так, чтобы в этой программе не было упоминания имени самого скрипта (если программа лежит в файле homework.php, то упоминания homework.php не должно быть в исходнике).

  2. Выведите список всех файлов в текущей директории скрипта.
    Создайте теперь в директории со скриптом несколько папок.
    Сделайте так, чтобы в списке, выводимом программой, остались только папки.
Читайте также
Комментарии (36)


1nSide

1 задача, сделал запись в фаил чисел от 100 до 1 и вывод их из этого файла

$file = fopen(__DIR__ . '/file4.txt', 'w');
for ($i = 100; $i>= 1; $i--) {
    fputs($file, $i . PHP_EOL);
}

$file = fopen(__DIR__ . '/file4.txt', 'r');
while (!feof($file)) {
    echo fgets($file);
    echo '<br>';
}
fclose($file);
ivashkevich

А зачем? Нужно было написать скрипт, который выводит свой собственный код.

1nSide

2 задачу не понял как делать

ivashkevich

Что именно не поняли? На каком пункте?

AnatolyMartyanov

1 задание

<?php
$file = file_get_contents(__FILE__);
echo $file;

или

<?php
$file = fopen(__FILE__ , 'r');
while  (!feof($file)) {
    echo fgets($file);
    echo '<br>';
}
ivashkevich

Отлично ;)
А можно было вообще написать echo file_get_contents... без использования переменных

AnatolyMartyanov

Понял, спасибо

lig7771991@list.ru

Первый вариант у меня ничего не выводит на экран, только второй...

Pavel-Tonk

У меня та же проблема.

AnatolyMartyanov

2 задание

$dir = '../file';
$files = scandir($dir);
foreach ($files as $file) {
    echo $file . '<br>';
}

foreach ($files as $dirr) {
    if (is_dir($dirr)) {
        echo $dirr . '<br>';
    }
}
ivashkevich

Тут всё хорошо, но нужно использовать константу __DIR__

DmitryGavrilov
<?php
//Выведите список всех файлов в текущей директории скрипта.
//Создайте теперь в директории со скриптом несколько папок.
//Сделайте так, чтобы в списке, выводимом программой, остались только папки.

//выводим файлы
$files = scandir(__DIR__ . '/');
foreach ($files as $file) {
echo $file . '<br>';
}

//выводим папки как папки, прокольно что есть is_dir)
$files = scandir(__DIR__ . '/');
foreach ($files as $dirr) {
    if (is_dir($dirr)) {
        echo $dirr . '<br>';
    }
}

?>
ivashkevich

Всё хорошо.

Закрывающий тег ?> в конце не нужен.

rusgil

Во примерах для открытия файлов и includ'ах используется DIR.
А зачем нужен абсолютный путь, почему не воспользоваться относительным?
В чем разница относительных и абсолютных путей?

ivashkevich

Потому что константа __DIR__ содержит путь до директории с файлом, в котором она написана. А если мы внутри /index.php подключим файл в папке /inc/123.php, в котором будет ещё один include, то он сработает относительно того файла, который мы запустили, а не в котором этот include написан. То есть если в /inc/123.php будет код:

include '456.php';

То подключится не файл /inc/456.php, а /456.php. Не в одной директории с файлом где написан include, а в одной директории с файлом, к которому мы обратились (/index.php).

Использование __DIR__ эту проблему решает.

Fox-24

Привет! Благодарю за урок!) Все супер)

1.

<?php
// Напишите программу, которая выводит свой собственный код.
// Сделайте так, чтобы в этой программе не было упоминания имени самого скрипта
// (если программа лежит в файле homework.php, то упоминания homework.php не должно быть в исходнике).

$file = fopen(__FILE__, 'r');
while (!feof($file)) {
    echo fgets($file);
    echo '<br>';
}
fclose($file);

2.

<?php
// Выведите список всех файлов в текущей директории скрипта.
$dir = __DIR__ . '/';
$files = scandir($dir);

foreach ($files as $value) {
    echo $value . '</br>';
}

3. Тут я немного больше сделал:)

<?php
// Создайте теперь в директории со скриптом несколько папок.
// Сделайте так, чтобы в списке, выводимом программой, остались только папки.

// Массив с именами новых папок
$newfolders = ['folder-1', 'folder-2', 'folder-3'];

// Если папки еще не существуют, создаем новые
foreach ($newfolders as $folder) {
    if (!is_dir($folder)) {
        mkdir($folder, 0700);
    }
}

// Задаем директорию и получаем массив с файлами
$dir = __DIR__ . '/';
$files = scandir($dir);

// Выводит список всех папок
foreach ($files as $value) {
    if (is_dir($value))
        echo $value . '</br>';
}
ivashkevich

Отлично =)

dom1r
  1. Мне показалось через fgets лучше, т.к он построчно выводит, а file_get_contents через пробел
<?php
echo "hello";

$file = fopen(__FILE__, 'r');
while (!feof($file)) {
    echo fgets($file);
    echo '<br>';
}
fclose($file);

2.

<?php
//выводит список файлов без директории
$filelist = [];

if ($handle = opendir(__DIR__)) {
    while (false !== ($entry = readdir($handle))) {
        if (is_file($entry)) {
            $filelist[] = $entry;
        }
    }

    closedir($handle);
}

print_r($filelist);
<?php
//выводит список папок
$filelist = [];

if ($handle = opendir(__DIR__)) {
    while (false !== ($entry = readdir($handle))) {
        if (is_dir($entry)) {
            $filelist[] = $entry;
        }
    }

    closedir($handle);
}

print_r($filelist);
ivashkevich
  1. Строки схлопывает браузер, если посмотрите исходный код страницы, то увидите переносы строк. В Вашем варианте новые строки выводятся из-за ручного добавления тега <br> после каждой строки. Также можно было весь вывод обернуть в тег <pre>.
  2. Хорошо
  3. Хорошо
ArtemijeKA
  1. $file = fopen($_SERVER['SCRIPT_FILENAME'], 'rb');
    while (!feof($file)) {
        echo fgets($file);
        echo '<br>';
    }
    fclose($file);
  2. $listFiles = array_diff(scandir(__DIR__), array('..', '.'));
    foreach ($listFiles as $fileName) {
        echo $fileName;
        echo '<br>';
    }
  3. $listFiles = array_diff(scandir(__DIR__), array('..', '.'));
    foreach ($listFiles as $fileName) {
        if (is_file($fileName)) {
            continue;
        }
        echo $fileName;
        echo '<br>';
    }

Спасибо за уроки!

ivashkevich

Хорошо, но:

  1. для получения пути до скрипта лучше использовать константу __FILE__, так как $_SERVER['SCRIPT_FILENAME'] не всегда покажет скрипт, в котором этот код написан.
  2. вместо array(1, 2) уже давно принято использовать запись [1, 2] - переучивайтесь.
ArtemijeKA

А когда $_SERVER['SCRIPT_FILENAME'] не покажет текущий файл? Когда вставлен в файле через require ?

Benya
<?php
$data = htmlspecialchars(file_get_contents(__FILE__));
echo $data;
Benya
<?php
$files = scandir(__DIR__ . '/');
foreach ($files as $file) {
    if (is_dir($file)) {
        echo $file . '<br>';
    }
}
SBTesla
$file = fopen(__FILE__ , 'r');
while (!feof($file)) {
    echo fgets($file);
    echo '<br>';
}

fclose($file);
//--------------------------------------------------

$dir = __DIR__. '/';
$file = scandir($dir);

foreach ($file as $value) {
    echo $value. '<br>';
}
demyanovpaul@yandex.ru

Напишите программу, которая выводит свой собственный код.
Сделайте так, чтобы в этой программе не было упоминания имени самого скрипта (если программа лежит в файле homework.php, то упоминания homework.php не должно быть в исходнике).

echo file_get_contents(__FILE__);

Выведите список всех файлов в текущей директории скрипта.
Создайте теперь в директории со скриптом несколько папок.
Сделайте так, чтобы в списке, выводимом программой, остались только папки.

foreach(scandir(__DIR__ . '/') as $file)
    if(is_dir($file))
        echo $file . '<br>';
ivashkevich

1 - ОК.
2 - НЕ ОК. Используйте фигурные скобки для тела цикла и условий! Это стандарт в мире PHP. Вам рановато про это читать, но раз уж игнорируете мои комментарии, то почитайте вот это =)

demyanovpaul@yandex.ru
foreach(scandir(__DIR__ . '/') as $file){
    if(is_dir($file)){
        echo $file . '<br>';
    }
}

Извините, старые привычки засели глубоко)Я читал, просто не увидел)
Я читал PSR. Это у меня от другого языка въелось)

ivashkevich

Понял, ок)

virtual2018

задача 1

//в случае php/html файла без обработки функцией htmlspecialchars, будет пустая страница
//необходимо преобразовать в html сущности
$data = htmlspecialchars(file_get_contents(__FILE__));
echo $data;

задача 2 - список файлов

if ($array_file = scandir(__DIR__)) {
    foreach ($array_file as $index) {
        if (is_file($index)) {
            echo '<br>' . $index;
        }
    }
}

задача 2.1 - список директорий

if ($array_file=scandir(__DIR__)) {
    foreach ($array_file as $index) {
        // отсеим стандартные указатели на текущую и вышестоящую диреторию
        if (is_dir($index) && $index != '.' && $index != '..') {
            echo '<br>'.$index;
        }
    }
}
Популярное за сутки
Сейчас читают
Логические задачи с собеседований