简体   繁体   中英

Removing last row from appending CSV file

I would like to remove the last row appended to a CSV file (sort of like 'undo' last appended row). So far I have an interface that takes a user-generated raw_input and performs a command. For instance, 'a' adds the row to the CSV file, 'r' rejects the row from the CSV file. I would like 'u' to remove the last row added to the CSV file. My code looks like this

for i in range(0,len(out['bestObjID']),1):
    j = raw_input('\n Add (a) or Reject (r)?: ')
    if j=='ADD' or j=='add' or j=='a' or j=='A':
        c = csv.writer(open('NLS1_candidates.csv','a+'))
        c.writerow(out[i])
        print(' Writing object to candidate list...')
        i += 1
    elif j=='REJECT' or j=='reject' or j=='r' or j=='R':
        print(' Object rejected...')
        i += 1
    elif j=='UNDO' or j=='undo' or j=='u' or j=='U':
        i -= 1
    elif j=='?' or j=='h' or j=='help' or j=='HELP' or j=='H':
        print('    \n Press (a) to add object to candidate list')
        print('     Press (r) to add to reject object')
        print('     Press (?) or (h) for help')
        print('     Press (q) to Quit')
    elif j=='q' or j=='Q' or j=='QUIT' or j=='quit':
        print('\n Quitting...')
        break
    else:
        print('    \n Press (a) to add object to candidate list')
        print('     Press (r) to add to reject object')
        print('     Press (?) or (h) for help')
        print('     Press (q) to Quit')

How would I go about adding 'undo' functionality to my CSV file?

Edit: I've failed to mention that when I add a row to the CSV file, out[i] is a row read from another CSV file. If that helps at all.

If your file is not large, you can store them in a list by readlines() and remove the last row, and then write to the file with the same filename.

cat sample.csv                                                                                                                                                                    
line1
line2
line3
cat test.py                                                                                                                                                                       
inputs = open("sample.csv")
all_lines = inputs.readlines()
all_lines.pop(len(all_lines)-1)  # removes last line
inputs.close()  # closes file

# truncate file and write all lines except the last line
with open("sample.csv", "w") as out:
    for line in all_lines:
        out.write(line.strip() + "\n")

python test.py                                                                                                                                                                    
cat sample.csv                                                                                                                                                                    
line1
line2

A (dirty) solution can be to write each line by specifing the EOF character ( \\n probably) at the beginning, and, when the last line should be deleted, to write the \\r character .

But this don't handle multiple line deletion.

In case of a very large file, a solution is to define a NB_UNDO_LIMIT integer, which is equal to the number of lines saved in memory before writing, allowing the user to undo at most NB_UNDO_LIMIT times the addition.

from collections import deque

NB_UNDO_LIMIT = 10
output = open('output', 'w')

float_lines = deque(maxlen=NB_UNDO_LIMIT)
for line in open('filename'):
    # write the older line if necessary
    if len(float_lines) == NB_UNDO_LIMIT:
        output.write(float_lines.popLeft())
    float_lines.append(line)
    # do a job on the NB_UNDO_LIMIT last lines

The following is untested, but should give you a basic idea of how it could be done. One of the reasons I asked whether your current code works was because of the manual manipulation of the i variable inside the for i in range(...): loop. Seems like it could cause problems...

last_write = None

for i in range(0,len(out['bestObjID']),1):
    j = raw_input('\n Add (a) or Reject (r)?: ')
    if j=='ADD' or j=='add' or j=='a' or j=='A':
        with open('NLS1_candidates.csv', 'ab+') as f:
            f.seek(0, os.SEEK_END)
            last_write = f.tell()  # remember where added row starts
            c = csv.writer(f)
            print(' Writing object to candidate list...')
            c.writerow(out[i])
    elif j=='REJECT' or j=='reject' or j=='r' or j=='R':
        print(' Object rejected...')
        i += 1
    elif j=='UNDO' or j=='undo' or j=='u' or j=='U':
        if last_write is None:
            print(' Nothing to undo!')
        else:
            with open('NLS1_candidates.csv', 'ab+') as f:
                f.seek(last_write)  # go back to where last row started
                print(' Removing last row added.')
                f.truncate()  # reset file size back to that point
                last_write = None
                i -= 1
    elif j=='?' or j=='h' or j=='help' or j=='HELP' or j=='H':
        print('    \n Press (a) to add object to candidate list')
        print('     Press (r) to add to reject object')
        print('     Press (?) or (h) for help')
        print('     Press (q) to Quit')
    elif j=='q' or j=='Q' or j=='QUIT' or j=='quit':
        print('\n Quitting...')
        break
    else:
        print('    \n Press (a) to add object to candidate list')
        print('     Press (r) to add to reject object')
        print('     Press (?) or (h) for help')
        print('     Press (q) to Quit')

*This will work only when you do not have successive UNDOs.

If you make some changes to file.csv, then the previous copy of that would be stored in file.csv~ Just do a file replace to get back the previous content.

Thanks to wfgeo : another and I guess a simple solition is to use os library, find the last row and truncate it:

import csv
import os

with open(fileName, 'w', newline='') as f:
  writer = csv.writer(f, delimiter=';', dialect='excel')
  
  for row in rows:
    row = rows[0].values()
    writer.writerow(row)

  f.seek(0, os.SEEK_END)
  f.seek(f.tell()-2, os.SEEK_SET)
  f.truncate()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM