2021年7月9日 星期五

讀取檔案與寫入檔案的方式

學習目標:
  • 了解 Python 如何讀寫檔案!
  • 了解 Python 如何使用 CSV 檔案!

讀寫一般檔案
  1. 從檔案中,讀取資料:
    • stores.txt 檔案內容如下:
      阿好蚵仔煎
      管長大腸包小腸
      盧小小滷味店
      阿Q日式拉麵店
      小寬肉粽老店
      阿強冷凍水餃店
      
    • readStores.py 檔案內容如下:
      # 讀取檔案內容
      files = open("stores.txt","r", encoding='utf-8')
      
      # 建立一個空的串列,準備接收檔案的每一行文字
      stores = []
      
      # 利用迴圈將每一行文字,放入串列
      for i in files:
      	stores.append(i)
         
      print(stores)
      print("第五家店:",stores[4])
      
      # 關閉檔案
      files.close()
      
    • 更快的讀取方式
      # 讀取檔案內容
      files = open("stores.txt","r", encoding='utf-8')
      
      # 建立一個空的串列,準備接收檔案的每一行文字
      stores = []
      
      # 利用 readlines 將每一行文字,放入串列
      stores = files.readlines()
      
      print(stores)
      
  2. 將資料寫回檔案,例:writeStores.py
    # 將檔案內容讀出至串列
    files = open("stores.txt","r", encoding='utf-8')
    stores = []
    for i in files:
        stores.append(i)
    files.close()
    
    # 最後一筆資料要處理換行的問題
    stores[-1] = str(stores[-1] + "\n")
    
    # 新增一家店名,店名後方,要加上"\n"
    newstore = "北極熊火鍋店\n"
    
    # 將新店家名稱加入 stores 串列
    stores.append(newstore)
    
    # 開啟檔案,設定成可寫入模式
    new_files = open("stores.txt","w", encoding='utf-8')
    
    # 將串列寫入檔案中
    new_files.writelines(stores)
    
    # 關閉檔案
    new_files.close()
    
  3. 如果只是附加,可以更快一點!
    # 新增一家店名,店名後方,要加上"\n"
    newstore = "\n北極熊火鍋店"
    
    # 開啟檔案,設定成附加寫入模式
    new_files = open("stores.txt","a", encoding='utf-8')
    
    # 將串列寫入檔案中
    new_files.writelines(newstore)
    
    # 關閉檔案
    new_files.close()
    
讀寫 CSV 檔案
  1. 從 CSV 檔案中,讀取資料:
    • CSV 檔案 food.csv 內容如下:
      菜單,價錢
      原汁牛肉麵,150
      牛肉湯麵,80
      餛飩麵,75
      泡麵,50
      
    • 讀取 CSV 檔案的作法,例:readFood.py
      # 引用 csv 類別
      import csv
      
      # 開啟 CSV 檔案
      with open('food.csv', newline='') as csvfile:
      
          # 讀取 CSV 檔案內容,可指定分隔符號
          rows = csv.reader(csvfile, delimiter=',')
      
          # 以迴圈輸出每一列
          for row in rows:
              print(row)
      
    • 第一行是欄位名稱
      # 引用 csv 類別
      import csv
      
      # 開啟 CSV 檔案
      with open('food.csv', newline='') as csvfile:
      
          # 讀取 CSV 檔內容,將每一列轉成一個 dictionary
          rows = csv.DictReader(csvfile)
      
          # 以迴圈輸出指定欄位
          for row in rows:
              print(row['菜單'], row['價錢'])
      
  2. 將資料,寫入 CSV 檔案內
    • 第一行是欄位名稱,CSV檔案一開始不用建立
          
      # 引用 csv 類別
      import csv
      
      # 開啟輸出的 CSV 檔案
      with open('food2.csv', 'w', newline='') as csvfile:
          # 建立 CSV 檔寫入器
          writer = csv.writer(csvfile, delimiter=',')
      
          # 寫入一列資料
          writer.writerow(['茶飲', '價錢'])
      
          # 寫入另外幾列資料
          writer.writerow(['綠茶', 30])
          writer.writerow(['紅茶', 35])
      
    • 一口氣寫入的方法
      # 引用 csv 類別
      import csv
      
      # 二維表格
      table = [
          ['茶飲', '價錢'],
          ['綠茶', 30],
          ['紅茶', 35]
      ]
      
      with open('food2.csv', 'w', newline='') as csvfile:
          writer = csv.writer(csvfile)
      
          # 寫入二維表格
          writer.writerows(table)
      
    • 使用 Python 的 Dictionary 寫法
      # 引用 csv 類別
      import csv
      
      # 開啟輸出的 CSV 檔案
      with open('food2.csv', 'w', newline='') as csvfile:
        # 定義欄位
        fieldnames = ['茶飲', '價錢']
      
        # 將 dictionary 寫入 CSV 檔
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
      
        # 寫入第一列的欄位名稱
        writer.writeheader()
      
        # 寫入資料
        writer.writerow({'茶飲': '綠茶', '價錢': 30})
        writer.writerow({'茶飲': '紅茶', '價錢': 35})
      
