LambdaからS3のファイルを直接読み書き(Python)

AWS S3に保存してあるCSVファイルを、Pythonから読み書きします。

今までは、MariaDBに保存していたデータですが、

  • ちょっとしたデータしか扱わない
  • 週一程度の更新

なので、CSVファイルに置き換えることにしました。

RDSとか、結構高いですしね。。。

あと、Lambda関数からアクセスするので、CSVファイルの保存先はS3にしました。
Lambdaだと /tmp に一時的に保存することも可能ですが、ダウンロードせず読み書きします。

初期処理

対象ファイルの存在チェック
そして、内容をメモリ上に読み込むところまで、一気にやっています。

# -*- coding: utf-8 -*-

from datetime import datetime,timedelta
import boto3
import io
import csv

class csv_work:
  def __init__(self):
    self.s3Resource = boto3.resource('s3')
    self.s3Client   = boto3.client('s3')
    self.bucket     = 'bucket_name' # バケット名を指定 
    self.key        = 'data.csv'    # CSVファイル名
    self.obj        = self.s3Resource.Object(self.bucket,self.key)

    # ファイルの存在チェック
    if self.checkS3KeyExists(self.key) == False:
      
      # とりあえずファイルを作っちゃう
      # ファイルを読み込んだりするので、適当な内容でファイルを作っています。
      self.obj.put( Body="1234,2021-01-01" )

    # CSVファイル読み込み
    self.s3obj = self.s3Resource.Object(self.bucket,self.key).get()
    self.file_contents = io.TextIOWrapper(io.BytesIO(self.s3obj['Body'].read()))

  return

ファイルチェック

読み込もうとしているファイルが有るか?の存在チェックを行っています。

#ファイル存在チェック
def checkS3KeyExists(self,key):
  try:
    self.s3Client.head_object(Bucket=self.bucket,Key=key)
    return True
  except Exception as e:
    print(e.args)

  return False # ファイルが存在しない。。

データの読み込み

CSVファイルを読み込んで、配列にセットして返します。

def getData(self):

  data_list = []

  # ストリームの先頭からシーク
  self.file_contents.seek(0)

  for rec in csv.reader(self.file_contents):
    data_list.append(rec)

  return data_list

データの削除

新しく、空のTextIOWrapperを作って、そこに残したいデータのみ入れていきます。

def delete_data(self):

  newCsv = io.TextIOWrapper(io.BytesIO())

  # ストリームの先頭からシーク
  self.file_contents.seek(0)

  writer = csv.writer(newCsv)

  for rec in csv.reader(self.file_contents):

    # 文字列 → 日付型
    dtCsv = datetime.strptime(str(rec[1]),'%Y-%m-%d')

    # 登録内容と3週間前を比較
    if dtCsv > datetime.now()+timedelta(weeks=-3): 
      writer.writerow([rec[0],datetime.now().strftime('%Y-%m-%d')])

  self.file_contents = newCsv
  return

登録

こちらは普通に追加しています。書き込みは別で行います。

def add_data(self,in_data):

  writer = csv.writer(self.file_contents)
  writer.writerow([in_data,datetime.now().strftime('%Y-%m-%d')])

S3にCSVファイルを書き込み

file_contentsの内容をS3上に直接書き込みます。

def commit(self):

  # ストリームの先頭からシーク
  self.file_contents.seek(0)

  self.s3Client.put_object(
    Body = self.file_contents.read(),
    Bucket = self.bucket,
    Key = self.key)