C# 为什么我可以上传一个文件,但如果没有内存不足异常,就不能下载它?

C# 为什么我可以上传一个文件,但如果没有内存不足异常,就不能下载它?,c#,.net,file,exception,out-of-memory,C#,.net,File,Exception,Out Of Memory,我的软件有一项功能,允许用户上传以字节字符串形式存储在我的数据库中的文件。 代码的工作原理如下: 计算文件中的字节数,并创建具有该长度的字节数组。然后将该文件读入字节数组。从这里开始,文件被分割成若干部分并存储在我的数据库中。这是通过使用以下代码完成的: openFile1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); blah, blah, blah . . . openFileBytes

我的软件有一项功能,允许用户上传以字节字符串形式存储在我的数据库中的文件。
代码的工作原理如下:

计算文件中的字节数,并创建具有该长度的字节数组。然后将该文件读入字节数组。从这里开始,文件被分割成若干部分并存储在我的数据库中。这是通过使用以下代码完成的:

openFile1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
blah, blah, blah
.
.
.
openFileBytesNumber = openFile1.Length;
byteArray = new byte[openFileBytesNumber];
openFile1.Read(byteArray, 0, (int)(openFileBytesNumber));
fullByteString = Convert.ToBase64String(byteArray);
当我下载它时,会发生以下情况:

字节字符串是通过从数据库加载文件数据并连接所有片段来创建的。使用以下代码行将字符串放入字节数组:

byteArray = Convert.FromBase64String(byteString.ToString());

这就是我得到内存不足异常的地方。为什么我在下载时得到OutOfMemoryException,而不是在上载时?

当您查询数据库时,似乎是通过DataSet将整个结果集存储在内存中。考虑使用Sql DataReaDER(或者数据库的IDataRead)代替Sql DataAd适配器和DataSet。这将允许您一次在内存中有一行,而不是整个结果集。

Base64有30%的开销,字符串有100%的开销(因为
char
是16位)。这就产生了160%的开销(1.3*2.0=2.6),用于将数据作为base64字符串保存在内存中

您将
数据集中的所有数据
StringBuilder
以及最终字符串和最终结果一起保存在内存中。这意味着总开销为780%(3*2.6+1=8.8)

代码需要的内存大约是文件大小的9倍

要减少内存使用,您可以:

  • 使用数据读取器而不是数据集。这样,在内存中一次只有一条记录
  • 对每条记录执行从base64到字节的转换,而不是构建整个字符串。如果字符串长度可以被4整除,就可以这样做

旁注:您在读取文件时使用的
Read
方法错误。
Read
方法返回读取的字节数,该字节数可能小于请求的字节数。您需要从方法中获取返回值并重复调用,直到获得所有数据:

int openFileBytesNumber = (int)openFile1.Length;
int len = 0;
while (len < openFileBytesNumber) {
  int l = openFile1.Read(byteArray, len, openFileBytesNumber - len);
  if (l == 0) {
    // unexpended end of file error - better handle that
  }
  len += l:
}
intopenfilebytesnumber=(int)openFile1.Length;
int len=0;
while(len
您的
FileStream
和实现
IDisposable
的任何其他对象需要在
中使用
块:

using (var openFile1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    blah, blah, blah
    .
    .
    .
    openFileBytesNumber = openFile1.Length;
    byteArray = new byte[openFileBytesNumber];
    openFile1.Read(byteArray, 0, (int)(openFileBytesNumber));
    fullByteString = Convert.ToBase64String(byteArray);
}

什么是
byteString
以及如何连接这些片段?.NET需要分配一个连续的内存块。如果文件很大,可能是因为找不到足够的连续内存进行第二次分配。将文件存储为Base64字符串是非常浪费的。它应该存储在一个二进制列中。@Guffa,StringBuilder byteString=new StringBuilder();对于(int i=0;i