转到更新以阅读现在的实际问题。Bert Peters 提交的第一个答案已经解决了旧问题。
老问题: 我有几个名为 file.1.txt、file.2.txt、file.3.txt 的文件……我正在使用 SplFileObject 读取第一个文件并使用 foreach 循环遍历其内容:
$file = new SplFileObject("file.1.txt");
foreach ($file as $row) {
// ...
}
其他文件可能会被读取,也可能不会被读取,这取决于我正在读取的第一个文件的内容。在所有情况下,都应该只有一个文件(file.2.txt 或 file.3.txt)可以在下一步中使用。所以在 foreach 循环中的某个地方有 if 语句来处理这个问题。
所有文件都具有相同的结构,因此出现了问题。我不想创建新的 foreach 来读取下一个文件 - 正如我所写的那样,它可能根本不需要,所以我想使用现有的 foreach 而不是编写新的。是否有可能用其他文件的内容覆盖 $file 变量并仅使用一个 foreach 或任何其他循环对其进行迭代?例如:
foreach ($file as $row) {
// ...
if ($contentContainsSomething) {
$file = new SplFileObject("file.2.txt");
// somehow reset foreach to read file.2.txt from start
}
}
我不想用goto
语句来解决这个问题。递归似乎是合适的解决方案,但如果有办法动态更改循环中的对象,我更喜欢这个解决方案。
更新: 如“老问题”中所述,所有使用的文件(file.1.txt、file.2.txt、...)都具有相同的结构,所以我不想编写更多相同的循环并复制代码. 相反,我使用了来自@Danack 的代码(他在 SO 聊天中建议),这已经是解决方案的一部分。这是无需任何升级即可读取更多文件的基本代码:
$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
$file = new SplFileObject($path);
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl("\t");
$path = null;
foreach ($file as $rowKey => $row) {
// echo row }
$path = "file.2.txt";
if ($whileCounter > 0) {
break; // solution to stop loop, just for now
}
$whileCounter++;
}
因此,此代码可以正常工作并按预期输出文件的行。问题是当我想用 seek() 方法读取文件的下一行时,因为我想对附加到下一行的一些信息做出决定。因此,如果我使用 seek($rowKey + 1) 帮助我获取下一行数据(我在行更改时使用 $file->current() )然后我调用 seek($rowKey) 到上一行,然后下一个文件将输出第一行两次,第二行将被遗漏。第三行以及之后的所有内容都打印得很好。这是通过以下代码实现的问题:
$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
$file = new SplFileObject($path);
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl("\t");
$path = null;
foreach ($file as $rowKey => $row) {
if ($whileCounter > 0) {
var_dump($row);
echo "<br>";
}
$file->seek($rowKey + 1);
if ($file->valid()) {
$file->seek($rowKey);
} else {
var_dump($row);
echo "<br>";
$path = "file.2.txt";
}
}
$whileCounter++;
}
如果您应用自定义 .csv 文件(至少有五个非空行)而不是 file.1.txt 和 file.2.txt,您将看到第二个和第三个输出是相同的(第二个和第三个输出是第一个和file.2.txt 的“第二”行)。这里有什么问题?