【问题标题】:How to append a file and take out a specific line python 3如何附加文件并取出特定行python 3
【发布时间】:2016-04-28 08:56:15
【问题描述】:

我有一个格式如下的股票文件:

12345678,Fridge,1,50
23456789,Car,2,50
34567890,TV,20,50

这是代码:

def main():
products = {}
#This is the file directory being made.
f = open('stockfile.txt') 
#This is my file being opened.

for line in f:


    # Need to strip to eliminate end of line character
    line = line[:-1]
    #This gets rid of the character which shows and end of line '\n'
    row = line.split(',')
    #The row is split by the comma
    products[row[0]] = [row[1], row[2],row[3]]
    #The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.

print(products)
total = 0

print('Id       Description         Total')
while True:
    GTIN = input('Please input GTIN ')
    if(GTIN not in products):
        print('Sorry your code was invalid, try again:')
        break

    row = products[GTIN]
    print(GTIN)
    description = row[0]
    value = row[1]
    stock = row[2]
    print(stock)

    quantity = input('Please also input your quantity required: ')
    row[2]= int(stock) - int(quantity)
    products[row[2]] = row[2]
    product_total= (int(quantity)*int(value))
    New_Stock  = GTIN + ',' + description + ',' + value + ',' + str(products[row[2]])
    f = open('stockfile.txt','r')
    lines = f.readlines()
    f.close()
    f = open("stockfile.txt","a")
    for row in lines:
        if((row + '\n') != (New_Stock + '\n')):
            f.write(New_Stock)
            f.close()

    print('%20s%20s%20s' % (GTIN, description, product_total))

    total = total + product_total

print('Total of the order is £%s' % total)
print(products)
main()

但是,代码不会更新股票。它应该做的是摆脱之前给定产品的库存,然后根据用户刚刚购买的数量进行更新。

我还没有开始,但是一旦库存达到零,我需要我的代码告诉用户我们已经缺货并需要一些新库存。然后需要向用户发送一条消息,等待我们补货,然后再显示补货价格。

如果您有时间,请您也编写这段新代码,如果没有,您能否解释一下如何更新库存以及为什么我的代码不起作用,谢谢。

