这个问题的标题是“Stream”这个词,因为下面的问题是我对 Streams 有一个更普遍的疑问的一个具体例子:
我有一个接受两种解决方案的问题,我想知道最好的一个:
- 我下载一个文件,将其保存到磁盘(2 分钟),读取它并将内容写入数据库(+ 2 分钟)。
- 我下载一个文件并将内容直接写入数据库(3 分钟)。
如果写入数据库失败,我将不得不在第二种情况下再次下载,但不是在第一种情况下。
哪个最好?你会用哪个?
除非增加的延迟真的会杀死你,否则我通常会选择选项 1,除非你有充分的理由不希望文件系统上的数据(例如,对安全性、容量的担忧......)。
或者Max Schmeling 建议的选项 3,在写入数据库的同时保存到文件系统。
磁盘空间很便宜,备份下载的数据通常很有用(例如,测试对数据库编写代码的更改,作为下载数据内容的证据,...)。
我假设如果由于文件内容中的某些内容而导致对数据库的写入失败,那么无论我尝试将相同的内容写入数据库多少次,它都会失败。在这种情况下,唯一的解决方案是(修复并)重新下载文件。如果由于数据库中的某些内容而导致对数据库的写入失败,那么您将遇到比是否需要再次下载文件更大的问题。
选择选项#2。
要详细说明 Jekke 的回复:
根据文件系统创建许多失败的场合(您必须创建一个有效的文件名,确保文件系统未满,确保文件可以由您打开和写入但不能由其他人打开和写入,并发呢?使用等)。
我能想到的写入文件的唯一好处是,在对数据库进行任何操作之前,您将知道下载已成功完成。如果您可以将内容保存在内存中,请改为这样做。如果您不能并且真的坚持在下载中断的情况下不访问数据库,那么至少使用 .NET 的内置支持来帮助您解决棘手的问题(例如,IsolatedStorageFileStream)。
没有理由第 2 步必须花费两分钟两次。下载文件时,您可以通过内存中的变量将其流式传输到数据库。
除非您有令人信服的理由保留文件的文件系统副本,否则在大多数情况下我会选择 #2。
我不明白您添加的关于时间或必须下载文件两次的限定符,但是,如果系统内存不足,将下载缓存到磁盘然后将其发送到数据库可能真的是您唯一的选项(假设您的数据提供者可以接受流)。
编辑:在原始帖子中,作者将直接写入数据库描述为一个两阶段的过程,我假设是 1. 将文件下载到变量中,2. 将变量内容流式传输到 DB。如果他在选项 2 中直接流式传输到数据库,那么我同意这是一个更好的方法。
我会选择选项二。不应该经常出现故障,当有你可以重新下载。如果由于某种原因您需要在文件系统上拥有该本地副本,则不要下载、保存、读取和发送到数据库...只需在保存到文件系统的同时下载并发送到数据库.
我会选择选项 3。将其保存到磁盘并将 URI 存储在数据库中。我从来都不喜欢在数据库中存储文件。
我会选择在我关于 blobstreams 的博客文章的主题中提到的迄今为止尚未提及的选项(也许在评论中除外):设置一个流处理管道,负责下载和解释您需要的文件。然后使用代码从这个复合流中读取解释记录,并在一个事务中(每个文件/每个记录,根据您的功能要求)在您的数据库中执行所需的插入/更新。
这种场景是Stream
基础类擅长的地方。这意味着您在处理时永远不会同时将整个文件放在磁盘或内存中的任何位置。正如您提到的下载文件需要几分钟,它可能很大。您的系统是否可以对完整文件进行中间存储(可能不止一次:内存和磁盘)?即使同时处理多个文件?
此外,如果您在实践中发现该链对您来说不够可靠,并且您希望能够将下载的文件临时存储到磁盘上,并且确实希望重复处理它而无需再次下载,这简单。所需要的只是管道中的额外内容Stream
,它将检查所需文件是否已经在您的“已下载文件”缓存中(在某个文件夹中,在隔离存储中,等等)并返回其中的字节,而不是实际循环下载Stream
进入您的处理管道。