C#IO读写文件使用错误
我有一个处理读写缓存文件的库。此库由同一台计算机上的Windows服务和控制台应用程序的多个实例使用。当用户登录时,控制台应用程序将运行 我偶尔会收到IO错误,说缓存文件正在被另一个进程使用。我假设不同的应用程序实例和试图同时读写的服务之间发生冲突 是否有一种方法可以在文件使用时锁定该文件,并强制所有其他请求“排队等候”以访问该文件C#IO读写文件使用错误,c#,file-io,C#,File Io,我有一个处理读写缓存文件的库。此库由同一台计算机上的Windows服务和控制台应用程序的多个实例使用。当用户登录时,控制台应用程序将运行 我偶尔会收到IO错误,说缓存文件正在被另一个进程使用。我假设不同的应用程序实例和试图同时读写的服务之间发生冲突 是否有一种方法可以在文件使用时锁定该文件,并强制所有其他请求“排队等候”以访问该文件 private void SaveCacheToDisk(WindowsUser user) { string serializedCach
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;
}
}
}
当然,只有在持有互斥锁时,才能使用和允许访问。请查看
TextWriter.Synchronized
方法
这应该让您可以这样做:
TextWriter.Synchronized(writer).Write(serializedCache);
您可以使用交叉过程。这允许您创建和使用通过名称跨进程标识的WaitHandle。一个线程在轮到它的时候被通知,做了一些工作,然后指示它已经完成,允许另一个线程继续 请注意,这仅在每个进程/线程都引用同一个命名的WaitHandle时才有效
在它们的签名中使用字符串创建命名的系统同步事件。
< P>一个选项,您可以考虑让控制台应用程序通过服务路由他们的文件访问,这样只有一个进程访问文件,并且可以同步访问其中的文件。 实现这一点的一种方法是通过(这里来自weblogs.asp.net)。我们在我工作的公司的一个项目中使用了这项技术,效果很好,我们的具体案例为.net Web服务提供了一种与运行在同一台机器上的Windows服务对话的方法 基于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 !";
}
}
}
+1:这看起来正是OP需要的。事实上,
StreamWriter
类上的MSDN明确建议将StreamWriter
替换为TextWriter.Synchronized
,如果需要线程安全的输出。Synchronized是一种静态方法。我相信这只适用于进程内同步。问题n实际上是进程间同步,只有互斥体才有操作系统级别的作用域。这不起作用。我将它应用于每个StreamReader和StreamWriter。不过谢谢你的建议。@Aaronaught:哦,是的,你说得对。我没有对OP想要的东西给予足够的关注。@Rob这听起来很有趣。你能解释一下b吗它提供了更多或一些psuedo代码?很抱歉,我以前从未做过类似的事情。@modernzombie-我能建议的最好方法是,您在两个参考页面中的一个页面上按照示例进行操作,我将尝试编写一个更简单的示例,因此请注意以下空间:)@Rob谢谢。当我发布评论时,我没有看到这两个示例。令人恼火的是,weblogs.asp.net中的示例无法直接运行。我将在我编译并运行(基于它)的答案中加入一个代码示例,该答案适用于我=)@robawesome。我真的很感激!我现在正在尝试。