Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1354471
  • 博文数量: 334
  • 博客积分: 10302
  • 博客等级: 上将
  • 技术积分: 2986
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-12 10:17
文章分类

全部博文(334)

文章存档

2013年(1)

2012年(9)

2011年(4)

2010年(10)

2009年(24)

2008年(64)

2007年(72)

2006年(150)

我的朋友

分类:

2007-07-02 13:53:37

利用Windows   API判断文件共享锁定状态      
  一、概述  
   
  锁是操作系统为实现数据共享而提供的一种安全机制,它使得不同的应用程序,不同的计算机之间可以安全有效地共享和交换数据。要保证安全有效地操作共享数据,必须在相应的操作前判断锁的类型,然后才能确定数据是否可读或可写,从而为开发出健壮的程序提供切实依据。    
  同样,在Windows中,文件可以共享模式打开,它也涉及到锁的操作问题。根据Windows中文件共享时加锁范围的大小,锁可分为全局锁和局部锁;全局锁以锁定文件全部内容为特征,而局部锁以锁定文件的局部内容为特征,且文件的锁定区域不可重复。根据Windows中文件共享时锁的操作权限分类,锁可分为:读锁,写锁,读写锁(可读可写,全局锁)。    
  利用上述文件中锁的区域不可重复的特性,我们可尝试给指定文件加一全局锁。若加锁成功,说明指定文件未被其它进程锁定;否则,说明有其它进程锁定了该文件。这里,我们利用两个Windows   Api文件操作函数:OpenFile和CreateFile来实现锁定状态的判断。    
   
  二、实现方法    
  1.   OpenFile函数使用说明    
  函数原型:function   OpenFile(const   lpFileName:   LPCSTR;   var   lpReOpenBuff:   TOFStruct;    
  uStyle:   UINT):   HFILE;   stdcall;    
  函数功能:以不同方式打开文件的操作(为兼容16位Windows程序保留的函数)。建议    
  Windows下使用CreateFile函数。    
  参数说明:lpFileName:   要打开文件的名称    
  lpReOpenBuff:   变量指针,用于存储文件被首次打开时接收信息。    
  UStyle:   打开文件的常量类型。    
  常量名    
  意义    
   
  Of_Create    
  创建文件    
   
  Of_Delete    
  删除指定文件    
   
  Of_Exist    
  打开文件以验证其存在否?存在,返回一无效句柄;否则,返回负数    
   
  Of_Parse    
  填充lpReOpenBuff内容,但不进行任何操作    
   
  Of_Prompt    
  如存在不存在,则显示一有重试和取消按钮的消息框    
   
  Of_Read    
  只读方式打开    
   
  Of_ReadWrite    
  读写方式打开    
   
  Of_ReOpen    
  打开lpReOpenBuff内指定的文件,而不依据lpFileName    
   
  Of_Search    
  强迫Windows查找文件---即使指定了文件路径    
   
  Of_Share_Compat    
  文件可由多个程序多次打开    
   
  Of_Share_Deny_None    
  共享打开    
   
  Of_Share_Deny_Read    
  禁止其它程序读该文件    
   
  Of_Share_Deny_Write    
  禁止其它程序写该文件    
   
  Of_Share_Exclusive    
  独占方式打开文件,其它程序不得再打开该文件    
   
  Of_Write    
  只写方式打开    
   
       
  返回值:成功,返回值为文件句柄(但可能无效,如:Of_Exist);出错,返回HFile_Error。    
  2.   CreateFile函数使用说明    
  函数原型:function   CreateFile(lpFileName:   PChar;    
  dwDesiredAccess,   dwShareMode:   DWORD;    
  lpSecurityAttributes:   PSecurityAttributes;    
  dwCreationDisposition,   dwFlagsAndAttributes:   DWORD;    
  hTemplateFile:   THandle):   THandle;   stdcall;    
  函数功能:以不同方式打开文件的操作,还可操作管道、邮槽、通信服务、设备以及控    
  制台等。    
  参数说明:   lpFileName:   要打开文件的名称    
  dwDesiredAccess:期望存取模式    
  取值   0:只允许获取一个设备的相关信息。    
  Generic_Read:只允许读设备    
  Generic_Write:只允许写设备(二者可组合使用)。    
  dwShareMode:共享模式。    
  取值   0:   不共享。    
  File_Share_Read和/或File_Share_Write:共享读和/或写。    
  lpSecurityAttributes:   定义文件安全特性的指针(前提:操作系统支持)。    
  DwCreationDisposition:   打开和创建文件方式。    
  取值   Create_New:   总创建新文件,如文件已存在,则出错。    
  Create_Always:   总创建新文件(会覆盖旧文件)。    
  Open_Existing:   打开已存在的文件,若文件不存在,则出错。    
  Open_Always:   总打开文件,如不存在,则创建。    
  dwFlagsAndAttributes:   要打开文件的标志和属性(如:隐藏,系统等)。    
  一般用File_Attribute_Normal,默认属性。    
  hTemplateFile::模板文件句柄。    
  若非0则指定一个文件句柄;否则,新文件将从这个文件复制    
  扩展属性。    
  返回值:成功,返回值为文件句柄;出错,返回Invalid_Handle_Value。    
   
  3。程序实现    
  利用上述两个函数,我们可编写程序判断某文件是否正在被其它进程锁定,以下为详细代码。    
  //利用OpenFile   Api函数判断    
  function   FileLocked(Fn:   string):   Boolean;    
  var    
  I   :   Integer;    
  Struct:   TOfStruct;    
  Style:   Cardinal;    
  Hdl:   Hfile;    
  Drive:   String;    
  begin    
  Style   :=   OF_Share_Exclusive;   //排它方式打开    
  Drive   :=   UpperCase(Fn[1]);    
  Struct.fFixedDisk   :=   Ord(Drive   <>   ’A’);   //判断是否是硬盘    
  Struct.cBytes   :=   SizeOf(Struct);    
  For   I   :=   1   to   Length(Fn)   do    
  Struct.szPathName[I-1]   :=   Fn[I];    
  Struct.szPathName[I]   :=   Chr(0);   //填充文件名    
  Hdl   :=   OpenFile(Pchar(Fn),   Struct,   Style);    
  if   Hdl   =   HFILE_ERROR   then    
  begin    
  Result   :=   True;   //文件被锁定    
  Showmessage(SysErrorMessage(GetLastError));   //显示错误原因    
  end    
  else    
  Result   :=   False;    
  end;    
   
  //利用CreateFile   Api函数判断    
  function   LockedFile(Fn:   string):   Boolean;    
  var    
  AFile:   THandle;    
  SecAtrrs:   TSecurityAttributes;    
  begin    
  FillChar(SecAtrrs,   SizeOf(SecAtrrs),   #0);    
  SecAtrrs.nLength   :=   SizeOf(SecAtrrs);   //结构体长度    
  SecAtrrs.lpSecurityDescriptor   :=   nil;   //安全描述    
  SecAtrrs.bInheritHandle   :=   True;   //继承标志    
  AFile   :=   CreateFile(PChar(Fn),   GENERIC_READ   or   GENERIC_WRITE,    
  FILE_SHARE_Read,   @SecAtrrs,   OPEN_EXISTING,    
  FILE_ATTRIBUTE_Normal,   0);    
  if   AFile   =   INVALID_HANDLE_VALUE   then    
  begin    
  Result   :=   True;   //文件被锁定    
  showmessage(SysErrorMessage(GetLastError));    
  end    
  else    
  Result   :=   False;    
  end;    
   
  4。程序的测试    
  在Delphi中新建一Application,在Form1的OnCreate事件中写入:    
  if   Not   FileLocked(‘c:\windows\desktop\a.txt’)   then   Showmessage(‘Cannot   Open   1’);    
  或    
  if   Not   LockedFile   (‘c:\windows\desktop\a.txt’)   then   Showmessage(‘Cannot   Open   2’);    
  再新建一批处理文件保存到桌面上,内容为:    
  dir   c:\*.*/s>c:\windows\desktop\a.txt’    
  运行此批处理文件,然后运行上述Delphi程序。这时候会出现消息框“其他进程正使用该文件,   因此现在无法访问。”。当批处理命令运行完毕后,再运行此程序则不会出现此信息。此时,再双击a.txt文档,记事本程序将无法打开该文档,说明加锁成功。    
   
  三、结束语    
  以上用两种方法实现了如何判断一个文件是否正被其它进程锁定。其中,方法一实现较为简单,但兼容性不好;而方法二为Windows推荐的方法,且功能强大。    
  利用以上实现方法,较好地解决了Windows下文件锁定状态判断的问题。为避免发生共享冲突和提高文件操作程序的健壮性提供了很好的参考依据。     
   
阅读(1632) | 评论(0) | 转发(0) |
0

上一篇:可恶的移动

下一篇:Delphi中的线程类

给主人留下些什么吧!~~