I am trying to read and write to the same csv file, to specifically delete a row in a csv file if a certain header contains a value. My csv file looks like this:
Item # | Price | Quantity | Name |
---|---|---|---|
1 | 2.99 | 1 | Muffin 1 |
2 | 3.99 | 2 | Muffin 2 |
3 | 4.99 | 3 | Cookie 1 |
4 | 5.99 | 4 | Cookie 2 |
I have the following code:
def delete_item(self, item_num):
self.result[:] = [d for d in self.result if d.get("Item #") != int(item_num)]
input = open('items2.csv', 'rb')
output = open('items2.csv', 'wb')
writer = csv.writer(output)
for row in csv.reader(input):
if row[0]!=item_num:
writer.writerow(row)
input.close()
output.close()
This method takes in a item_num that is entered by the user, and deletes it from the list of dictionaries I have. I am also trying to get this specific row deleted from my csv file that the data is stored in. For example, if the user inputs they would like to delete the row that has the Item # of 1, it would delete this row in the csv file.
I have the following method that I believe does so, but understand I cannot read and write to the same csv file at the same time, as it will simply clear it. I know this isnt extremely practical, as it can load up memory, but I need to adjust the same csv file, and know this can be done by reading, closing it, and then writing. How would I do this?
The same CSV file should look like this after it is done if item_num = 2
.
Item # | Price | Quantity | Name |
---|---|---|---|
1 | 2.99 | 1 | Muffin 1 |
3 | 4.99 | 3 | Cookie 1 |
4 | 5.99 | 4 | Cookie 2 |
CodePudding user response:
As you said, you can't (or really shouldn't try to) concurrently read and write the same file. There are several options.
- If you don't care about preserving the old file:
- read the whole file in to a dictionary.
- close the file that is read
- monkey with the dictionary as needed
- open and write the same file with the 'w' modifier on the write command to over-write the current contents
- If you want to save the orig file (usually a great idea):
- read the whole file into a dictionary
- close the file, perhaps rename it to
<filename>_orig
- monkey with the dictionary
- open a new file with the old name (or in a new folder of
mods
)
- If you are doing this a lot, it starts to smell like a database so:
- make the jump to sqlite, which is included in core python
- read/write concurrently to your heart's content.
TL;DR Summary: do the reading / writing operations sequentially
CodePudding user response:
You're not doing it concurrently like the other user suggests. You're working with it sequentially, row by row, byte by byte. It's completely safe. You may even use only a single descriptor doing it. That should do it
def delete_item(self, item_num):
self.result[:] = [d for d in self.result if d.get("Item #") != int(item_num)]
editing = open('items2.csv', 'r b')
pointer = 0
for row in csv.reader(editing):
if row[0] == item_num:
rest = editing.read()
editing.seek(pointer)
editing.write(rest)
editing.truncate()
editing.close()
break
pointer = editing.tell()
This code assumes there's only one row with the provided item #