George Thompson
George Thompson

Reputation: 7037

PHP How can I iterate over a directory and merge all files that end with same string in a single file of that name

Description:

I have a directory that contains a large number of files named as follows:

2013_11_weekly.csv 
2013_10_weekly.csv 
2013_08_weekly.csv 
2013_09_weekly.csv 
2013_11_any_string.csv 
2013_10_any_string.csv

Problem:

How can I iterate over the directory and merge all the files that end with the same string into single files?

The end result would be a directory containing the following files.

weekly.csv 
any_string.csv 
...

Research:

I have the following code snippet that merges all all files.

<?php

$files = glob("*.csv");
$out = fopen("merged_files.csv", "w");
foreach($files as $file){
    fwrite($out, file_get_contents($file));
}
fclose($out);
echo "files merged";

?>

How can I amend my script to achieve the above?

I know I may have to use an array function, a str_ function and possibly a regular expression function.

Upvotes: 2

Views: 2110

Answers (5)

Kleskowy
Kleskowy

Reputation: 2668

Try this - it assumes the rules to grouping files (2013_[two-digits]_[grouping_string]). Nice trick is using ?P sign in regexp, which will put the aggregation string into $maches array under 'string_aggr' key:

$filenameRegexp = '/2013_[0-9]{2}_(?P<string_aggr>.+)\.csv/';
foreach (glob('*.csv') as $filename) {
   if (preg_match($filenameRegexp, $filename, $matches)) {
      $aggrFilename = $matches['string_aggr'] '.csv';
      file_put_contents($aggrFilename, file_get_contents(filename), FILE_APPEND);
   }
}

What it does is basically:

  1. Find all files matching the pattern '*.csv';
  2. Take each file and check if it matches pattern "2013_[two-digits]_[anything].csv"
  3. If it does match the pattern - get it's contents, and append it to the end of the file named "anything.csv".

After running it you should get desired results - multiple files with aggregated contents, according to those "anything" parts, in your case: weekly, any_string etc.

Upvotes: 2

mondjunge
mondjunge

Reputation: 1239

Instead of fwrite, you should use file_put_content. This function is able to append data to a file.

Description

int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )

This function is identical to calling fopen(), fwrite() and fclose() successively to write data to a file.

If filename does not exist, the file is created. Otherwise, the existing file is overwritten, unless the FILE_APPEND flag is set.

resulting in code like (not tested, just for understanding):

<?php
$files = glob("*.csv");
foreach($files as $file){
    // get substring 6 chars before the last 4 chars (.csv)
    $type = substr($file, -4, -10)
    // switch based on the substring $type
    switch($type) {
        case "weekly":
            file_put_content("merged_files_weekly.csv", file_get_contents($file), FILE_APPEND);
        break;
        case "string" :
            file_put_content("merged_any_string.csv", file_get_contents($file), FILE_APPEND);
        break;
        default:
            // do nothing
        break;
    }

}
echo "files merged";

Upvotes: 0

OlivierH
OlivierH

Reputation: 3890

You can do an array, concatenate all values into array and then create those files

For example :

$files = glob("*.csv");
$files_content = array();

//parse all your files
foreach($files as $file){
    //get the suffix (ie '_weekly')
    $filename_end = substr(basename($file), 8);
    if(!isset($files_content[$file])) $files_content[$file] = "";
    //concatenate strings
    $files_content[$file] .= file_get_contents($file);
}

//and then create those files
foreach($fields_content as $filename => $content){
    $out = fopen($filename, "w");
    fwrite($out, $content);
    fclose($out);
}

Upvotes: 0

Glavić
Glavić

Reputation: 43552

This is very simple, you must just figure out, how to fetch common name from filenames.

In my example, I split filename on 8th position (2013_11_weekly.csv becomes weekly.csv ):

$files = glob("*.csv");
$out = array();
foreach($files as $file) {
    $name = substr(basename($file), 8);
    if (!isset($out[$name])) {
        $out[$name] = fopen($name, "w");
    }
    fwrite($out[$name], file_get_contents($file));
}
foreach ($out as $f) {
    fclose($f);
}

Upvotes: 1

Meghendra S Yadav
Meghendra S Yadav

Reputation: 134

It may be helpful for you. If you not getting your proper answer than let me know. merging multiple csv files using php

Upvotes: 0

Related Questions