免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5859 | 回复: 12
打印 上一主题 下一主题

[原创] PHP文件锁定读写的一点注意 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-02-08 00:44 |只看该作者 |倒序浏览
都说文本方式容易出现文件锁定失效等乱七八糟的问题.

其实并不是失效, 而是写法有些不对, 尤其是在 win32之类的平台下运行时更要注意.

被 lock_ex 后的文件 再以read模式 fopen 的话将读到空内容!!!

如果没有判断就把它当作空做操作后再写入就出错啦....

很多问题出在这里.


再来补充一下

如果一个文件被以write的模式fopen后并 flock(..LOCK_EX)的话

有另一个程序这时去 fopen 它,并且也要 flock(LOCK_EX) 的话,  这肯定出错.

因为第二个fopen时文件的size可能已经被 truncate 成 0 了..

------------- 下面做一个测试 ---------------

测试程序1.  :::: 1.php
<?php
$fd = fopen("./test.txt", "w";
flock($fd, LOCK_EX);
sleep(10);
fwrite($fd, "hightman";
flock($fd, LOCK_UN);
fclose($fd);
?>;

测试程序2.  ::::: 2.php
<?php
  $fd = fopen("./test.txt", "r";
   echo fread($fd, 512);
   fclose($fd);
?>;
测试程序3  :::::: 3.php
<?php
    if ($fd = @fopen("./test.txt", "r+") {
        flock($fd, LOCK_EX);
        fseek($fd, 0, SEEK_END);
        fwrite($fd, "shit";
        flock($fd, LOCK_UN);
        fclose($fd);
    }
?>;

程序测试方法 1: 运行 1.php 然后马上去运行 2.php  ,  2.php 的输出结果是空.
             2: 运行 1.php 然后马上去运行 3.php,  3.php 将在 1.php 运行结束后才能结束
                不过结果文件内容是: "shit" 而不是 "hightmanshit"

所以特别要注意write时的情况
"w", "r+", "a", "a+" 都要注意文件长度为0的情况!可能文件是空,也可能是被flock

论坛徽章:
0
2 [报告]
发表于 2004-02-08 00:51 |只看该作者

[原创] PHP文件锁定读写的一点注意

对于这种情况我一般都不用锁定,直接 rename 之后再处理。如果有意外和处理完毕再 rename 回去

论坛徽章:
0
3 [报告]
发表于 2004-02-08 00:53 |只看该作者

[原创] PHP文件锁定读写的一点注意

本人作过相当多的测试,用rename效率很差的

论坛徽章:
0
4 [报告]
发表于 2004-02-08 01:12 |只看该作者

[原创] PHP文件锁定读写的一点注意

hi hightman, i m cx@ctb

2: 运行 1.php 然后马上去运行 3.php, 3.php 将在 1.php 运行结束后才能结束
不过结果文件内容是: "shit" 而不是 "hightmanshit"


这个跟我得到的结果不同,3.php 将在 1.php 运行结束后才能结束 没错,但结果文件内容是: "hightmanshit"

论坛徽章:
0
5 [报告]
发表于 2004-02-08 01:12 |只看该作者

[原创] PHP文件锁定读写的一点注意

原帖由 "财狼" 发表:


这个跟我得到的结果不同,3.php 将在 1.php 运行结束后才能结束 没错,但结果文件内容是: "hightmanshit"


en, Unix类的系统下的结果是正确的,但WIN32是模拟的FLOCK所以会失败.

论坛徽章:
0
6 [报告]
发表于 2004-02-08 01:18 |只看该作者

[原创] PHP文件锁定读写的一点注意

你说反了吧,3.php不就是要在结尾加上shit吗?hightmanshit的结果证明锁定成功了

另外,3.php改为:
  1. <?php
  2. if ($fd = @fopen("./test.txt", "a")) { //or a+
  3. flock($fd, LOCK_EX);
  4. fwrite($fd, "shit");
  5. flock($fd, LOCK_UN);
  6. fclose($fd);
  7. }
  8. ?>;
复制代码


是不是要简洁一些?

论坛徽章:
0
7 [报告]
发表于 2004-02-08 01:26 |只看该作者

[原创] PHP文件锁定读写的一点注意

呵呵,详细测试过你会发线 "a" 和 "r+"再fseek是效果不一样的,

我只想证明一下锁定不安全,在 unix之类系统下用 "a"模式是较为安全的,不过 "a" 只会把东西写在最后,也就是 fwrite前似乎会自动 fseek(..0, SEEK_END), 你可以试试用 "a"模式打开,然后 fseek(x,0,SEEK_sET)再fwrite,会发现东西仍然被写在最后,呵呵
而 "r+"后立即fseek的话,该文件如果恰好被另一个进程改动过的话,FWRITE时是不会再加在最后的.

论坛徽章:
0
8 [报告]
发表于 2004-02-08 01:26 |只看该作者

[原创] PHP文件锁定读写的一点注意

还有你的 2.php 犯了一个错误,之所以没有读出内容是因为没有锁定,改成:

  1. <?php
  2. $fd = fopen("./test.txt", "r");
  3. flock($fd, LOCK_SH); // or LOCK_EX
  4. echo fread($fd, 512);
  5. flock($fd, LOCK_UN);
  6. fclose($fd);
  7. ?>;
复制代码


在 1.php 运行之后立即运行 2.php,可以得到正确的“hightman”,不过要在 1.php 运行结束之后。winxp/fat32/PHP4.34

不过手册上fread之前都是不flock,这点的确要小心

论坛徽章:
0
9 [报告]
发表于 2004-02-08 01:29 |只看该作者

[原创] PHP文件锁定读写的一点注意

原帖由 "财狼" 发表:

在 1.php 运行之后立即运行 2.php,可以得到正确的“hightman”,不过要在 1.php 运行结束之后。winxp/fat32


结束之后当然行了,如果有很多连接进程在同时访问就会出现 1.php还没结束就执行2.php 的操作了...

就拿计数器来说吧,一般是读出其中的老数据作 ++再写回去...
如果此时计数文件被锁定中...另一进程读取出来作++时会因为读成空值而当成0,这时数据就不对了嘛.

论坛徽章:
0
10 [报告]
发表于 2004-02-08 01:35 |只看该作者

[原创] PHP文件锁定读写的一点注意

不,你没看清我的原话,

在 1.php 运行之后立即运行 2.php,可以得到正确的“hightman”,不过要在 1.php 运行结束之后--2.php 才能继续运行,得到正确的结果。

如果 2 不锁,那就不会等待 1,立即返回一个空值
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP