我从客户端获取数据并将其保存到本地主机上的本地驱动器。我检查了一个221MB的文件但是对1Gb文件的测试给出了以下异常:
未处理的类型' System.OutOfMemoryException'发生在mscorlib.dll
以下是服务器端的代码,其中异常出现。
已更新
服务器:
public void Thread()
{
TcpListener tcpListener = new TcpListener(ipaddr, port);
tcpListener.Start();
MessageBox.Show("Listening on port" + port);
TcpClient client=new TcpClient();
int bufferSize = 1024;
NetworkStream netStream;
int bytesRead = 0;
int allBytesRead = 0;
// Start listening
tcpListener.Start();
// Accept client
client = tcpListener.AcceptTcpClient();
netStream = client.GetStream();
// Read length of incoming data to reserver buffer for it
byte[] length = new byte[4];
bytesRead = netStream.Read(length, 0, 4);
int dataLength = BitConverter.ToInt32(length,0);
// Read the data
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
bytesRead = netStream.Read(data, allBytesRead, nextPacketSize);
allBytesRead += bytesRead;
bytesLeft -= bytesRead;
}
// Save to desktop
File.WriteAllBytes(@"D:\LALA\Miscellaneous\" + shortFileName, data);
// Clean up
netStream.Close();
client.Close();
}
我首先从客户端获取文件大小,然后是数据。
1)。我应该增加缓冲区大小或任何其他技术吗?
2)。 File.WriteAllBytes()
和File.ReadAllBytes()
似乎阻塞并冻结了PC。是否有任何异步方法可以帮助提供服务器端收到的文件进度。
答案 0 :(得分:2)
在将其写入光盘之前,您不需要将整个内容读取到内存中。只需从网络流直接复制到FileStream
:
byte[] length = new byte[4];
// TODO: Validate that bytesRead is 4 after this... it's unlikely but *possible*
// that you might not read the whole length in one go.
bytesRead = netStream.Read(length, 0, 4);
int bytesLeft = BitConverter.ToInt32(length,0);
using (var output = File.Create(@"D:\Javed\Miscellaneous\" + shortFileName))
{
netStream.CopyTo(output, bytesLeft);
}
请注意,您应该使用netStream.Close()
语句,而不是显式调用using
:
using (Stream netStream = ...)
{
// Read from it
}
这样即使抛出异常,流也将被关闭。
答案 1 :(得分:1)
CLR的每个对象限制有点短于2GB。然而,这就是理论,实际上你可以分配多少内存取决于框架允许你分配多少内存。我不希望它允许您分配1 GB数据表。您应该分配较小的表,并将数据以块的形式写入磁盘文件。
答案 2 :(得分:1)
"内存不足"异常发生是因为您尝试将整个文件放入内存,然后将其转储到磁盘上。这不是最理想的,因为你不需要内存中的整个文件来写入文件:你可以以合理大小的增量逐块读取它,并在你去的时候写出来。
从.NET 4.0开始,您可以使用Stream.CopyTo
方法在几行代码中完成此任务:
// Read and ignore the initial four bytes of length from the stream
byte[] ignore = new byte[4];
int bytesRead = 0;
do {
// This should complete in a single call, but the API requires you
// to do it in a loop.
bytesRead += netStream.Read(ignore, bytesRead, 4-bytesRead);
} while (bytesRead != 4);
// Copy the rest of the stream to a file
using (var fs = new FileStream(@"D:\Javed\Miscellaneous\" + shortFileName, FileMode.Create)) {
netStream.CopyTo(fs);
}
netStream.Close();
从.NET 4.5开始,您也可以使用CopyToAsync
,这将为您提供一种异步读写的方法。
请注意从流中删除初始四个字节的代码。这样做是为了避免写入流的长度以及"有效载荷"字节。如果您可以控制网络协议,则可以更改发送方以停止使用其长度为流添加前缀,并删除在接收方读取和忽略它的代码。