【问题标题】:how to parse multiple rows from a csv file using php如何使用php解析csv文件中的多行
【发布时间】:2015-02-10 12:03:43
【问题描述】:

我有 2 个 .csv 文件,它们的第一列具有相似的值,包含的代码仅针对一行执行此任务,它仅执行一次迭代,请帮我修改代码...

hostrefined.csv contents...
name1,23423,detail1
name2,12312,detail2
name3,21312,detail3

hbarefined.csv contents...
name1,det1,det2,2323
name1,det3,det4,23434
name1,det5,det6,34343
name2,det9,det7,232322
name3,det10,det28,232

the output file has to be like

name1,23423,detail1,det1,det2,2323
name1,23423,detail1,det3,det4,23434
name1,23423,detail1,det5,det6,34343
name2,12312,detail2,det9,det7,232322
name3,21312,detail3,det10,det28,232

这里是代码

$handle = fopen("hostsrefined.csv", "r");
$handle1 = fopen("hbarefined.csv", "r");

$fp=fopen('test.csv','w');
while($data1 = fgetcsv($handle1, 1000, ","))
{
while($data = fgetcsv($handle, 1000, ","))
{
    if($data1[0]==$data[0])
    {
        for($s=0;$s<9;$s++)  // to write data from first .csv file
        {

            fwrite($fp,$data[$s]);
            fwrite($fp,",");
        }
        for($s=1;$s<6;$s++)     // to write data frm second .csv file
        {


                fwrite($fp,$data1[$s]);
                fwrite($fp,",");

        }

    }

    fwrite($fp,"\n");
}fwrite($fp,"\n");

}

【问题讨论】:

  • CSV 文件中有什么内容?
  • 我不明白。你能说得更具体点吗?
  • 请更具体地说明您要做什么。如果没有更多信息,您的代码很难阅读。此外,来自两个 csv 文件的一些测试数据会很好。你想用 csv1 和 csv2 的子集创建第三个 csv 文件,我理解了吗?
  • 这与 PHPExcel 库无关,因此删除该标签
  • 复制while循环并将$handle1更改为$handle,甚至将循环放入函数并传递句柄。然后执行两次编写的函数:第一次使用$handle1 第二次使用$handle

标签: php parsing csv export-to-csv


【解决方案1】:

首先,让我们调试您的脚本。如果您遵循您的算法并仔细查看 php 的文件处理,那么为什么您只为第一行获得所需结果的问题是显而易见的。

您在脚本的开头打开了这两个文件。 PHP 在文件的开头为每个文件设置一个文件指针。让我们在第一行更容易理解。

您的第一个 while 循环遍历您的详细信息文件 (hbarefined.csv),您希望根据每个文件中相等的第一个字段在其中加入内容。然后,您启动一​​个 while 循环,读取 hostrefined.csv 的每一行。如果您找到具有所需主键的行,则将 hbarefined 和 hostrefined 这两行的内容连接起来,并将其写入 test.csv。在这里,我们有您脚本的前 2 个故障。

  1. 即使您的主键不匹配,您也要在 test.csv 中写一个新行。结果看起来很难看。

  2. 您正在自己为 test.csv 创建 csv 格式。不!看看fputcsv()

您不知道的是,您的第二个 while 循环会在每次迭代时将 hostrefined.csv 的文件指针向前移动一行,但在到达文件末尾时不会重置它。因为您为 hbarefined.csv 的每一行通读了整个 hostrefined.csv,所以在第一个 while 循环的第一次迭代之后就到达了终点。您的第一个 while 循环的第二次和所有即将进行的迭代在 hostrefined.csv 的末尾开始读取,因此永远不会找到匹配的行。您需要在第一个 while 循环的每次迭代结束时使用 rewind()

$handle = fopen("hostsrefined.csv", "r");
$handle1 = fopen("hbarefined.csv", "r");

