处置和 return 值

Dispose and return value

我对流感到困惑,return 值和处置。 IE。我使用 Stream 并希望 return 从方法流式传输。下一个代码:

    public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
    {
        HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
        using (var stream = new FileStream(@"D:\_forTest.jpg", FileMode.Open))
        {
            length = stream.Length;
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentLength = length;

            return result;
        }
    }

    public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
    {
        long length = 0;
        HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
        using (var stream = new FileStream(@"D:\_forTest.jpg", FileMode.Open))
        {
            length = stream.Length;
            result.Content = new StreamContent(stream);
        }

        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentLength = length;

        return result;

    }

returns 504状态码:

ReadResponse() failed: The server did not return a complete response for this request. Server returned 0 bytes.

因此,据我了解,当我们从方法中退出时,流被处理掉

如果我根本不调用 Dispose:

    public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
    {
        long length = 0;
        HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
        var stream = new FileStream(@"D:\_forTest.jpg", FileMode.Open);
        length = stream.Length;
        result.Content = new StreamContent(stream);

        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentLength = length;

        return result;
    }

有时我会收到该文件被另一个进程阻止的消息。如何正确制作?

一些背景: 一般来说,如果你想流式传输文件的内容,你要做的就是从文件流中读取并写入 HTTP 响应的输出流。 示例:

using (var source = new FileStream(...))
{
    byte[] buffer = new byte[4096];
    int byteCount;
    while ((byteCount = await source.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        await output.WriteAsync(buffer, 0, byteCount);
    }
}

现在,在您的特定情况下,您使用的是 framework/pattern,这需要您将内容流传递给它,而不是让您自己写入输出。在这种情况下,您被迫将处理流的责任转移给处理程序方法的调用者。

规格: 如果您的问题是文件被锁定,那么您可以在打开流时允许共享 read/write 访问:

var stream = new FileStream(@"D:\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

这将允许其他进程在您读取文件时对文件进行读写访问。

编辑:如@Evk 所述,更安全的选择是仅与读者共享访问权限(尝试打开文件进行写入将被拒绝):

    var stream = new FileStream(@"D:\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.Read);

改进: 如果您的文件适合内存,明智的做法是将其内存缓存而不是直接从磁盘流式传输。如果您同时有数千个请求来获取此文件,您的磁盘将成为一个巨大的瓶颈。使用具有 retention/expiration 策略的缓存,并在缓存未命中时读取并缓存整个文件。通过这种方式,您还可以最小化打开文件句柄的 window(打开,线性 I/O 读取,关闭;非常快)。