如何使用php解析csv文件中的多行

时间:2015-02-10 12:03:43

标签: php parsing csv export-to-csv

我有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");

}

1 个答案:

答案 0 :(得分:1)

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

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

您的第一个while循环遍历您的details-file(hbarefined.csv),您希望根据每个文件中相同的第一个字段来连接内容。然后,启动一个while循环,读取hostrefined.csv的每一行。如果找到包含所需主键的行,则可以加入hbarefined和hostrefined这两行的内容,并将其写入test.csv。这里我们有你脚本的前两个故障。

  1. 即使您与主键不匹配,也会向test.csv写一个新行。结果看起来很难看。

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

  3. 您不知道的是,您的第二个while循环会在每次迭代时将hostrefined.csv的文件指针向前移动一行,但在到达文件末尾时不会重置它。因为您通过整个hostrefined.csv读取了hbarefined.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");
    

    另外,请尝试使用变量名清楚。在for-loop中连续2次使用$ 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

    享受