在 ASP.NET MVC 中使用 FileShare.ReadWrite 和 HttpPostedFile

Posted

技术标签:

【中文标题】在 ASP.NET MVC 中使用 FileShare.ReadWrite 和 HttpPostedFile【英文标题】:Use FileShare.ReadWrite with HttpPostedFile in ASP.NET MVC 【发布时间】:2019-10-11 22:32:17 【问题描述】:

我正在使用下面的代码将发布的文件保存到服务器,但该文件正在被持续读取,需要使用 FileShare.ReadWrite,因此我不会收到锁定错误。

 httpRequest.Files[0].SaveAs(filePath);

以下是我的阅读方法,我怎样才能做到这一点,使用 HttpPosted 文件是性能最好的正确方法。

using (var fileStream = new FileStream(
                   fileLocation,
                   FileMode.Open,
                   FileAccess.Read,
                   FileShare.ReadWrite))
                
                    using (var streamReader = new StreamReader(fileStream))
                    
                        xDocument = XDocument.Parse(streamReader.ReadToEnd());
                    
                

这是我最好的选择吗?

 using (var memoryStream = new MemoryStream())
                
                    httpRequest.Files[0].InputStream.CopyTo(memoryStream);
                    var bytes = memoryStream.ToArray();

                    using (var fs = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
                    
                        fs.Write(bytes, 0, bytes.Length);
                    
                

【问题讨论】:

我知道@efaruk 现在删除的答案不是问题,但它是答案吗?这是检查文件是否实际锁定的更好方法:***.com/a/11060322/495455 - 我的代码与您大致相同,并且我对其进行了测试。如果您阅读了许多 cmets,则在最轻微的竞争条件下可能存在文件锁定问题和性能。我会选择具有内置故障处理和容错能力的 Polly .Net 框架...... 我的问题不是关于那个,而是从 HTTPPosted 文件中做的。 怎么样?从根本上说,您正在写入磁盘,并且正在从磁盘读取同一文件。您收到文件锁定错误。你提到了FileAccessFileShare 标志来解决这个问题,然后是关于性能的问题,正如我提到的,我的代码和你一样。它表现良好。那么问题是什么? 在 ASP.NET MVC 中将 FileShare.ReadWrite 与 HttpPostedFile 结合使用 - 您必须使用内存、@efaruk 提到的 MQ 或分贝。让我仔细检查一下 doco HttpPostedFile 没有给你那种控制权。 我知道它没有,这就是为什么我从 httpposted 文件中寻求替代方案,甚至举了一个例子。 不,它不支持它:docs.microsoft.com/en-us/dotnet/api/… - 当文件被上传时,不要从文件中读取信号。或者让文件上传一个 2 步过程,他们将其上传到 DataGrid,然后单击一个按钮来处理将合并/更新新/更改值的数据。 【参考方案1】:

问题:

您想要一个“写入:一次,读取:多次”锁

假设:

文件很小(平均写入操作为 5000 毫秒) 没有其他写入或读取操作(只有一个具有 2 个功能的程序) 读取文件的次数远多于写入文件的次数

解决方案


    using System;
    using System.IO;
    using System.Threading;
    using System.Web.Mvc;

    namespace ***_56307594.Controllers
    

        public class HomeController : Controller
        

            public ActionResult A()
            
                readFile();
                return View();
            

            public ActionResult B()
            
                writeFile();
                return View();
            


            private static object writeLock = new Object();

            private void readFile()
            
                while (!Monitor.TryEnter(writeLock, 5000)) ; //wait 5000 ms for the writeLock (serializing access)
                using (var stream = new FileStream("filePath", FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var reader = new StreamReader(stream))
                
                    // active read
                    // xDocument = XDocument.Parse(streamReader.ReadToEnd());

                
            
            private void writeFile()
            
                lock (writeLock)
                
                    FileStream stream = null;
                    while (stream == null) //wait for the active read
                    
                        try
                        
                            stream = new FileStream("filePath", FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                        
                        catch (IOException)
                        
                        // will fail if active read becase FileShare.None   while (stream == null) will  wait
                    
                
                    Request.Files[0].InputStream.CopyTo(stream);
                // unlock
            

        
    

注意:

    我没有测试负载或只是在网络服务器上测试解决方案 我只在纸上测试过?

参考:

locking - How long will a C# lock wait, and what if the code crashes during the lock? - Stack Overflow

c# - Deleting files in use - Stack Overflow

multithreading - Is there a way to detect if an object is locked? - Stack Overflow

Implementing Singleton in C# | Microsoft Docs

c# - Using the same lock for multiple methods - Stack Overflow

c# - Write-Once, Read-Many Lock - Stack Overflow

c# lock write once read many - Google Search

FileShare Enum (System.IO) | Microsoft Docs

【讨论】:

Request.Files[0].InputStream.CopyTo(stream); 似乎不在正确的位置 @MikeFlynn ?‍♀️ 它在锁内,并且在您使用 FileShare.None 获得独占文件访问权限后 变量stream超出范围,看你的代码 @MikeFlynn 谢谢?,从 While 计算大括号,它看起来不错(可能是因为它看起来超出范围的间距),我希望它会在某种程度上有所帮助

以上是关于在 ASP.NET MVC 中使用 FileShare.ReadWrite 和 HttpPostedFile的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 和 Angularjs 与 ASP.NET MVC 和 Reactjs

在 ASP.NET 中使用 WebAPI 或 MVC 返回 JSON

在ASP.NET MVC中使用DropDownList

七天学会ASP.NET MVC ——ASP.NET MVC 数据传递

七天学会ASP.NET MVC ——ASP.NET MVC 数据传递

如何在 Asp.Net 5 (MVC 6) 中使用实体框架 6.x