public function decodeFile($path, $schema = null)
    {
        if (!file_exists($path)) {
            throw new FileNotFoundException(sprintf(
                'The file %s does not exist.',
                $path
            ));
        }

        $errorMessage = null;
        $errorCode = 0;

        set_error_handler(function ($errno, $errstr) use (&$errorMessage, &$errorCode) {
            $errorMessage = $errstr;
            $errorCode = $errno;
        });

        $content = file_get_contents($path);

        restore_error_handler();

        if (null !== $errorMessage) {
            if (false !== $pos = strpos($errorMessage, '): ')) {
                // cut "file_get_contents(%path%):" to make message more readable
                $errorMessage = substr($errorMessage, $pos + 3);
            }

            throw new IOException(sprintf(
                'Could not read %s: %s (%s)',
                $path,
                $errorMessage,
                $errorCode
            ), $errorCode);
        }

        try {
            return $this->decode($content, $schema);
        } catch (DecodingFailedException $e) {
            // Add the file name to the exception
            throw new DecodingFailedException(sprintf(
                'An error happened while decoding %s: %s',
                $path,
                $e->getMessage()
            ), $e->getCode(), $e);
        } catch (ValidationFailedException $e) {
            // Add the file name to the exception
            throw new ValidationFailedException(sprintf(
                "Validation of %s failed:\n%s",
                $path,
                $e->getErrorsAsString()
            ), $e->getErrors(), $e->getCode(), $e);
        } catch (InvalidSchemaException $e) {
            // Add the file name to the exception
            throw new InvalidSchemaException(sprintf(
                'An error happened while decoding %s: %s',
                $path,
                $e->getMessage()
            ), $e->getCode(), $e);
        }
    }