I've an existing csv file with following values
column1 column2
Fr-fc Fr-sc
Sr-fc Sr-sc
I want to add 2 new columns in it and achieve the following format
column1 column2 column3 column4
Fr-fc Fr-sc 1 2
Sr-fc Sr-sc 1 2
If I use following code it inserts same column header value in column data for the newly created columns
$a = file('amit.csv');// get array of lines
$new = '';
foreach($a as $line){
$line = trim($line);// remove end of line
$line .=";column3";// append new column
$line .=";column4";// append new column
$new .= $line.PHP_EOL;//append end of line
}
file_put_contents('amit2.csv', $new);// overwrite the same file with new data
How I can achieve the above?
Instead of reinventing the wheel, you can use php's inbuilt csv functions fgetcsv and fputcsv respectively to ease your work. First read in each row with fgetcsv and store the data in a multidimensional array:
$delimiter = "\t"; //your column separator
$csv_data = array();
$row = 1;
if (($handle = fopen('test.csv', 'r')) !== FALSE) {
while (($data = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
$csv_data[] = $data;
$row++;
}
fclose($handle);
}
Next edit the rows to add the extra columns using array_merge:
$extra_columns = array('column3' => 1, 'column4' => 2);
foreach ($csv_data as $i => $data) {
if ($i == 0) {
$csv_data[$i] = array_merge($data, array_keys($extra_columns));
} else {
$csv_data[$i] = $data = array_merge($data, $extra_columns);
}
}
Finally use fputcsv to enter each row into the csv.
if (($handle = fopen('test.csv', 'w')) !== FALSE) {
foreach ($csv_data as $data) {
fputcsv($handle, $data, $delimiter);
}
fclose($handle);
}
You can combine these steps to make your code more efficient by reducing the number of loops.
This approach is less code
<?php
$inFile = fopen('test.csv','r');
$outFile = fopen('output.csv','w');
$line = fgetcsv($inFile);
while ($line !== false) {
$line[] = 'third column';
$line[] = 'fourth column';
fputcsv($outFile, $line);
$line = fgetcsv($inFile);
}
fclose($inFile);
fclose($outFile);
Related
I am trying to convert a tab delimited file to csv. The problem is its a huge file. 100000 plus records. And i want only specific columns from that file. The file is not generated by me but by amazon so i cant really control the format.
The code i made works fine. But i need to ignore/remove some columns or rather i want only few columns from that. How do i do that without effecting the performance of conversion from txt to csv.
$file = fopen($file_name.'.txt','w+');
fwrite($file,$report);
fclose($file);
$handle = fopen($file_name.".txt", "r");
$lines = [];
$row_count=0;
$array_count = 0;
$uid = array($user_id);
if (($handle = fopen($file_name.".txt", "r")) !== FALSE)
{
while (($data = fgetcsv($handle, 100000, "\t")) !== FALSE)
{
if($row_count>0)
{
$lines[] = str_replace(",","<c>",$data);
array_push($lines[$array_count],$user_id);
$array_count++;
}
$row_count++;
}
fclose($handle);
}
$fp = fopen($file_name.'.csv', 'w');
foreach ($lines as $line)
{
fputcsv($fp, $line);
}
fclose($fp);
I am using unset to remove any column. But is there a better way ? for multiple columns.
I would do that by checking keys. For example:
// columns keys you don't wanna skip
$keys = array(0, 1, 3, 4, 7, 9);
$lines = file($file_name);
$result_lines = array();
foreach ($lines as $line) {
$tmp = array();
$tabs = explode("\t", $line);
foreach($tabs as $key => $value){
if(in_array($key, $keys)){
$tmp[] = $value;
}
}
$result_lines[] = implode(",", $tmp);
}
$finalString = implode("\n", $result_lines);
// Then write string to file
Hope it helps.
Cheers,
SiniĊĦa
In its simplest form i.e. without worrying about removing columns from the output this will do a simple read line and write line, therefore no need to maintain any memory hungry arrays.
$file_name = 'tst';
if ( ($f_in = fopen($file_name.".txt", "r")) === FALSE) {
echo 'Cannot find inpout file';
exit;
}
if ( ($f_out = fopen($file_name.'.csv', 'w')) === FALSE ) {
echo 'Cannot open output file';
exit;
}
while ($data = fgetcsv($f_in, 8000, "\t")) {
fputcsv($f_out, $data, ',', '"');
}
fclose($f_in);
fclose($f_out);
This is one way of removing the unwanted columns
$file_name = 'tst';
if ( ($f_in = fopen("tst.txt", "r")) === FALSE) {
echo 'Cannot find inpout file';
exit;
}
if ( ($f_out = fopen($file_name.'.csv', 'w')) === FALSE ) {
echo 'Cannot open output file';
exit;
}
$unwanted = [26,27]; //index of unwanted columns
while ($data = fgetcsv($f_in, 8000, "\t")) {
// remove unwanted columns
foreach($unwanted as $i) {
unset($data[$i]);
}
fputcsv($f_out, $data, ',', '"');
}
fclose($f_in);
fclose($f_out);
I have an array of csv elements and I want to retrieve the key of the column 'Due Date' (the result is 10) and display the array at the column 10. However, it doesn't display the result but it will show the column 1 and I don't know why.
Code:
while (($line = fgetcsv($file)) !== FALSE) {
//$line is an array of the csv elements
$value = array_search('Due Date', $line);
print_r($line[$value]);
}
Just do it like this so you can easily get the column number 10:
$var = array();
while($row = fgetcsv($yourFile)) {
$var[] = $row;
}
//Get Column 10
$var[] = $row[9];
Edit:
<?php
$valueOfSearch = "YOUR VALUE OF SEARCH";
$linesOfCsv = file('YOUR PATH.csv');
$lineNumberOfCSV = false;
while (list($key, $line) = each($linesOfCsv) and !$lineNumberOfCSV) {
$lineNumberOfCSV = (strpos($line, $valueOfSearch) !== FALSE);
}
if($lineNumberOfCSV){
//Add YOUR CONDITION
}
?>
Open the fine and take csv values inside an array and close the file. After that try your logic.
So to get value you can use:
$file = 'file.csv';
$line = array();
$file = fopen($file,"r");
while(! feof($file))
{
$line = fgetcsv($file);
}
fclose($file);
$key = array_search('Due Date', $line);
print_r($line[$key]);
I'm not sure how to print an exact element (like column 5, row 3) of a csv file in PHP. I have a CSV file with 3 columns: ID, cost, location. I need to search for the ID, which I can do and I can even return what row number it is. But then how can I print off that row's column 3? The code below prints the line number where $interior can be found.
$lines = file('database.csv');
$line_number = false;
while (list($key, $line) = each($lines) and !$line_number) {
$line_number = (strpos($line, $interior) !== FALSE);
}
if($line_number){
$search = $interior;
$line_number = false;
if ($handle = fopen("database.csv", "r")) {
$count = 0;
while (($line = fgets($handle, 4096)) !== FALSE and !$line_number) {
$count++;
$line_number = (strpos($line, $search) !== FALSE) ? $count : $line_number;
}
fclose($handle);
}
echo $line_number;
If
$lines = file('database.csv');
Gave you the lines in an array then:
$line = explode(",", $lines[2]);
Will give you an array of each elemet of row 3 (note the two (+1) in the lines variable).
So...
Echo $line[4];
Will be the third row and fifth column of database.csv
Since this question lacks a complete (non-breaking) answer:
You can simply use str_getcsv on each line of your csv and store the results in an array:
$lines = file('database.csv');
$data = array();
foreach($lines as $line)
{
// if your CSV uses a different delimiter or you enclose your fields with a different character than " alter the following line according to the php docs of str_getcsv
$data[] = str_getcsv($line);
}
// get row 3, column 5:
echo $data[2][4];
You can find the position of all comma(as it is CSV file) then on the basis of strpos($line, $search) this function's return you can decide the column.But if any of your column will contain comma, this logic will fail.
For that case, search the positions of ", (assuming your column will quoted by double quote).
You can put it inside your while loop:
$searchStr = "CA" ;
$mystr = "5,50.00,CA";
$myArr = explode(",",$mystr);
foreach($myArr as $k=>$v)
{
if($v == $searchStr)
echo "Column :". $k;
}
I have a csv file with some records and each record has unique ID. I'm running a loop to find that unique ID and then append some more data to that record.
Is it possible to do this without a temporary file? Creating such file and moving all data in it takes more time...
My code is:
<?php
$temp = fopen('tempwin.csv','w+');
if (($handle = fopen("win.csv", "r+")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$num = count($data);
$row++;
for ($c=0; $c < $num; $c++) {
if($data[4] == trim($leadid)){
$data[5] = trim($_POST['year']);
$data[6] = trim($_POST['make']);
$data[7] = trim($_POST['model']);
$data[8] = trim($_POST['trade']);
}
}
fputcsv($temp, $data);
}
fclose($handle);
fclose($temp);
}
unlink('win.csv');
rename('tempwin.csv','win.csv');
You can use following, but you need to pass the row number i.e where you need to add row.
<?php
//A helping function to insert data at any position in array.
function array_insert($array, $pos, $val)
{
$array2 = array_splice($array, $pos);
$array[] = $val;
$array = array_merge($array, $array2);
return $array;
}
//What and where you want to insert
$DataToInsert = '11,Shamit,Male';
$PositionToInsert = 3;
//Full path & Name of the CSV File
$FileName = 'data.csv';
//Read the file and get is as a array of lines.
$arrLines = file($FileName);
//Insert data into this array.
$Result = array_insert($arrLines, $PositionToInsert, $DataToInsert);
//Convert result array to string.
$ResultStr = implode("\n", $Result);
//Write to the file.
file_put_contents($FileName, $ResultStr);
?>
Fetch the data out of the original file as an array or string, make your modifications and then simply overwrite the contents of the file with your modified data.
I would like to convert a CSV to Json, use the header row as a key, and each line as object. How do I go about doing this?
----------------------------------CSV---------------------------------
InvKey,DocNum,CardCode
11704,1611704,BENV1072
11703,1611703,BENV1073
---------------------------------PHP-----------------------------------
if (($handle = fopen('upload/BEN-new.csv'. '', "r")) !== FALSE) {
while (($row_array = fgetcsv($handle, 1024, ","))) {
while ($val != '') {
foreach ($row_array as $key => $val) {
$row_array[] = $val;
}
}
$complete[] = $row_array;
}
fclose($handle);
}
echo json_encode($complete);
Just read the first line separately and merge it into every row:
if (($handle = fopen('upload/BEN-new.csv', 'r')) === false) {
die('Error opening file');
}
$headers = fgetcsv($handle, 1024, ',');
$complete = array();
while ($row = fgetcsv($handle, 1024, ',')) {
$complete[] = array_combine($headers, $row);
}
fclose($handle);
echo json_encode($complete);
I find myself converting csv strings to arrays or objects every few months.
I created a class because I'm lazy and dont like copy/pasting code.
This class will convert a csv string to custom class objects:
Convert csv string to arrays or objects in PHP
$feed="https://gist.githubusercontent.com/devfaysal/9143ca22afcbf252d521f5bf2bdc6194/raw/ec46f6c2017325345e7df2483d8829231049bce8/data.csv";
//Read the csv and return as array
$data = array_map('str_getcsv', file($feed));
//Get the first raw as the key
$keys = array_shift($data);
//Add label to each value
$newArray = array_map(function($values) use ($keys){
return array_combine($keys, $values);
}, $data);
// Print it out as JSON
header('Content-Type: application/json');
echo json_encode($newArray);
Main gist:
https://gist.github.com/devfaysal/9143ca22afcbf252d521f5bf2bdc6194
For those who'd like things spelled out a little more + some room to further parse any row / column without additional loops:
function csv_to_json_byheader($filename){
$json = array();
if (($handle = fopen($filename, "r")) !== FALSE) {
$rownum = 0;
$header = array();
while (($row = fgetcsv($handle, 1024, ",")) !== FALSE) {
if ($rownum === 0) {
for($i=0; $i < count($row); $i++){
// maybe you want to strip special characters or merge duplicate columns here?
$header[$i] = trim($row[$i]);
}
} else {
if (count($row) === count($header)) {
$rowJson = array();
foreach($header as $i=>$head) {
// maybe handle special row/cell parsing here, per column header
$rowJson[$head] = $row[$i];
}
array_push($json, $rowJson);
}
}
$rownum++;
}
fclose($handle);
}
return $json;
}