-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[LazyStreamReader] Add LazyStreamReader
- Loading branch information
1 parent
9bd3039
commit 2d58098
Showing
9 changed files
with
275 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,3 +101,22 @@ class GoogleCloudStorageLazyStreamFactory | |
} | ||
} | ||
``` | ||
|
||
### Reading lazily a stream with `LazyStreamReader` | ||
|
||
Files are already read lazily by default: when you call `fread()`, you only fetch the number of bytes you asked for, not more. | ||
`LazyStreamReader` does the same thing, but it also allows you to keep the stream open or not between reading operations. | ||
|
||
For example, you may want to read a file 1MB by 1MB, and do some processing that may take some time each time. By setting the `autoClose` option to `true` when creating a new `LazyStreamReader` object, you ask to close the stream after each reading operation and open it again when the next reading operation is triggered. You'll be resumed at the same position you were in the stream before closing it. | ||
|
||
```php | ||
// The stream is not opened yet, in case you never need it | ||
$stream = new \LazyStream\LazyStreamReader('https://user:[email protected]/my-file.png', chunkSize: 1024, autoClose: true, binary: true); | ||
|
||
// Use the stream directly in the loop | ||
foreach ($stream as $str) { | ||
// With auto-closing, the stream is already closed here. You can | ||
// do any long operation, and the stream will be opened again when | ||
// you get in the next loop iteration | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<?php | ||
|
||
namespace LazyStream; | ||
|
||
use LazyStream\Exception\LazyStreamOpenException; | ||
|
||
abstract class AbstractLazyStream | ||
{ | ||
/** | ||
* @param resource|null $handle | ||
*/ | ||
protected $handle; | ||
|
||
protected ?array $metadata = null; | ||
|
||
public function __construct( | ||
protected string $uri, | ||
protected string $openingMode, | ||
) { | ||
} | ||
|
||
public function __destruct() | ||
{ | ||
$this->closeStream(); | ||
} | ||
|
||
protected function openStream(): void | ||
{ | ||
if (!\is_resource($this->handle)) { | ||
$this->handle = @\fopen($this->uri, $this->openingMode); | ||
|
||
if ($this->handle === false) { | ||
throw new LazyStreamOpenException($this->uri, $this->openingMode); | ||
} | ||
|
||
$this->metadata = \stream_get_meta_data($this->handle); | ||
} | ||
} | ||
|
||
protected function closeStream(): void | ||
{ | ||
if (\is_resource($this->handle)) { | ||
\fclose($this->handle); | ||
} | ||
|
||
$this->handle = null; | ||
} | ||
|
||
/** | ||
* @return resource|null | ||
*/ | ||
public function getStreamHandle() | ||
{ | ||
return $this->handle; | ||
} | ||
|
||
/** | ||
* @return array Stream meta-data array indexed by keys given in https://www.php.net/manual/en/function.stream-get-meta-data.php. | ||
*/ | ||
public function getMetadata(): array | ||
{ | ||
if ($this->metadata === null) { | ||
// If metadata is null, then we never opened the stream yet | ||
$this->openStream(); | ||
$this->closeStream(); | ||
} | ||
|
||
return $this->metadata; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
/* | ||
* (c) Alexandre Daubois <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace LazyStream; | ||
|
||
class LazyStreamReader extends AbstractLazyStream implements LazyStreamReaderInterface | ||
{ | ||
private int $position = 0; | ||
|
||
/** | ||
* @param string $uri A valid stream URI. | ||
* @param bool $autoClose Whether the stream should be closed between reading operations. | ||
*/ | ||
public function __construct( | ||
string $uri, | ||
private int $chunkSize, | ||
private bool $autoClose = true, | ||
private bool $binary = false, | ||
) { | ||
parent::__construct($uri, $this->binary ? 'rb' : 'r'); | ||
} | ||
|
||
public function getStreamPosition(): int | ||
{ | ||
return $this->position; | ||
} | ||
|
||
public function isAutoClose(): bool | ||
{ | ||
return $this->autoClose; | ||
} | ||
|
||
public function setAutoClose(bool $autoClose): void | ||
{ | ||
$this->autoClose = $autoClose; | ||
} | ||
|
||
public function getIterator(): \Generator | ||
{ | ||
yield from $this->read(); | ||
} | ||
|
||
private function read(): \Generator | ||
{ | ||
$this->openStream(); | ||
|
||
while (($data = \fread($this->handle, $this->chunkSize)) !== false && \strlen($data) !== 0) { | ||
$this->position += $this->chunkSize; | ||
|
||
if ($this->autoClose) { | ||
$this->closeStream(); | ||
yield $data; | ||
|
||
$this->openStream(); | ||
\fseek($this->handle, $this->position); | ||
|
||
continue; | ||
} | ||
|
||
yield $data; | ||
} | ||
|
||
$this->closeStream(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
/* | ||
* (c) Alexandre Daubois <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace LazyStream; | ||
|
||
interface LazyStreamReaderInterface extends \IteratorAggregate | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.