$fp=fopen('test.csv','w');
while($data1 = fgetcsv($handle1, 1000, ","))
{
while($data = fgetcsv($handle, 1000, ","))
{
    if($data1[0]==$data[0])
    {
        for($s=0;$s<9;$s++)  // to write data from first .csv file
        {

            fwrite($fp,$data[$s]);
            fwrite($fp,",");
        }
        for($s=1;$s<6;$s++)     // to write data frm second .csv file
        {


                fwrite($fp,$data1[$s]);
                fwrite($fp,",");

        }

    }

    fwrite($fp,"\n");
}
fwrite($fp,"\n");
rewind($handle);
}

这将修复您的脚本。

一些一般说明: 你的代码很难阅读,这让我很难调试和修复。正确使用缩进,并为新命令使用新行,例如:

while($data = fgetcsv($handle, 1000, ","))
{
    // ...some code
}fwrite($fp,"\n");

另外,请尽量清楚地使用您的变量名。连续 2 次在 for 循环中使用 $s 作为索引变量会让人很困惑。 $fp 是什么?你明白我...

我重写了你的代码供你参考:

<?php
/**
 * Goal of this script is to read a csv-file with a primary-key (input-primary.csv)
 * in field 0 and join contents from a second csv-file (input-detail.csv).
 * Each row in input-detail.csv has the primary key from input-primary.csv
 * in field 0 as well.
 * This script needs php version 5.4 o higher
 */

/**
 * First, we define some helper functions
 */

/**
 * Read csv-contents from $filename and return it indexed by primary-key.
 * Primary-key is in field 0
 * 
 * @param string $filename file to read
 * @return array
 */
function getCsvContentIndexedByPrimaryKey($filename)
{
    $handle = fopen($filename, 'r');
    $indexedContents = [];
    while (false !== $row = fgetcsv($handle)) {
        $primaryKey = $row[0];
        $indexedContents[$primaryKey] = $row;
    }

    return $indexedContents;
}

/**
 * Joins contents from $row and $indexedContents by index taken from 
 * field 0 of $row. Primarykey-field of $row will be unset. If no content
 * was found in $indexedContents an exception is thrown with the primary-key.
 * 
 * @param array $row row from input-detail.csv
 * @param array $indexContents result from getCsvContentIndexedByPrimaryKey
 * @return array joined content
 * @throws Exception if no content for $row[0] was found in $indexedContents
 */
function joinRowByPrimaryKey($row, $indexedContents)
{
    $primaryKey = $row[0];
    if (isset($indexedContents[$primaryKey])) {
        $contentToJoin = $indexedContents[$primaryKey]; unset($row[0
        ]); return array_merge($contentToJoin, $row);
    }
    throw new \Exception(sprintf(
        'Primary-key %s not found in indexed-contents', $row[0]));
}

/**
 * Now, here we go.
 */

// we create the indexed-content and initialize our output and error-handling
$indexedContents = getCsvContentIndexedByPrimaryKey('input-primary.csv');
$outputContent = [];
$errors = [];

// now we read the second csv-file
$handle = fopen('input-detail.csv', 'r');
while (false !== $row = fgetcsv($handle)) {
    try {
        $outputContent[] = joinRowByPrimaryKey($row, $indexedContents);
    } catch (\Exception $e) { // we catch the exception from joinRowByPrimaryKey here
        $errors[$row[0]] = $e->getMessage();
    }
}

// Finally, we create our result-file and write our output-content to it
// note the usage of fputcsv @see http://php.net/fputcsv
// there is no need to manually write commas, line-endings and the like
$handle = fopen('result.csv', 'w');
foreach ($outputContent as $row) {
    fputcsv($handle, $row);
}

// and print our errors
foreach ($errors as $error) {
    echo $error . PHP_EOL;
}

带有示例 csv 文件的代码也在 github 上:https://github.com/jbrinksmeier/so-28431197

享受

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 2019-06-27
    相关资源
    最近更新 更多