<?php // FileStream.php // Created: 2021-04-30 // Updated: 2024-07-31 namespace Index\IO; use ErrorException; class FileStream extends GenericStream { public const OPEN_READ = 'rb'; // O R E // Open file for reading, throw if not exists public const OPEN_READ_WRITE = 'r+b'; // O RW E // Open file for reading and writing, throw if not exist public const NEW_WRITE = 'wb'; // C W T // Create file for writing, truncate if exist public const NEW_READ_WRITE = 'w+b'; // C RW T // Create file for reading and writing, truncate if exist public const APPEND_WRITE = 'ab'; // OC A // Open file for appending, create if not exist public const APPEND_READ_WRITE = 'a+b'; // OC R A // Open file for reading and appending, create if not exist public const CREATE_WRITE = 'xb'; // C W T // Create file for writing, throw if exist public const CREATE_READ_WRITE = 'x+b'; // C RW T // Create file for reading and writing, throw if exist public const OPEN_OR_CREATE_WRITE = 'cb'; // OC W // Opens or creates a file for writing public const OPEN_OR_CREATE_READ_WRITE = 'c+b'; // OC RW // Opens or creates a file for reading and writing public const LOCK_NONE = 0; public const LOCK_READ = LOCK_SH; public const LOCK_WRITE = LOCK_EX; public const LOCK_NON_BLOCKING = LOCK_NB; private int $lock; public function __construct(string $path, string $mode, int $lock) { $this->lock = $lock; try { $stream = fopen($path, $mode); } catch(ErrorException $ex) { throw new IOException('An error occurred while trying to open a file.', $ex->getCode(), $ex); } if($stream === false) throw new IOException('An unhandled error occurred while trying to open a file.'); parent::__construct($stream); if($this->lock & self::LOCK_WRITE) flock($this->stream, LOCK_EX); elseif($this->lock & self::LOCK_READ) flock($this->stream, LOCK_SH); } public function close(): void { if($this->lock !== self::LOCK_NONE) flock($this->stream, LOCK_UN); parent::close(); } public static function openRead(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::OPEN_READ, $lock); } public static function openReadWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::OPEN_READ_WRITE, $lock); } public static function newWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::NEW_WRITE, $lock); } public static function newReadWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::NEW_READ_WRITE, $lock); } public static function appendWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::APPEND_WRITE, $lock); } public static function appendReadWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::APPEND_READ_WRITE, $lock); } public static function createWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::CREATE_WRITE, $lock); } public static function createReadWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::CREATE_READ_WRITE, $lock); } public static function openOrCreateWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::OPEN_OR_CREATE_WRITE, $lock); } public static function openOrCreateReadWrite(string $path, int $lock = self::LOCK_NONE): FileStream { return new FileStream($path, self::OPEN_OR_CREATE_READ_WRITE, $lock); } }