【问题讨论】:

    标签: python file python-3.x dictionary append


    【解决方案1】:

    当您seek 到给定行并调用write 时,为了完全覆盖该行,而不影响其他行或无意中创建新行,库存中的每行必须具有固定宽度。如何确保固定宽度?通过给记录中的每个字段一个固定的宽度。基本上,您选择每个字段可以包含的最大字符数;在这里,我假设所有字段为 8(尽管它们不能全部相同),因此您的库存将以这种方式存储:

    12344848,  Fridge,       2,      50
    13738389,      TV,       5,      70
    

    如果你继续这样做,每行都会有一个最大宽度,这将使你能够找到行的开头并完全覆盖它。试试这个代码:

    MAX_FIELD_LEN = 8
    
    def main():
        products = {}
        product_location  = {}
        location = 0
        # This is the file directory being made.
        with open('stockfile.txt', 'r+') as f:
            # This is my file being opened.
    
            for line in f:
                # keep track of each products location in file  to overwrite with New_Stock
                product_location[line.split(',')[0]] = location
                location += len(line)
                # Need to strip to eliminate end of line character
                line = line[:-1]
                # This gets rid of the character which shows and end of line '\n'
                row = line.split(',')
                # The row is split by the comma
                products[row[0]] = [row[1], row[2], row[3]]
                # The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.
    
            print(products)
            total = 0
    
            while True:
                GTIN = input('Please input GTIN: ')
                # To terminate user input, they just need to press ENTER
                if GTIN == "":
                    break
                if (GTIN not in products):
                    print('Sorry your code was invalid, try again:')
                    break
    
                row = products[GTIN]
                description, value, stock = row
                print('Stock data: ')
                print('GTIN \t\tDesc. \t\tStock \t\tValue')
                print(GTIN,'\t',description,'\t', stock, '\t', value)
    
                quantity = input('Please also input your quantity required: ')
                row[2] = str(int(stock) - int(quantity))
                product_total = int(quantity) * int(value)
                for i in range(len(row)):  
                    row[i]  = row[i].rjust(MAX_FIELD_LEN)
                New_Stock = GTIN.rjust(MAX_FIELD_LEN) + ',' + ','.join(row) + '\n'
                #print(New_Stock, len(New_Stock))
                f.seek(product_location[GTIN])
                f.write(New_Stock)
                print('You bought: {0} {1} \nCost: {2}'.format(GTIN, description, product_total))
    
                total = total + product_total
            f.close()
            print('Total of the order is £%s' % total)
    
    main()
    

    使用此程序时,请确保 TXT 文件中的每个字段都正好是 8 个字符宽(不包括逗号)。如果要增加字段宽度,请相应地更改 MAX_FIELD_LEN 变量。您的 TXT 文件应如下所示:

    【讨论】:

    • 我仍然遇到同样的问题,但不幸的是,即使在添加之后。
    • @HC123 你能发布你的代码吗?以及您收到此错误时的文本文件?
    • 抱歉,由于某种原因,我似乎无法...您能否尝试将您的代码合并到我的代码中并与文件一起发布,好吗?由于某种原因,我似乎无法发布。 @TisteAndii
    • 不幸的是我仍然遇到同样的问题: products[row[0]] = [row[1], row[2], row[3]] IndexError: list index out of range
    • @HC123 我用我给你看的示例在我的电脑上尝试了代码,它运行良好。它对你有用吗?编辑您的帖子以显示您正在使用的示例 TXT 文件。还要知道您的 TXT 文件中不应有多余的行;确保使用 BACKSPACE 以确保最后一行是包含库存的最后一行。
    【解决方案2】:

    在前几行中,您将整个数据文件加载到内存中:

    for line in f:
        products[row[0]] = [row[1], row[2],row[3]]
    

    那么只需更新内存中的数据,并让用户输入一个特殊命令:“save”将整个列表写入您的文件。

    您还可以捕获您的应用程序进程 KILL 信号,因此如果用户按 ctrl + c,您可以在退出前询问他是否要保存。

    并且可能每隔几秒钟将列表的临时副本保存到文件中。

    【讨论】:

    • 你会怎么做@Loïc,你能不能显示一个代码?
    【解决方案3】:

    如果您的客户打算多次运行此程序,我建议您为此使用shelve 模块。将整个文件读入内存并重新写入文本将随着库存的增长而变得低效。 Shelve 在您的 PC 上创建持久文件(确切地说是 3 个文件)以存储您的数据。最重要的是,shelve 将为您提供您想要的相同的dict 界面,因此您只需在文件上调用shelve.open(),您就可以开始使用 GTIN 作为键访问/更新您的股票。它非常简单,只需查看 python 手册即可。如果你真的想要一个文本文件,你可以让你的程序遍历包含你的股票的shelve文件(与字典相同)并将键(GTIN)及其值(你的股票数量)写入你的文本文件打开。通过这种方式,您可以轻松直观地访问您的记录,并在您的 TXT 文件中采用可读的格式。

    【讨论】:

      【解决方案4】:
      MAX_FIELD_LEN = 8
      
      def main():
          products = {}
          product_location  = {}
          location = 0
          # This is the file directory being made.
          with open('stockfile.txt', 'r+') as f:
          # This is my file being opened.
      
          for line in f:
              # keep track of each products location in file  to overwrite with New_Stock
              product_location[line.split(',')[0]] = location
              location += len(line)
              # Need to strip to eliminate end of line character
              line = line[:-1]
              # This gets rid of the character which shows and end of line '\n'
              row = line.split(',')
              # The row is split by the comma
              products[row[0]] = [row[1], row[2], row[3]]
              # The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.
      
          print(products)
          total = 0
      
          while True:
              GTIN = input('Please input GTIN: ')
              # To terminate user input, they just need to press ENTER
              if GTIN == "":
                  break
              if (GTIN not in products):
                  print('Sorry your code was invalid, try again:')
                  break
      
              row = products[GTIN]
              description, value, stock = row
              print('Stock data: ')
              print('GTIN \t\tDesc. \t\tStock \t\tValue')
              print(GTIN,'\t',description,'\t', stock, '\t', value)
      
              quantity = input('Please also input your quantity required: ')
              row[2] = str(int(stock) - int(quantity))
              product_total = int(quantity) * int(value)
              for i in range(len(row)):  
                  row[i]  = row[i].rjust(MAX_FIELD_LEN)
              New_Stock = GTIN.rjust(MAX_FIELD_LEN) + ',' + ','.join(row) + '\n'
              #print(New_Stock, len(New_Stock))
              f.seek(product_location[GTIN])
              f.write(New_Stock)
              print('You bought: {0} {1} \nCost: {2}'.format(GTIN, description, product_total))
      
              total = total + product_total
          f.close()
          print('Total of the order is £%s' % total)
      
      main()
      

      这是文本文件: 12345678, Fridge, 1, 50 23456789, Car, 2, 50 34567890, TV, 20, 50

      我在 Mac 桌面上执行此操作或它是 python 3.4.3 是否有区别?

      【讨论】:

      • @TisteAndii 这是我运行时的代码,也是您发布的代码。
      • 我认为使用 Mac 很重要,因为 OSX 之前的 Mac 使用不同的行尾。尝试用\r 替换New_Stock 中的\n(在for 循环之后)(您也可以尝试\r\n)。还要更改行:location += len(line) 到 location = f.tell() 和 line = line[:-1] 到 line = line.rstrip()
      【解决方案5】:

      上面使用搁置的建议听起来是个好主意,但如果您想保持文件原样,但只使用(大部分)代码更新更改的记录(而不是每次都重写整个文件),这似乎有效。

      def main():
          products = {}
          product_location  = {}
          location = 0
          # This is the file directory being made.
          with open('stockfile.txt', 'r+') as f:
              # This is my file being opened.
      
              for line in f:
                  # keep track of each products location in file  to overwrite with New_Stock
                  product_location[line.split(',')[0]] = location
                  location += len(line)
                  # Need to strip to eliminate end of line character
                  line = line[:-1]
                  # The row is split by the comma
                  row = line.split(',')
                  products[row[0]] = [row[1], row[2], row[3]]
                  """
                  The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and
                  price so GTIN 12345678 is going to correspond to Fridge and 1.
                  """
      
              print(sorted(products.items()))
              total = 0
      
              while True:
                  GTIN = input('\nPlease input GTIN or press [Enter] to quit:\n')
                  # To terminate user input, they just need to press ENTER
                  if GTIN == "":
                      break
                  if (GTIN not in products):
                      # Let the user continue with order after mistake in GTIN input
                      print('Sorry your code was invalid, try again:')
                      continue
      
                  row = products[GTIN]
                  print('GTIN:', GTIN)
                  description = row[0]
                  value = row[1]
                  stock = row[2]
                  stock_length = len(row[2])
                  backorder = 0
                  print('In Stock:', stock)
      
                  quantity = input('Please also input your quantity required:\n')
                  if int(quantity) > int(stock):
                      row[2] = 0
                      backorder = int(quantity) - int(stock)
                      # TO DO
                      Backordered_Stock = GTIN + ',' + description + ',' + value + ',' + str(backorder) + '\n'
                  else:
                      row[2] = int(stock) - int(quantity)
                  products[row[2]] = row[2]
                  product_total = (int(quantity) * int(value))
                  New_Stock = GTIN + ',' + description + ',' + value + ',' + str(products[row[2]]).rjust(stock_length) + '\n'
                  f.seek(product_location[GTIN])
                  f.write(New_Stock)
                  print('Ordered - {0:>6} GTIN: {1:>10}  Desc: {2:<20}  at £{3:>6}  Total value: £{4:>6}  On backorder: {5:>4}'.
                      format(int(quantity), GTIN, description, int(value), product_total, backorder))
      
                  total = total + product_total
      
              print('Total of the order is £%s' % total)
      
      main()
      

      【讨论】:

      • 如果您的 NewStock 比当前行长,您最终可能会覆盖下一行的一部分,或者如果 NewStock 太短,您可能会在同一行中获得额外的字符。这仅在每行具有固定长度时才有效。没有任何方法可以选择性地更新文件,除非为记录中的每个字段提供固定宽度,并在必要时添加填充。
      • 代码可以工作,但是由于某种原因它停止工作......现在它出现了这个:products[row[0]] = [row[1], row[2], row[3 ]] IndexError: 列表索引超出范围
      • 由于某种原因代码停止工作? @TisteAndii
      • 这样做是因为您覆盖了其他行的部分内容,从而破坏了代码的一致性。如果你想让这个工作,我会发布一个答案来帮助
      • 请您这样做,这将非常有帮助! @TisteAndii
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 2023-01-30
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 2015-02-18
      相关资源
      最近更新 更多