修改遊戲主要流程
  1. 製作「機會」的 CSV 檔案,例如:chance.csv:
    機會訊息,金額
    中大樂透普獎2000元,2000
    賣出股票獲利1000元,1000
    繳納水電費支出500元,-500
    加油站加油支出800元,-800
    過年紅包收入1500元,1500
    
  2. 製作「機會」類別,抽取機會內容:
    import random
    import csv
    
    class Chance:
        
        __messages = []
        __money = []
    
        # 讀取 CSV 檔案
        def choice(self):
            with open('chance.csv', newline='', encoding='utf-8') as csvfile:
                rows = csv.DictReader(csvfile)
                for row in rows:
                    self.__messages.append(row['機會訊息'])
                    self.__money.append(row['金額'])
                
            # 隨機抽取一張
            nums = random.randint(0,len(self.__messages)-1)
            return (self.__messages[nums],self.__money[nums])
        
    
    if __name__ == "__main__":
        myChance = Chance()
        print(myChance.choice())
    
  3. 修改遊戲流程主程式 main.py :
    # 引用 random 類別中的 randrange() 函數
    from random import randrange
    
    # 引用 Player 物件
    import Player
    
    # 引用 Chance 物件
    import Chance
    
    # 常用函式、參數設定區域
    ## 遊戲方格總數
    areas = 24
    
    ## 處理玩家是否有經過「開始」
    def playerPo(steps):
        if (steps >= areas):
            return (steps % areas)
        else:
            return steps
    
    # 程式流程開始
    # 使用 if __name__
    if __name__ == "__main__":
    
        # 要求玩家要輸入遊戲人數
        players_num = eval(input("請輸入玩家人數:"))
    
        # 建立玩家物件
        players = []
    
        # 按照遊戲人數,使用 Player 類別
        # 逐次產生玩家名稱、玩家代號、玩家初始遊戲幣、玩家初始位置等物件內容
        for i in range(players_num):
            players.append(Player.Player())
            # 要求玩家輸入玩家名稱
            players[i].setName(input("請輸入玩家名稱:"))
            
        # 輸出資料
        for i in range(players_num):
            print(players[i].getName())
            print(players[i].getPo())
            print(players[i].getMoney())
    
        # 設定玩家順序值
        i = 0
    
        # 開始進行遊戲
        while True:    
        ##### a.)
        ##### b.) 擲骰子
            newstep = randrange(1,6)
            print(players[i].getName() + "擲骰子:" + str(newstep) + " 點")
            print(players[i].getName() + "前進中...")
            # 設定玩家新的位置
            players[i].setPo(newstep)
            
        ##### c.) 移動到骰子點數的框格
            newpo = players[i].getPo()
            
            # I. 可能經過起點
            if newpo >= areas:
                newpo = playerPo(newpo)
                if newpo == 0:
                    print("玩家回到「開始」位置:", newpo)
                elif newpo < (areas/4):
                    print("玩家越過「開始」位置:", newpo)
    
            print("玩家在新位置:",newpo)
            #  II. 可能落在邊角框格
            if (newpo  == 6):
                print("玩家休息一天")
            if (newpo  == 18):
                print("玩家再玩一次")
    
            #  III. 可能是在機會與命運框格
            ## 機會的地圖編號是 3,15 兩個號碼
            if ((newpo == 3) or (newpo == 15)):
                myChance = Chance.Chance()
                chances = myChance.choice()    
                print("玩家中機會:",chances[0])
    
            #  IV. 可能是在地產框格
               
        ##### e.)
            # 輪至下一位玩家
            i = i + 1
            if (i >= players_num):
                i = i - players_num
            
        ##### f.) 結束遊戲條件
            ends = input("是否結束遊戲?Y:是 N:繼續")
            if ((ends == "Y") or (ends == "y")):
                break