在 ILIAS 中使用 flysystem 附加到文件

Append to file using flysystem in ILIAS

我目前正在为某些插件编写一个记录器,写入 ILIAS 中相当大的日志文件。我正在使用整洁的新文件系统。由于新的日志消息需要附加到文件中,我不能简单地使用 put 或 update,因为它们似乎总是截断日志文件。 Flysystem 似乎不支持简单的追加命令,所以我发现一种有效的方法如下:

$old_data = "";
if ($DIC->filesystem()->storage()->has($this->path)) {
    $old_data = $DIC->filesystem()->storage()->read($this->path);
}
$DIC->filesystem()->storage()->put($this->path, $old_data.$string);

但是,如果将大量数据附加到日志,这对于 IO 来说似乎非常昂贵。我想,这最好使用流来完成。我在文档 (https://github.com/ILIAS-eLearning/ILIAS/tree/release_5-3/src/Filesystem) 中发现了以下内容:

$webDataRoot = $DIC->filesystem()->web();
$fileStream = $webDataRoot->readStream('relative/path/to/file');

//seek at the end of the stream
$fileStream->seek($fileStream->getSize() - 1);
//append something
$fileStream->write("something");

但是,我得到了 无法写入不可写流 异常。看来,我需要像这样打开流:

$resource = fopen('myPath', 'rw');

然而,文档中特别不鼓励这样做。使用 ILIAS 中的文件系统解决此问题的最佳方法是什么?

问题

ILIAS 的文件系统抽象利用 flysystem 来操作文件系统。然而,正如您已经指出的那样,flysystem 没有提供将数据附加到文件的简单方法。主要原因似乎是许多用于将文件写入存储后端的文件系统适配器由于底层技术不支持追加操作,例如重新上传整个文件的 S3 V3 storage adapter文件。

不幸的是,文档位于 (ILIAS-eLearning) is wrong, because the streams returned by flysystem are read only due to the fact that some filesystem adapters only "emulate" the behaviour of a filestream. The stream points to a local copy or in-memory stream instead of the "real" file located at the storage backend, see Flysystem AWS S3 Adapter.

结论

总之,在当前的 ILIAS 文件系统实现中,没有正确的方法可以将数据附加到现有文件,因为 flyway 不提供此类操作。 此外,即使 flyway 提供,某些存储后端仍然不支持此类操作。一个很好的例子是 AWS S3 存储后端请参阅问题 .

的答案

您的用例的可能解决方法

如果您能够使用多个日志文件,请使用某种日志文件轮换来减少 IO,这不是解决方案,但有助于将负载至少保持在一致的水平。例如,如果大小超过 20MB,则写入新的日志文件并保留最后 20 个日志文件。