PHP:文件写入问题
我正在尝试创建一个为玩家编写分数列表的函数。
例如:
player_1 100 12 12 10
player_2 39 13 48 29
当玩家击败(或做得更差)之前的分数时,他们的分数将被新分数覆盖。
我编写了一个可以工作的函数,但存在多个问题。
function write($player)
{
global $logfile;
$lines = file($logfile);
foreach($lines as $i => $line)
{
$pieces = explode(" ", $line);
$pieces[0] = trim($pieces[0]);
if( $pieces[0] == $player->name ) //found name
{
trim($lines[$i]);
unset($lines[$i]); //remove the old player data
$lines[$i] = "{$player->name} {$player->lvl} {$player->exp} {$player->mana} \n"; //write the new score
$fp = fopen($logfile,'a');
fwrite($fp,$lines[$i]);
$found = TRUE;
break;
}
}
if(!$found) //record a new player whose score isn't in the file
{
$fp = fopen($logfile,'a');
$newp = "$player->name $player->lvl $player->exp $player->mana \n";
fwrite($fp, $newp);
}
fclose($fp);
}
该文件仅附加新分数,不会覆盖以前的分数。有人可以指出我的错误吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尝试将:更改
为
PHP.fopen 文件打开模式 ;)
编辑
您可以通过在 foreach 循环之后放置
fwrite()
来覆盖您的播放器条目,方法是使用 joined 行覆盖整个文件(这可能会导致性能问题)。或者
尝试使用
fgets()
逐行循环,然后如果找到正确的匹配项,请使用fseek()
到上一行并覆盖它;)fgets() fseek()
第二次编辑
根据要求提供代码示例;) 这个想法是保存上一行的位置,然后将其用于
fseek
和覆盖。我不确定fwrite
是否能在行尾没有PHP_EOL
的所有环境下正常工作,但在我的环境中效果很好。Try changing:
into
in your
PHP.fopen file open modes ;)
EDIT
You can override your player entry by putting the
fwrite()
after foreach loop by overriding the whole file with joined lines (this may cause performace issues).Or
Try to loop line by line using
fgets()
and then if you will find the right match usefseek()
to the previous line and override it ;)fgets() fseek()
SECOND EDIT
Code sample as requested ;) The idea is to save previous line position and then use it to
fseek
and override. I'm not sure if thefwrite
will work well on all enviroments withoutPHP_EOL
at the end-of-line, but on mine it's fine.首先,让我们看看它重复记录的原因。
$lines
是一个数组,您将在其中更新特定玩家的记录。但是在更新记录后,您将其附加到文件中(使用“a”模式),因此复制了该播放器的条目。想法应该是更新文件中的记录。根据您的逻辑,最好的办法是将
$lines
重写到文件中。由于$lines
将始终包含更新的条目,因此这是有道理的。现在进入为新玩家创建条目的逻辑。该逻辑没有任何问题,但可以通过将新条目附加到
$lines
而不是写入文件来改进。这是更新后的代码。请注意,我删除了不需要的行。
希望有帮助!
First, let us see the reason why it duplicates the record.
$lines
is an array in which you are updating the record of the specific player. But after updating the record, you are appending it to the file (using "a" mode) and therefore duplicating the entry of that player.The idea should be to update that record in the file. And with your logic, the best thing is to rewrite
$lines
to the file. Since$lines
will always contain the updated entry, it makes sense.Now coming to the logic where you are making an entry for a new player. There is nothing wrong in that logic but it could be improved by appending the new entry to
$lines
instead of writing to the file.Here is the updated code. Please note that I've removed lines that weren't needed.
Hope it helps!
这段代码是否运行在有许多用户同时访问的Web服务器上?
如果是,想象一下当一个用户刚刚打开文件进行写入,文件被清空,而另一个用户在第一个用户完成写入数据之前打开它进行读取时,会发生什么情况。
部分解决方案是写入临时文件,并在完成后将临时文件重命名为原始文件。重命名是原子性的,因此用户将看到原始文件或新文件,而不是介于两者之间的文件。
但您仍然会错过一些更新。您可以锁定文件,这意味着当一个人正在写入时另一个人无法读取。为此,您可以使用集群函数: http://php.net/manual/en /function.flock.php
正确的解决方案是使用真实的数据库。例如,Sqlite 很好而且简单:没有外部服务器进程或密码......
Is this code run on a web server with many users accessing at the same time?
If it is, imagine what happens when one user has just opened the file for writing, the file is emptied, and another opens it for reading before the first one has finished writing the data.
A partial solution is write to a temp file and rename the temp as the original when you are done. Rename is atomic, so the users will see either the original file or the new one and not something in between.
But youll still miss some updates. You could lock the file, meaning that when one person is writing another can't read. To do that you would use the flock function: http://php.net/manual/en/function.flock.php
The proper solution is using a real database. Sqlite for example is nice and simple: no external server processes or passwords...