繁体   English   中英

C#IO读写文件使用错误

[英]C# IO Reading and Writing file in use error

我有一个处理读写缓存文件的库。 Windows服务和同一台计算机上的控制台应用程序的多个实例使用此库。 控制台应用程序在用户登录时运行。

我偶尔会收到IO错误,说另一个进程正在使用缓存文件。 我假定尝试同时读写的不同应用程序实例和服务之间发生冲突。

有没有一种方法可以在使用文件时锁定文件,并强制所有其他请求“排队”访问文件?

    private void SaveCacheToDisk(WindowsUser user) {
        string serializedCache = SerializeCache(_cache);
        //encryt
        serializedCache = AES.Encrypt(serializedCache);

        string path = user == null ? ApplicationHelper.CacheDiskPath() :
            _registry.GetCachePath(user);
        string appdata = user == null ? ApplicationHelper.ClientApplicationDataFolder() :
            _registry.GetApplicationDataPath(user);

        if (Directory.Exists(appdata) == false) {
            Directory.CreateDirectory(appdata);
        }

        if (File.Exists(path) == false) {
            using (FileStream stream = File.Create(path)) { }
        }

        using (FileStream stream = File.Open(path, FileMode.Truncate)) {
            using (StreamWriter writer = new StreamWriter(stream)) {
                writer.Write(serializedCache);
            }
        }
    }

    private string ReadCacheFromDisk(WindowsUser user) {
        //cache file path
        string path = user == null ? ApplicationHelper.CacheDiskPath() :
            _registry.GetCachePath(user);

        using (FileStream stream = File.Open(path, FileMode.Open)) {
            using (StreamReader reader = new StreamReader(stream)) {
                string serializedCache = reader.ReadToEnd();
                //decrypt
                serializedCache = AES.Decrypt(serializedCache);

                return serializedCache;
            }
        }
    }

当然,您可以使用互斥锁并仅在持有互斥锁时才允许访问。

您可以使用跨进程EventWaitHandle 这使您可以创建和使用通过名称跨进程标识的WaitHandle。 轮到一个线程时通知它,做一些工作,然后指示它已经完成,允许另一个线程继续进行。

请注意,这仅在每个进程/线程都引用相同名称的WaitHandle时有效。

在签名中带有字符串的EventWaitHandle构造函数将创建命名的系统同步事件。

您可以考虑的一种选择是让控制台应用程序通过该服务路由其文件访问,这样,只有一个进程访问该文件,并且您可以在那里同步对其的访问。

一种实现方法是通过IPC通道进行远程处理 (这是来自weblogs.asp.net的另一个示例 )。 我们在我所工作的公司的项目中使用了此技术,并且效果很好,我们的特定案例为.net WebService提供了与在同一台计算机上运行的Windows Service进行通信的方式。

基于weblogs.asp.net示例的示例

基本上,您需要使用下面的代码创建一个解决方案,添加两个控制台应用程序(一个称为“服务器”,另一个称为“客户端”)和一个库。向两个控制台应用程序添加对该库的引用,然后粘贴下面的代码,并添加对System.Runtime.Remoting的引用到服务器和控制台。

运行服务器应用程序,然后运行客户端应用程序。 观察服务器应用程序已经有一条消息由客户端传递给它的事实。 您可以将此扩展到任意数量的消息/任务

// Server:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
namespace RemotingSample
{
    public class Server
    {
        public Server()
        { 
        }
        public static int Main(string[] args)
        {
            IpcChannel chan = new IpcChannel("Server");
            //register channel
            ChannelServices.RegisterChannel(chan, false);
            //register remote object
            RemotingConfiguration.RegisterWellKnownServiceType(
                        typeof(RemotingSample.RemoteObject),
                   "RemotingServer",
                   WellKnownObjectMode.SingleCall);

            Console.WriteLine("Server Activated");
            Console.ReadLine();
            return 0;
        }
    }
}

// Client:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using RemotingSample;
namespace RemotingSample
{
    public class Client
    {
        public Client()
        { 
        }
        public static int Main(string[] args)
        {
            IpcChannel chan = new IpcChannel("Client");
            ChannelServices.RegisterChannel(chan);
            RemoteObject remObject = (RemoteObject)Activator.GetObject(
                        typeof(RemotingSample.RemoteObject),
                        "ipc://Server/RemotingServer");
            if (remObject == null)
            {
                Console.WriteLine("cannot locate server");
            }
            else
            {
                remObject.ReplyMessage("You there?");
            }
            return 0;
        }
    }
}

// Shared Library:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;

namespace RemotingSample
{
    public class RemoteObject : MarshalByRefObject
    {
        public RemoteObject()
        {
            Console.WriteLine("Remote object activated");
        }
        public String ReplyMessage(String msg)
        {
            Console.WriteLine("Client : " + msg);//print given message on console
            return "Server : I'm alive !";
        }
    }
}

TextWriter.SynchronizedTextWriter.Synchronized方法。

http://msdn.microsoft.com/en-us/library/system.io.textwriter.synchronized.aspx

这应该使您可以执行此操作:

TextWriter.Synchronized(writer).Write(serializedCache);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM