C#HttpListener:存储发布的文件总是比原始文件大2个字节

时间:2016-06-10 09:37:35

标签: c# httplistener httplistenerrequest

问题描述:

我的C#程序中有一个HttpListener,它接收带有已发布文件(jpg,doc,zip或类似文件)的POST请求。我在同一台Windows机器上发送和接收文件。

我从中获取了代码 https://stackoverflow.com/a/8468520/241475(来自Java世界,我是C#/ .Net的新手),据说这只是一个概念证明,在服务器端上传和存储数据几乎可以正常工作,除了存储的文件总是比原始文件大2个字节。

这对于jpg,doc或单个zip文件无关紧要 - 我仍然可以打开它们并且它们显示正常 - 但是当我上传一个zip文件是多卷zip的一部分时,解压缩通常会失败,因为一个文件里面拉链,其余拉链拉链。

示例:

在此示例中,您可以看到原始文件(import_filesystem.kmumitkst.z01.ORIGINAL),其中10485760字节大,我发布到我的HttpListener并存储了名为import_filesystem.kmumitkst.z01的版本,其中是10485762字节大。

当我然后通过WinRar解压缩时,它告诉我CRC /校验和不正确,并且由于这两个额外的字节,其中的一个文件已损坏。

enter image description here

代码:

这是存储接收文件的代码:

while (_listener.IsListening)
{
    ThreadPool.QueueUserWorkItem((c) =>
    {
        var ctx = c as HttpListenerContext;  
        SaveFile(ctx.Request.ContentEncoding, GetBoundary(ctx.Request.ContentType), 
            ctx.Request.InputStream, targetFilePath);
        ...
    }
}

// =====================================


private static void SaveFile(Encoding enc, String boundary, Stream input, string targetPath)
{
    Byte[] boundaryBytes = enc.GetBytes(boundary);
    Int32 boundaryLen = boundaryBytes.Length;

    using (FileStream output = new FileStream(targetPath, FileMode.Create, FileAccess.Write))
    {
        Byte[] buffer = new Byte[1024];
        Int32 len = input.Read(buffer, 0, 1024);
        Int32 startPos = -1;

        // Find start boundary
        while (true)
        {
            if (len == 0)
            {
                throw new Exception("Start Boundaray Not Found");
            }

            startPos = IndexOf(buffer, len, boundaryBytes);
            if (startPos >= 0)
            {
                break;
            }
            else
            {
                Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
                len = input.Read(buffer, boundaryLen, 1024 - boundaryLen);
            }
        }

        // Skip four lines (Boundary, Content-Disposition, Content-Type, and a blank)
        for (Int32 i = 0; i < 4; i++)
        {
            while (true)
            {
                if (len == 0)
                {
                    throw new Exception("Preamble not Found.");
                }

                startPos = Array.IndexOf(buffer, enc.GetBytes("\n")[0], startPos);
                if (startPos >= 0)
                {
                    startPos++;
                    break;
                }
                else
                {
                    len = input.Read(buffer, 0, 1024);
                }
            }
        }

        Array.Copy(buffer, startPos, buffer, 0, len - startPos);
        len = len - startPos;

        while (true)
        {
            Int32 endPos = IndexOf(buffer, len, boundaryBytes);
            if (endPos >= 0)
            {
                if (endPos > 0) output.Write(buffer, 0, endPos);
                break;
            }
            else if (len <= boundaryLen)
            {
                throw new Exception("End Boundaray Not Found");
            }
            else
            {
                output.Write(buffer, 0, len - boundaryLen);
                Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
                len = input.Read(buffer, boundaryLen, 1024 - boundaryLen) + boundaryLen;
            }
        }
    }
}

private static String GetBoundary(String ctype)
{
    return "--" + ctype.Split(';')[1].Split('=')[1];
}

private static Int32 IndexOf(Byte[] buffer, Int32 len, Byte[] boundaryBytes)
{
    for (Int32 i = 0; i <= len - boundaryBytes.Length; i++)
    {
        Boolean match = true;
        for (Int32 j = 0; j < boundaryBytes.Length && match; j++)
        {
            match = buffer[i + j] == boundaryBytes[j];
        }

        if (match)
        {
            return i;
        }
    }
    return -1;
}

问题:

这两个额外字节来自哪里?无论我发送的文件类型或文件大小是多少,它总是超过2个字节。

有没有其他方法可以通过HttpListener保存收到的文件?谢谢你的提示。

1 个答案:

答案 0 :(得分:0)

找到解决方案,不得不改变

while (true)
{
    Int32 endPos = IndexOf(buffer, len, boundaryBytes);
    if (endPos >= 0)
    {
        if (endPos > 0) output.Write(buffer, 0, endPos);
        break;
    }

while (true)
{
    Int32 endPos = IndexOf(buffer, len, boundaryBytes);
    if (endPos >= 0)
    {
        if (endPos > 0) output.Write(buffer, 0, endPos-2);
        break;
    }

-2添加endPos,以避免在结尾处出现额外的换行符。