Nette Documentation Preview

syntax
Nette SafeStream
****************

.[perex]
Nette SafeStream гарантирует, что каждая операция чтения и записи файла происходит изолированно. Это значит, что ни один поток не начнёт читать файл, который ещё не дописан до конца, и что несколько потоков не перезапишут один и тот же файл.

Установка:

```shell
composer require nette/safe-stream
```


Для чего это нужно?
-------------------

Для чего вообще нужны изолированные операции? Начнём с простого примера, который многократно записывает в файл, а затем читает из него ту же строку:

```php
$s = str_repeat('Long String', 10000);

$counter = 1000;
while ($counter--) {
	file_put_contents('file', $s); // записываем
	$readed = file_get_contents('file'); // читаем
	if ($s !== $readed) { // проверяем
		echo 'strings are different!';
	}
}
```

Может показаться, что вызов `echo 'strings are different!'` никогда не произойдёт. Всё наоборот. Попробуйте запустить этот скрипт одновременно в двух вкладках браузера. Ошибка появится почти сразу.

Одна из вкладок прочитает файл в момент, когда другая ещё не дописала его целиком, так что содержимое будет неполным.

Поэтому код небезопасен, если выполняется несколько раз одновременно (то есть в нескольких потоках). В интернете это не редкость, потому что серверы часто отвечают большому количеству пользователей одновременно. Обеспечить, чтобы ваше приложение надёжно работало и при выполнении в нескольких потоках (было потокобезопасным), принципиально важно. Иначе может произойти потеря данных и возникнут труднообнаружимые ошибки.

Однако, как видите, нативные функции PHP для чтения и записи файлов не изолированы и не атомарны.


Как использовать SafeStream?
----------------------------

SafeStream создаёт безопасный протокол, через который файлы можно читать и записывать изолированно обычными функциями PHP. Достаточно снабдить имя файла приставкой `nette.safe://`:

```php
file_put_contents('nette.safe://file', $s);
$s = file_get_contents('nette.safe://file');
```

SafeStream обеспечивает, что записывать в файл одновременно может не более одного потока. Остальные потоки ждут в очереди. Если ни один поток не пишет, читать файл параллельно может сколько угодно потоков.

С протоколом можно использовать все обычные функции PHP, например:

```php
// 'r' означает открыть только для чтения
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://config.ini');
```


Ограничения
-----------

SafeStream изолирует чтение и запись содержимого файлов, но не может сделать атомарной каждую операцию. Помните об этих границах:

- **Сведения о файле не изолированы.** Функции, которые только запрашивают метаданные, например `file_exists()`, `filesize()` или `is_file()`, в блокировке не участвуют. Они могут вернуть сведения о файле, который другой поток как раз записывает.
- **Удаление открытого файла в Windows.** В отличие от Unix, Windows не позволяет удалить файл, который другой поток в данный момент держит открытым, так что `unlink('nette.safe://file')` может дать сбой.
- **Автоматический откат незавершённой записи.** Если запись прерывается на середине (например, кончается место на диске), то при закрытии файла SafeStream обрезает его обратно до размера, который был до начала записи, так что частично записанных данных он никогда не оставляет.

Если вы переходите на более новую версию, посмотрите страницу [обновления |upgrading].


{{sitename: Документация Nette}}

Nette SafeStream

Nette SafeStream гарантирует, что каждая операция чтения и записи файла происходит изолированно. Это значит, что ни один поток не начнёт читать файл, который ещё не дописан до конца, и что несколько потоков не перезапишут один и тот же файл.

Установка:

composer require nette/safe-stream

Для чего это нужно?

Для чего вообще нужны изолированные операции? Начнём с простого примера, который многократно записывает в файл, а затем читает из него ту же строку:

$s = str_repeat('Long String', 10000);

$counter = 1000;
while ($counter--) {
	file_put_contents('file', $s); // записываем
	$readed = file_get_contents('file'); // читаем
	if ($s !== $readed) { // проверяем
		echo 'strings are different!';
	}
}

Может показаться, что вызов echo 'strings are different!' никогда не произойдёт. Всё наоборот. Попробуйте запустить этот скрипт одновременно в двух вкладках браузера. Ошибка появится почти сразу.

Одна из вкладок прочитает файл в момент, когда другая ещё не дописала его целиком, так что содержимое будет неполным.

Поэтому код небезопасен, если выполняется несколько раз одновременно (то есть в нескольких потоках). В интернете это не редкость, потому что серверы часто отвечают большому количеству пользователей одновременно. Обеспечить, чтобы ваше приложение надёжно работало и при выполнении в нескольких потоках (было потокобезопасным), принципиально важно. Иначе может произойти потеря данных и возникнут труднообнаружимые ошибки.

Однако, как видите, нативные функции PHP для чтения и записи файлов не изолированы и не атомарны.

Как использовать SafeStream?

SafeStream создаёт безопасный протокол, через который файлы можно читать и записывать изолированно обычными функциями PHP. Достаточно снабдить имя файла приставкой nette.safe://:

file_put_contents('nette.safe://file', $s);
$s = file_get_contents('nette.safe://file');

SafeStream обеспечивает, что записывать в файл одновременно может не более одного потока. Остальные потоки ждут в очереди. Если ни один поток не пишет, читать файл параллельно может сколько угодно потоков.

С протоколом можно использовать все обычные функции PHP, например:

// 'r' означает открыть только для чтения
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://config.ini');

Ограничения

SafeStream изолирует чтение и запись содержимого файлов, но не может сделать атомарной каждую операцию. Помните об этих границах:

  • Сведения о файле не изолированы. Функции, которые только запрашивают метаданные, например file_exists(), filesize() или is_file(), в блокировке не участвуют. Они могут вернуть сведения о файле, который другой поток как раз записывает.
  • Удаление открытого файла в Windows. В отличие от Unix, Windows не позволяет удалить файл, который другой поток в данный момент держит открытым, так что unlink('nette.safe://file') может дать сбой.
  • Автоматический откат незавершённой записи. Если запись прерывается на середине (например, кончается место на диске), то при закрытии файла SafeStream обрезает его обратно до размера, который был до начала записи, так что частично записанных данных он никогда не оставляет.

Если вы переходите на более новую версию, посмотрите страницу обновления.