I'm making a simple file transfer sender and receiver app through the wire. What I have so far is that the sender converts the file into a byte array and sends chunks of that array to the receiver.
我正在通过电线制作一个简单的文件传输发送器和接收器应用程序。到目前为止,我发送的是发送方将文件转换为字节数组,并将该数组的块发送给接收方。
This works with file of up to 256mb
, but anything above, the line:
这适用于高达256mb的文件,但上面的任何内容,行:
byte[] buffer = StreamFile(fileName); //This is where I convert the file
Throws a System out of memory exception.
I'm looking for a way to read the file in chunks then write that chunk instead of loading the whole file into a byte
. How can I do this with a FileStream
?
我正在寻找一种方法来读取块中的文件然后写入该块而不是将整个文件加载到一个字节中。我怎么能用FileStream做到这一点?
EDIT:
编辑:
Sorry, heres my crappy code so far:
对不起,到目前为止,这是我糟糕的代码:
private void btnSend(object sender, EventArgs e)
{
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] fileName = Encoding.UTF8.GetBytes(fName); //file name
byte[] fileData = null;
try
{
fileData = StreamFile(textBox1.Text); //file
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Out of memory");
return;
}
byte[] fileNameLen = BitConverter.GetBytes(fileName.Length); //length of file name
clientData = new byte[4 + fileName.Length + fileData.Length];
fileNameLen.CopyTo(clientData, 0);
fileName.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + fileName.Length);
clientSock.Connect("172.16.12.91", 9050);
clientSock.Send(clientData, 0, 4 + fileName.Length, SocketFlags.None);
for (int i = 4 + fileName.Length; i < clientData.Length; i++)
{
clientSock.Send(clientData, i, 1 , SocketFlags.None);
}
clientSock.Close();
}
And here's how I receive (the code was from a tutorial)
这是我收到的方式(代码来自教程)
public void ReadCallback(IAsyncResult ar)
{
int fileNameLen = 1;
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
if (flag == 0)
{
Thread.Sleep(1000);
fileNameLen = BitConverter.ToInt32(state.buffer, 0);
string fileName = Encoding.UTF8.GetString(state.buffer, 4, fileNameLen);
receivedPath = fileName;
flag++;
}
if (flag >= 1)
{
BinaryWriter writer = new BinaryWriter(File.Open(receivedPath, FileMode.Append));
if (flag == 1)
{
writer.Write(state.buffer, 4 + fileNameLen, bytesRead - (4 + fileNameLen));
flag++;
}
else
writer.Write(state.buffer, 0, bytesRead);
writer.Close();
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
else
{
Invoke(new MyDelegate(LabelWriter));
}
}
I just really want to know how I can read the file in chunks so that I dont need to convert it to a byte.
我真的想知道如何以块的形式读取文件,以便我不需要将其转换为字节。
Thanks for the responses so far, I think I'm starting to get it :D
感谢到目前为止的回复,我想我已经开始明白:D
3 个解决方案
#1
15
Just call Read
repeatedly with a small buffer (I tend to use something like 16K). Note that the call to Read
may end up reading a smaller amount than you request. If you're using a fixed chunk size and need the whole chunk in memory, you could just use an array of that size of course.
只需用一个小缓冲区重复调用Read(我倾向于使用像16K这样的东西)。请注意,对Read的调用最终可能会读取比您请求的数量更少的数量。如果你使用固定的块大小并且需要内存中的整个块,那么你当然可以使用那个大小的数组。
Without knowing how you're sending the file, it's hard to give much advice about how to structure your code, but it could be something like this:
在不知道你如何发送文件的情况下,很难就如何构造代码提出很多建议,但它可能是这样的:
byte[] chunk = new byte[MaxChunkSize];
while (true)
{
int index = 0;
// There are various different ways of structuring this bit of code.
// Fundamentally we're trying to keep reading in to our chunk until
// either we reach the end of the stream, or we've read everything we need.
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
SendChunk(chunk, index); // index is the number of bytes in the chunk
}
if (index != chunk.Length) // We didn't read a full chunk: we're done
{
return;
}
}
If I was more awake I'd probably find a more readable way of writing this, but it'll do for now. One option is to extract another method from the middle section:
如果我更清醒的话,我可能会找到一种更易读的写作方式,但现在就可以了。一种选择是从中间部分提取另一种方法:
// Attempts to read an entire chunk into the given array; returns the size of
// chunk actually read.
int ReadChunk(Stream stream, byte[] chunk)
{
int index = 0;
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
return index;
}
#2
2
var b = new byte[1<<15]; // 32k
while((count = inStream.Read(b, 0, b.Length)) > 0)
{
outStream.Write(b, 0, count);
}
#3
2
Have you looked into WCF Streaming? Here is a good article on MSDN that describes the capabilities of WCF to Stream GBs of data.
你有没有看过WCF流媒体?以下是MSDN上的一篇很好的文章,它描述了WCF对Stream数据流的功能。
大数据和流媒体
#1
15
Just call Read
repeatedly with a small buffer (I tend to use something like 16K). Note that the call to Read
may end up reading a smaller amount than you request. If you're using a fixed chunk size and need the whole chunk in memory, you could just use an array of that size of course.
只需用一个小缓冲区重复调用Read(我倾向于使用像16K这样的东西)。请注意,对Read的调用最终可能会读取比您请求的数量更少的数量。如果你使用固定的块大小并且需要内存中的整个块,那么你当然可以使用那个大小的数组。
Without knowing how you're sending the file, it's hard to give much advice about how to structure your code, but it could be something like this:
在不知道你如何发送文件的情况下,很难就如何构造代码提出很多建议,但它可能是这样的:
byte[] chunk = new byte[MaxChunkSize];
while (true)
{
int index = 0;
// There are various different ways of structuring this bit of code.
// Fundamentally we're trying to keep reading in to our chunk until
// either we reach the end of the stream, or we've read everything we need.
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
SendChunk(chunk, index); // index is the number of bytes in the chunk
}
if (index != chunk.Length) // We didn't read a full chunk: we're done
{
return;
}
}
If I was more awake I'd probably find a more readable way of writing this, but it'll do for now. One option is to extract another method from the middle section:
如果我更清醒的话,我可能会找到一种更易读的写作方式,但现在就可以了。一种选择是从中间部分提取另一种方法:
// Attempts to read an entire chunk into the given array; returns the size of
// chunk actually read.
int ReadChunk(Stream stream, byte[] chunk)
{
int index = 0;
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
return index;
}
#2
2
var b = new byte[1<<15]; // 32k
while((count = inStream.Read(b, 0, b.Length)) > 0)
{
outStream.Write(b, 0, count);
}
#3
2
Have you looked into WCF Streaming? Here is a good article on MSDN that describes the capabilities of WCF to Stream GBs of data.
你有没有看过WCF流媒体?以下是MSDN上的一篇很好的文章,它描述了WCF对Stream数据流的功能。
大数据和流媒体