【问题标题】:Fwrite random behaviorFwrite 随机行为
【发布时间】:2015-07-29 19:57:35
【问题描述】:

我正在尝试编写一个读取文件并对其进行编辑的脚本,我正在使用 fopen 进行。

我的问题是,当fwrite它应该输入单词TEST它也会删除一些东西并输入一些数字没有理由。

这是我的代码:

if (($gestor = fopen("files/prueba.pim", "c+")) !== FALSE) {
    while (($datos = fgetcsv($gestor, 1000, "<br>")) !== FALSE) {
        $numero = count($datos);
        for ($c=0; $c < $numero; $c++) {
            if ("G81"==substr($datos[$c], 0, 3)){
                fwrite($gestor, "COMIENZO DE CICLO".PHP_EOL);
            }else {
           if (";"!=substr($datos[$c], 0, 1))  echo utf8_encode($datos[$c]."\n");
            if ("X"==substr($datos[$c], 0, 1) or "Y"==substr($datos[$c], 0, 1))
                fwrite($gestor, "TEST".PHP_EOL);
        }
    }
    }
    fclose($gestor);
}

回声仅用于测试目的。

我无法正确粘贴输入和输出不知道为什么所以我将它粘贴到 pastebin 抱歉。

正如您在输出中看到的,G81 I-1. F500. 之后的 2 行刚刚消失,随机数和空格也出现在以 Y 开头的某些行中。

【问题讨论】:

  • 在你的代码中你只写了COMIENZO DE CICLOTEST,但是在提供的输出中我看到了更多的数据。也许你也在其他地方写文件?此外,如果您希望附加到文件,请使用 a 标志而不是 cc 将覆盖文件开头的内容)
  • 感谢您的评论 @Justinas ,但正如您所见,使用 c+ 并没有覆盖文件。你能告诉我你还看到了什么数据吗?我不知道你在说什么。对不起,如果这听起来太粗鲁,在我看来,但我不知道用英语怎么说^^
  • 您应该尝试创建一个较小的测试用例 - 请参阅 stackoverflow.com/help/mcve 了解为什么这对您和我们都有帮助的一些提示和解释。
  • 你混合读取和写入同一个文件。当然,你会弄得一团糟。打开一个新文件进行写入。从第一个文件 (fgetcsv()) 中读取数据,对其进行处理,然后将结果放入第二个文件 (fwrite())。关闭这两个文件,然后删除输入文件(或重命名,以保留它作为备份)并用第一个文件的名称重命名第二个文件。
  • 这是现在的输入 G81 I-1. F500. X-79.803 Y64.947 X-81.468 Y67.451 X-86.995 Y64.947 X-97.3 Y68.781 X-107.603 Y64.947 X-109.268 Y67.451 X-114.433 Y66.373 X-119.304 Y66.445 Y78.111 和这个 otuput G81 I-1. F500. COMIENZO DE CICLO X-81.468 Y67.451 TEST 95 Y64.947 X-97.3 Y68.781 TEST 603 Y64.947 X-109.268 Y67.451 TEST 433 Y66.373 X-119.304 Y66.445 TEST 1 你看到的仍然写随机数,试试@axiac 说的。

标签: php fopen fwrite


【解决方案1】:

为什么它不像你认为的那样有效

您认为的随机数实际上是输入文件的一部分。因为你从一个文件中读取然后写入它,所以你会覆盖输入文件中的行片段。

例如,输入文件中的16-19 行读取:

G81 I-1. F500.
X-79.803
Y64.947
X-81.468 Y67.451

代码使用 (fgetcsv()) 读取行 17,然后写入 COMIENZO DE CICLO,然后在当前文件指针位置(位于行 18 的开头)处添加新行。 1718 行包含 15 个字符和两个换行符。看来您正在 Windows 上运行代码;它使用两个字符来表示一个新行,两行总共有 19 个字符。

COMIENZO DE CICLO 恰好有 17 个字符;你写的新行增加了两个字符,总共也有 19 个字符。这样一来,输入中的1718 行将完全替换为包含文本COMIENZO DE CICLO 的单行。

这是16-18 行在输出文件中的显示方式:

G81 I-1. F500.
COMIENZO DE CICLO
X-81.468 Y67.451

fgetcsv() 的下一次调用从当前文件指针位置读取,这是在18 行的开头(它曾经是fwrite() 之前的19 行;行号用于人类,代码使用从文件开头的偏移量来保持他们的内部预订。)原始行的内容18Y64.947)被代码忽略然后覆盖。它没有被处理就丢失了。

文件中的下一行(原始文件中第一个fwrite()19-21 之后的行18-20):

X-81.468 Y67.451
X-86.995 Y64.947
X-97.3 Y68.781

代码读取18 (X-81.468 Y67.451) 行并决定它必须为fwrite('PRUEBA'.PHP_EOL)。当前文件指针位于19 行的开头(X-86.995 Y64.947 行)。 fwrite('PRUEBA'.PHP_EOL) 覆盖该行的第一个 6+2 字符:

X-86.995 Y64.947               <--- original
^^^^^^^^
PRUEBA..                       <--- replacement

(我使用点而不是换行符)将其更改为:

PRUEBA
 Y64.947

Y64.947 之前有一个空格字符。它在输入文件中并且未被覆盖。

X-86.995 部分在没有被读取的情况下永远丢失了,下一次调用fgetcsv() 会读取 Y64.947 行,并且可能不会执行您想要的操作。

这样一直持续到文件末尾。

如何做对

以下代码显示了如何正确处理文件。您需要使用将从输入文件读取的不需要替换的片段放入输出文件的代码来完成它。这段代码要插入的地方标有一个大注释,还建议在那里写什么。

$gestor = fopen("files/prueba.pim", 'r');
$output = fopen('files/output.txt', 'w');

// Test if fopen() succeeded for both files
if ($gestor == FALSE || $output == FALSE) {
    // Handle the error somehow (return from function or exit the program
    // or display an error, it depends on your application).        
    exit(1);
}


// Read, process, write
while (($datos = fgetcsv($gestor, 1000, "<br>")) !== FALSE) {
    $processed = FALSE;
    $numero = count($datos);
    for ($c = 0; $c < $numero; $c ++) {
        if ("G81" == substr($datos[$c], 0, 3)) {
            fwrite($output, "COMIENZO DE CICLO".PHP_EOL);
            $processed = TRUE;
        } else {

//         if (";" != substr($datos[$c], 0, 1)) {
//             echo utf8_encode($datos[$c]."\n");
//         }

           if ("X" == substr($datos[$c], 0, 1) or "Y" == substr($datos[$c], 0, 1)) {
               fwrite($gestor, "TEST".PHP_EOL);
            $processed = TRUE;
           }
        }
    }

    // Here you probably need to fwrite($output) the rows that didn't match
    // the conditions above (nothing was output for them)
    //
    // This is how I would write it:
    //     if (! $processed) {
    //         fwrite($gestor, implode('<br>', $datos).PHP_EOL);
    //     }                             ^
    //       +---------------------------+
    // Put here the same string you used as the third argument to fgetcsv()
}

// Close both files then rename them
fclose($gestor);
fclose($output);

// Remove the previous backup, if any
if (file_exists('files/prueba.pim.backup')) {
    unlink('files/prueba.pim.backup');
}
// Backup the input file
rename('files/prueba.pim', 'files/prueba.pim.backup');
// Replace the input file with the output file
rename('output.txt', 'files/prueba.pim.backup');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 2016-03-29
    • 2013-04-21
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多