1

This is my database named myDB.txt:

28273139
iPhone
5.50
30
5
35
81413852
Book
1.50
43
10
55

The text file database follows the format

Product Code
Product Name
Price
Current Stock
Reorder Stock (the lowest the stock can go)
Target Stock

Now, the I want to update the iPhone data. This is the iPhone data.

28273139
iPhone
5.50
30
5
35

It uses the 8-digit product code to identify the product.

I have written the following code.

userCode = "28273139"
newstock = "29"

database = open('myDB.txt','r+')
while(str(userCode) not in next(database)):
    pass
else:
    for i in range(3):
        line = next(database)
        replace = line.replace(line,newstock)
        database.write(replace)

I want to change the 4th value of the list, the number 30 to the number 29, which I declared as the variable newstock. The program moves 3 lines down, since the format is the same for every product in the database and replaces the line with this new value.

The result I need from updating the iPhone data -

28273139
iPhone
5.50
29
5
35

However, this method doesn't work.
I receive an error every time.

AttributeError: 'str' object has no attribute 'readlines'

Can someone help fix my problem? Is the code I have written correct to produce the required result?

martineau
  • 119,623
  • 25
  • 170
  • 301
vik1245
  • 546
  • 2
  • 9
  • 26
  • You said that you get some error. Can you post it here? – MaLiN2223 Feb 09 '17 at 23:12
  • @MaLiN2223 posted it! `AttributeError: 'str' object has no attribute 'readlines'` – vik1245 Feb 09 '17 at 23:13
  • you are trying to move line 3 lines forward, but line isnt an iterator, its a string, so readlines doesnt work here – Nullman Feb 09 '17 at 23:15
  • readlines() reads all the lines in a file, so it is a method of the file, not the string. – David Hoksza Feb 09 '17 at 23:16
  • @Nullman oh! Can you respond with an answer please on the bottom just to expand on the point? – vik1245 Feb 09 '17 at 23:16
  • @DavidHoksza So what method should I use instead? – vik1245 Feb 09 '17 at 23:16
  • @BobSmith To skip three lines you can use ```for i in range(3): line = database.readline()``` – David Hoksza Feb 09 '17 at 23:21
  • @BobSmith Using newlines as the only field separator is brittle. Imagine what would happen if, somehow, an empty/wrong line got inserted somewhere in the file... CSV or JSON would be safer and easier to work with. Secondly, consider whether you want to read the entire file into memory by doing `database.readlines()` and work on the resulting `list` (easy but costly in terms of memory) or go for a less memory-intensive approach and read a few lines, store them in a buffer, do your edits, write the buffer to an output file, repeat. – jDo Feb 09 '17 at 23:22
  • @DavidHoksza I tried your method but it doesn't change the text file at all. Could you possibly post your method as an answer? – vik1245 Feb 09 '17 at 23:30
  • 3
    I hate to be "that guy", but have you considered not rolling-your-own database? I see a lot of upside, and very little downside, in using `sqlite3`. Seems simpler, less error-prone, and more flexible. – Emmet Feb 09 '17 at 23:40
  • @Emmet is right ofc, so switch if you have a choice. you changed my code some and made it replace the next 3 lines with your value, not just the last line (btw, i have no idea how to actaully WRITE to the file, im just bringing the cursor to the right spot) – Nullman Feb 09 '17 at 23:44

2 Answers2

2

This is a lot easier when you configure your text file to be key:value pairs (like the dict construct in python, or values in another DB like SQL). Then you can simply set a sentinel value when the value is met, then unset when you've replaced the correct line.

So, if changing the format of text to:

ProductCode <value>
ProductName <value>
Price <value>
CurrentStock <value>
ReorderStock <value>
Targetstock <value>

Then you can do something like this:

ProductCode = "28273139"
NewStock = "29"
SentinelValue = 0

with open('myDB.txt', 'r+') as database:
  for line in database:
  (key, val) = line.split()
  if key == "ProductCode":
    if val == ProductCode:
      SentinelValue = 1
  if key != "ProductCode":
    if key == "CurrentStock":
      if SentinelValue == 1:
        line = line.replace(val, NewStock)
    print line

It is a bit dirty and could surely be cleaned up, but it is much more verbose. Also, note that the space is important as it is used as the delimiter when splitting the lines.

You may also notice I didn't write to the file: At least for me in python 2.7, there seems to be an issue where I can't replace a line of text, only append with f.write(). This code works and replaces to stdout, the workaround for writing to a file is to simply write all lines to a new file:

ProductCode = "28273139"
NewStock = "29"
SentinelValue = 0
fout = open('newDB.txt', 'w')

with open('myDB.txt', 'r+') as database:
  for line in database:
  (key, val) = line.split()
  if key == "ProductCode":
    if val == ProductCode:
      SentinelValue = 1
  if key != "ProductCode":
    if key == "CurrentStock":
      if SentinelValue == 1:
        line = line.replace(val, NewStock)
    fout.write(line)
    print line

You could then write logic to replace the files as needed. However, I would very much suggest looking at how to write and read from an actual SQL database. I hope this helps! ^^

martineau
  • 119,623
  • 25
  • 170
  • 301
RedBarron
  • 99
  • 5
0

you should probably iterate over your file differently, something along the lines of:

database = open('myDB.txt','r+')
while(str(userCode) not in next(database)):
    pass
else:
    for i in range(3): line = next(database)

the above line is inspired by David Hoksza

at this point you should be at the desired line im 100% sure there is a better pythonic way of doing this, but i dont have much experience with file manipulation in python i think this should work in python 3

Nullman
  • 4,179
  • 2
  • 14
  • 30