处理Stream (.NET) 的最佳实践

4
问题的标题是“流”,因为下面的问题是我对流的更一般疑问的具体例子:
我有一个问题,可以接受两种解决方案,我想知道哪个是最好的:
1. 下载文件,保存到磁盘(2分钟),读取并将内容写入数据库(+2分钟)。 2. 下载文件并直接将内容写入数据库(3分钟)。
如果在第二种情况下写入数据库失败,我将不得不重新下载,但在第一种情况下不需要重新下载。
哪个更好?你会使用哪个?
8个回答

3

除非增加的延迟真的让你受不了,否则我通常会选择选项1,除非你有不想将数据放在文件系统中的充分理由(例如关于安全性、容量等方面的担忧)。

或者也许像Max Schmeling建议的那样选择选项3,同时保存到文件系统和写入数据库。

磁盘空间很便宜,而且通常有备份下载数据很有用(例如测试更改数据库编写代码,作为下载数据内容的证据等)。


2
我认为,如果由于文件内容中的某些问题导致向数据库写入失败,无论我尝试多少次将相同的内容写入数据库,它都会一直失败。在这种情况下,唯一的解决方案是(修复并)重新下载该文件。如果由于数据库中的某些问题导致写入到数据库失败,那么你面临的问题比是否需要重新下载文件更大。
选择第二个选项。

2

对于Jekke的回复,我想进行详细说明:

依赖文件系统会导致许多故障(您必须创建一个有效的文件名,确保文件系统不是满的,确保文件可以被您打开和写入但不被其他人打开和写入,那么并发使用怎么办等等)。

我认为将内容写入文件的唯一好处是,在对数据库执行任何操作之前,您将知道下载已成功完成。如果可以将内容保存在内存中,请尽量这样做。如果不能,并且您真的坚持不在下载中断的情况下访问数据库,至少使用.NET的内置支持来帮助您处理棘手的部分(例如IsolatedStorageFileStream)。


1

我会选择一个目前还没有被提到的选项(除了评论中可能提到的),它在我的有关blobstreams的博客文章主题中提到:建立一个处理流水线,负责下载和解释所需的文件。然后使用代码从这个复合流中读取解释记录,并根据您的功能要求在一个事务(每个文件/每个记录)内执行所需的插入/更新操作。

这种情况是Stream类优秀的应用场景。这意味着在处理过程中,您永远不会在磁盘或内存中同时拥有整个文件。正如您提到的,下载文件需要几分钟,它可能很大。您的系统能否承受完整文件的中间存储(可能超过一次:内存和磁盘)?即使多个文件同时处理?

此外,如果您在实践中发现该链不够可靠,并且希望能够将已下载的文件暂时存储到磁盘上,确实希望能够在不必重新下载文件的情况下重复处理它,那很容易。 所需的只是管道中的额外的 Stream ,它会检查文件是否已经在您的“已下载文件”缓存中(在某个文件夹中、隔离存储中或其他任何地方),并返回其中的字节,而不是实际地将下载的 Stream 循环到处理管道中。

1

第二步不必两次花费两分钟。在下载文件的同时,你可以通过内存中的变量将其流式传输到数据库。

除非有充分的理由保留文件系统副本,大多数情况下我会选择第二种方法。


你是对的,第一个需要2步而不是第二个。 - Jader Dias

1

我不理解你所添加的关于时间或需要下载文件两次的限定符,但是,如果系统内存不足,将下载缓存到磁盘然后发送到数据库可能真的是您唯一的选择(假设您的数据提供程序可以接受流)。

编辑:在原帖中,作者将直接写入数据库描述为一个两阶段的过程,我认为这个过程是1.将文件下载到变量中,2.将变量内容流式传输到数据库。如果他在选项2中直接流式传输到数据库,那么我同意这是更好的方法。


什么是内存不足?直接写入数据库会消耗更多的内存吗? - Jader Dias
如果系统有25MB的空闲空间,而您想插入45MB的数据,则无法将所有数据存储在内存中,您必须将其缓存到磁盘上,然后分批发送到数据库。但是,根据您问题的更改,我同意选项2是更好的选择。 - overslacked
但是使用流式传输,数据仍然占用45MB吗?每个块不是在使用后立即丢弃吗? - Jader Dias
这真的取决于“流水线”设置以及数据提供程序如何读取您传递给它的流,但是-至少在理论上-如果您直接将流式数据传输到数据库中,则不应该出现任何内存问题。然而,我不知道是否有任何数据提供程序直接支持此功能。 - overslacked

1
我会选择第二个选项。失败的情况应该不会经常发生,如果确实出现了问题,您可以重新下载。如果由于某种原因需要在文件系统上保留本地副本,则不要下载、保存、读取并发送到数据库...只需在同时保存到文件系统时下载并发送到数据库即可。

我在想如何实现它,因为在.NET中,我必须将内容保存到内存中才能在两个位置写入它。 - Jader Dias
您可以从StreamReader读取,然后写入多个StreamWriters。 - Max Schmeling

1

我会选择第三个选项。将其保存到磁盘并将URI存储在数据库中。我从来没有喜欢过将文件存储在数据库中。


在我的情况下,文件(XML)并没有存储到数据库中,但是它的解析数据是存储了的。 - Jader Dias
1
等等,但是如果你已经解析了数据,那么它就在内存中了,所以这个问题就不相关了,不是吗? - Quibblesome
你下载文件。你解析文件。你插入数据库。如果数据库插入失败,那么你肯定仍然拥有在解析期间创建的对象吧?除非你只是提取基本元素? - Quibblesome

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接