Writing
Determine if Writable
The isWritable()
determines if a stream is writable or not.
$a = FileStream::open('people.txt', 'r+b');
$b = FileStream::open('contacts.txt', 'rb');
echo $a->isWritable(); // true
echo $b->isWritable(); // false
Write
Use the write()
method to write data to the stream.
The method returns amount of bytes written to the stream.
$stream = FileStream::openTemporary();
$bytes = $stream->write('abc');
echo $bytes; // 3
Behind the scene, PHP's fwrite()
is used for writing data to the stream.
Write Formatted
If you want to write data using a specific format, then you can use the writeFormatted()
method.
The method accepts a $format
argument, as specified by PHP's fprintf()
, and an arbitrary amount of values.
Similar to write()
, this method also returns the amount of bytes written to the stream.
$stream = FileStream::openTemporary();
$greetings = 'Hi there';
$name = 'John';
$bytes = $stream->writeFormatted('%s <<%s>>', $greetings, $name);
echo $bytes; // 16
echo (string) $stream; // Hi there <<John>>
Put
Alternatively, you can use the put()
method to write data to a stream. This method is a "fluent" version of write()
.
$stream = FileStream::openTemporary()
->put('a')
->put('b')
->put('c');
echo (string) $stream; // abc
Put Formatted
putFormatted()
is a "fluent" version of the writeFormatted()
method.
$stream = FileStream::openTemporary();
$a = 'Hi there';
$b = 'John';
$c = 'Smith'
$stream
->putFormatted('%s ', $a)
->putFormatted('<<%s ', $b)
->putFormatted('%s>>', $c);
echo (string) $stream; // Hi there <<John Smith>>
Append
The append()
method is able to add data, at the end of the stream, if the stream is seekable. If the stream is not seekable, then a StreamNotSeekable
exception will be thrown.
The method accepts four arguments:
$data
: Data to be appended.int|null $length
: (optional) Maximum bytes to append. By default, all bytes left in$data
are appended.int $offset
: (optional) The offset where to start to copy data (offset on$data
).int|null $maximumMemory
: (optional) Maximum amount of bytes, before writing to a temporary file. (Defaults to 2 MB if not specified).
The $maximumMemory
argument is relevant when $data
is a pure string, or numeric. If that is the case, then the append()
method will wrap the $data
into a "temporary" stream internally, before reading from it.
$stream = FileStream::open('people.txt', 'r+b')
->append("\nJohn");
Behind the scene, PHP's stream_copy_to_stream()
is used to append.
Append Resource
To append data from a resource, pass in the resource as the $data
argument.
$resource = fopen('contacts.txt', 'r');
$stream = FileStream::open('people.txt', 'r+b')
->append($resource);
Append Stream
You may also append directly from another stream.
$from = FileStream::open('contacts.txt', 'r');
$stream = FileStream::open('people.txt', 'r+b')
->append($from);
Caution
When pure PSR-7 StreamInterface
is appended
If you choose to append from pure "PSR stream" (a stream that inherits from StreamInterface
, but not from \Aedart\Contracts\Streams\Stream
), then the given "data" stream is automatically detached.
$stream = FileStream::open('people.txt', 'r+b')
->append($psrStream);
// Attempt using "psr stream" after it was appended...
$psrStream->rewind(); // Invalid - Exception is thrown
The reason for this behavior is due to the limitation of PSR-7's defined StreamInterface
. There is no safe way to obtain a reference to the underlying resource, without detaching it. PHP's native stream_copy_to_stream()
can therefore not be applied. One would have to "manually" read the "data" stream, and add chunks of data manually. Such could impact performance significantly.
Workaround
To avoid loosing reference to the underlying resource, of the given "data" stream, you SHOULD wrap it into a Stream
component provided by this package, using the makeFrom()
method.
// Detached "PSR stream" and wrapped into FileStream
$from = FileStream::makeFrom($psrStream);
$stream = FileStream::open('people.txt', 'r+b')
->append($from);
$from->rewind(); // Stream rewound
Copy
In situations when you wish to copy the stream, then you can use the copy()
method.
This method will create a new "temporary" stream via openTemporary()
.
It accepts optional $length
and $offset
as arguments.
$stream = FileStream::open('my-file.txt', 'r+b')
->put('abc')
->positionToStart();
$copyA = $stream->copy();
$copyB = $stream
->positionToStart()
->copy(1, 1);
echo $copyA; // abc
echo $copyB; // b
Note
The initial stream's position is affected by the copy()
method.
Behind the scene, PHP's stream_copy_to_stream()
is used for the copy operation.
Copy To Target
If you wish to copy a stream into a specific target stream, then use the copyTo()
method.
It accepts a $target
stream, $length
and $offset
as optional arguments.
$stream = FileStream::open('my-file.txt', 'r+b')
->put('abc')
->positionToStart();
$target = FileStream::open('target.txt', 'r+b');
$copy = $stream->copyTo($target, 1, 1);
echo ($copy === $target); // true
echo (string) $copy; // b