1

I want to replace the header row of a cvs file text.csv.

header_list = ['column_1', 'column_2', 'column_3']

The header will look like this;

column_1, column_2, column_3

Here is my code;

import csv
with open('text.csv', 'w') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(header_list)

The header of the csv file was replaced correctly. However, the rest of the rows in the csv file were deleted. How do I replace only the header leaving the other rows intact?

I am using python v3.6

user3848207
  • 3,737
  • 17
  • 59
  • 104
  • 2
    Either this is not a [mcve] or you are destroying the entire existing `text.csv` because you are overwriting the file with new data, `"w"` does not append, it *overwrites*. – Jongware Jul 22 '18 at 09:48

2 Answers2

5

Here is a proper way to do it using csv module.
csv.DictReader reads the content of csv file into a list of dicts. It takes an optional fieldnames argument which if set applies a custom header and ignores an original header and treats it as a data row. So, all you need to do is read your csv file with csv.DictReader and write data with csv.DictWriter. You will have to drop the first row in the reader because it contains the old header and write the new header. It does make sense to write the new data to a separate file though.

import csv

header = ["column_1", "column_2", "column_3"]

with open('text.csv', 'r') as fp:
    reader = csv.DictReader(fp, fieldnames=header)

    # use newline='' to avoid adding new CR at end of line
    with open('output.csv', 'w', newline='') as fh: 
        writer = csv.DictWriter(fh, fieldnames=reader.fieldnames)
        writer.writeheader()
        header_mapping = next(reader)
        writer.writerows(reader)
user3848207
  • 3,737
  • 17
  • 59
  • 104
taras
  • 6,566
  • 10
  • 39
  • 50
  • You create a new csv. The OP wants the header to be at the beginning of the same .csv – Agile_Eagle Jul 22 '18 at 11:07
  • 1
    @Agile_Eagle, there are several ways to do it. Anyway, in my opinion, writing to a separate file is more flexible. One can always remove an old version when needed. – taras Jul 22 '18 at 11:15
  • Your answer is tested to work fine. However, there is a side effect. There is an extra carriage return at the end of each line. So, instead of just having CR, LF at end of each line, the file has CR, CR, LF at the end of each line. – user3848207 Jul 25 '18 at 06:52
  • 1
    @user3848207, it does looks weird. I assume you are using windows. [This answer](https://stackoverflow.com/a/3191811/3023116) addresses your issue. – taras Jul 25 '18 at 07:17
  • @taras, indeed I am using Windows. Indeed, you've got the complete right answer:). That answer addressed my issue. – user3848207 Jul 25 '18 at 07:21
4

Use this:

import csv
header_list = ['column_1', 'column_2', 'column_3']
mystring = ",".join(header_list)
def line_prepender(filename, line):
    with open(filename, 'r+') as csvfile:
        content = csvfile.read()
        csvfile.seek(0, 0)
        csvfile.write(line.rstrip('\r\n') + '\n' + content)

line_prepender("text.csv", mystring)
Agile_Eagle
  • 1,710
  • 3
  • 13
  • 32
  • thanks but the solution does not work. What happens is that the intended header gets written or appended to the bottom of the csv file. The original header remains intact. – user3848207 Jul 22 '18 at 08:54
  • Thanks a lot. I need to be away for a while. I will mark your answer as the correct one after I have tested. Upvoted. – user3848207 Jul 22 '18 at 09:05
  • Thanks! Tested to be working. Marked as correct answer :) – user3848207 Jul 22 '18 at 12:40
  • I did further testing and realize your answer is not working. After running the code, the new header was appended but the original header was not replaced. The csv file ended up having 2 headers. – user3848207 Jul 25 '18 at 06:49
  • Sorry if I was unclear to give you the impression that I want a csv file with 2 headers. csv file with 2 headers is abnormal. A csv file should only have 1 header. – user3848207 Jul 25 '18 at 13:26
  • 1
    Okay got it. No problem – Agile_Eagle Jul 25 '18 at 16:09