【发布时间】:2015-02-07 16:08:17
【问题描述】:
我遇到了OutOfMemoryException。我的流程如下:
- 我从数据库中读取数据(大集合,数百万行)。
- 我遍历检索到的数据并将其附加到
StringBuilder。 - 我在
StringBuilder上调用 ToString 并使用 SFTP (Renci.SSHnet) 将字符串上传到新文件。
此流程不起作用,因为要保存在内存中的文件太多。我决定做一些改变:
- 现在使用数据读取器获取数据并返回(而不是返回整个数据集)
- 我无法在
StringBuilder上调用ToString,因为字符串太大而无法放入内存。我将StringBuilder更改为StreamWriter,这样我就可以直接写入一个流,然后SFTP 上传过程可以使用该流。
这就是事情开始变得棘手的地方。我想在我的数据处理代码中将新数据附加到StreamWriter,而 SFTP 上传代码从同一流中读取,对其进行 GZIP 压缩并上传数据。请注意,它应该只在远程服务器上创建一个文件。换句话说:我想在上传处理过的数据的同时处理数据,这样我就可以保持非常低的内存占用。我无法让这个工作。这是我想出的(简化示例),但它从不读取数据:
static void Main()
{
using (var stream = new MemoryStream())
{
WriteToStream(stream, GetData());
ReadFromStream(stream);
}
}
static IEnumerable<string> GetData()
{
for (int i = 0; i < 10; i++)
{
var date = DateTime.Now;
Console.WriteLine("{0:O} - Fetched some data: {1}", date, i);
yield return string.Format("{0}", i);
}
}
static void WriteToStream(Stream stream, IEnumerable<string> data)
{
using (var writer = new StreamWriter(stream))
{
foreach (string str in data)
{
Console.WriteLine("{0:O} - Wrote some data: {1}", DateTime.Now, str);
writer.WriteLine("{0}", str);
}
}
}
static void ReadFromStream(Stream stream)
{
using (var reader = new StreamReader(stream))
{
while (reader.Peek() >= 0)
{
var res = reader.ReadLine();
Console.WriteLine("{0} - Read some data: {1}", DateTime.Now, res);
}
}
}
谁能指出我正确的方向?
【问题讨论】:
-
参见stackoverflow.com/questions/24253975/…,这与您尝试做的非常相似。
-
您的示例不起作用,因为
StreamWriter关闭时StreamWriter关闭了基础流(MemoryStream)。您可以使用this overloaded constructor 来防止这种情况。在调用ReadFromStream之前,您还需要将MemoryStream位置设置为0。但这仍然无法满足您的需求,因为 FTP 上传组件可能不会配合。我上面提供的链接可以让你做你想做的事。但是,您需要将生产者或消费者放在单独的线程上。
标签: c# memory ftp stream streaming