diff --git a/.gitIgnore b/.gitIgnore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitIgnore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/README.md b/README.md index 3121a45..fd3d085 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # binary -Lightweight tool to read/write tons of data directly in file, skipping memory usage +Lightweight tool to read/write tons of data directly in file, skipping memory usage \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ececb30 --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "vvval/binary", + "description": "Lightweight tool to read/write tons of data directly in file, skipping memory usage", + "authors": [ + { + "name": "Valentin V / vvval", + "email": "vintsukevich@gmail.com" + } + ], + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "autoload": { + "psr-4": { + "Vvval\\Binary\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Vvval\\Binary\\Tests\\": "tests" + } + } +} \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..94dc2bd --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + \ No newline at end of file diff --git a/src/BinaryGenerator.php b/src/BinaryGenerator.php new file mode 100644 index 0000000..7d21481 --- /dev/null +++ b/src/BinaryGenerator.php @@ -0,0 +1,200 @@ +handler)) + { + throw new HandlerException("Binary generator has already started with \"$this->filename\" file."); + } + + $this->compression = $compression; + + return $this; + } + + /** + * @param $filename + * @param $mode + * @throws HandlerException + */ + public function start($filename, $mode) + { + $this->mode = $mode; + $this->filename = $filename; + + if (!empty($this->handler)) + { + throw new HandlerException("Binary generator has already started with \"$this->filename\" file."); + } + + if (!empty($this->compression)) + { + $this->handler = gzopen($this->filename, $this->mode); + } + else + { + $this->handler = fopen($this->filename, $this->mode); + } + + if (empty($this->handler)) + { + throw new HandlerException("Error during opening \"$this->filename\" file."); + } + } + + /** + * + */ + public function finish() + { + if (!empty($this->handler)) + { + if (!empty($this->compression)) + { + gzclose($this->handler); + } + else + { + fclose($this->handler); + } + + $this->handler = null; + } + } + + /** + * @param $data + * @return int + * @throws HandlerException + * @throws WriteDataException + */ + public function writeData($data) + { + if (!$this->isWriteMode()) + { + throw new WriteDataException("Unable to write data into \"$this->filename\" file, read mode is set."); + } + + if (empty($this->handler)) + { + throw new HandlerException("Unable to write data into \"$this->filename\" file, no resource is available."); + } + + $packedLength = pack('L', mb_strlen($data)); + + if (!empty($this->compression)) + { + return gzwrite($this->handler, $packedLength . $data); + } + + return fwrite($this->handler, $packedLength . $data); + } + + /** + * @return null|string + * @throws HandlerException + * @throws ReadDataException + */ + public function readData() + { + if (!$this->isReadMode()) + { + throw new ReadDataException("Unable to read data from \"$this->filename\" file, write mode is set."); + } + + if (empty($this->handler)) + { + throw new HandlerException("Unable to read data from \"$this->filename\" file, no resource is available."); + } + + if (!empty($this->compression)) + { + $length = gzread($this->handler, 4); + } + else + { + $length = fread($this->handler, 4); + } + + if (empty($length)) + { + return null; + } + + if (mb_strlen($length) != 4) + { + throw new ReadDataException("Unable to read data from \"$this->filename\" file, data is corrupted."); + } + + $length = unpack('L', $length); + + if (!empty($this->compression)) + { + return gzread($this->handler, $length[1]); + } + else + { + return fread($this->handler, $length[1]); + } + } + + /** + * @return bool + */ + private function isReadMode() + { + return $this->mode === self::READ; + } + + /** + * @return bool + */ + private function isWriteMode() + { + return in_array($this->mode, [self::WRITE, self::APPEND]); + } + + /** + * Check if file was closed. + * + */ + public function __destruct() + { + if (!empty($this->handler)) + { + throw new HandlerException("Binary generator hasn't finished \"$this->filename\" file yet."); + } + } +} \ No newline at end of file diff --git a/src/Exceptions/GeneratorException.php b/src/Exceptions/GeneratorException.php new file mode 100644 index 0000000..eda7391 --- /dev/null +++ b/src/Exceptions/GeneratorException.php @@ -0,0 +1,15 @@ +start($this->writeFile, BinaryGenerator::WRITE); + $binary->writeData('some data.1'); + $binary->writeData('some data.2'); + $binary->finish(); + + $this->assertFileExists($this->writeFile); + } +} \ No newline at end of file diff --git a/tests/assets/.empty b/tests/assets/.empty new file mode 100644 index 0000000..e69de29