【问题标题】:How to split a large file into chunks in c#?如何在c#中将大文件拆分成块?
【发布时间】:2011-08-05 06:37:52
【问题描述】:

我正在通过网络制作一个简单的文件传输发送方和接收方应用程序。到目前为止,发送者将文件转换为字节数组并将该数组的块发送给接收者。

这适用于最大为 256mb 的文件,但此行会针对上述任何内容引发“系统内存不足”异常:

byte[] buffer = StreamFile(fileName); //This is where I convert the file

我正在寻找一种方法来读取块中的文件,然后写入该块而不是将整个文件加载到byte 中。如何使用FileStream 做到这一点?

编辑:

抱歉,到目前为止,这是我糟糕的代码:

    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();
    }

这是我收到的方式(代码来自教程)

   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));
        }

    }

我真的很想知道如何分块读取文件,这样我就不需要将其转换为字节。

感谢到目前为止的回复,我想我开始明白了:D

【问题讨论】:

  • 找不到这样的方法StreamFile,你能告诉我应该包含哪个库吗?

标签: c# file tcp filestream


【解决方案1】:

只需使用小缓冲区重复调用Read(我倾向于使用类似 16K 的缓冲区)。请注意,对Read 的调用最终可能会读取比您请求的 数量。如果您使用固定的块大小并且需要内存中的整个块,那么您当然可以使用该大小的数组。

在不知道如何发送文件的情况下,很难就如何构建代码给出很多建议,但可能是这样的:

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;
    }
}

如果我再清醒一点,我可能会找到一种更易读的方式来写这篇文章,但现在就可以了。一种选择是从中间部分提取另一种方法:

// 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】:
    var b = new byte[1<<15]; // 32k
    while((count = inStream.Read(b, 0, b.Length)) > 0)
    {
      outStream.Write(b, 0, count);
    }
    

    【讨论】:

      【解决方案3】:
       public static IEnumerable<byte[]> SplitStreamIntoChunks(Stream stream, int chunkSize)
          {
            var bytesRemaining = stream.Length;
            while (bytesRemaining > 0)
            {
              var size = Math.Min((int) bytesRemaining, chunkSize);
              var buffer = new byte[size];
              var bytesRead = stream.Read(buffer, 0, size);
              if (bytesRead <= 0)
                break;
              yield return buffer;
              bytesRemaining -= bytesRead;
            }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-27
        • 2020-05-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多