分割してCSVに書く、分割されたCSVを読む
1年前のプログラムの一部改良。
複数ファイルを連続して読むプログラム - Cucco’s Compute Hack
ディレクトリのパスと、ファイル名(拡張子ナシ、連番ナシ)を与えて、
決まった行数を書いたファイルを保存する、それらのファイルを開いて読む、というプログラム。
読む場合は以前から継続で、イテレータを利用できるようにした。
読むファイルをすべてリストで指定していたが、pathlibで一覧を取得している。
プログラム
import csv from pathlib import Path import os from faker import Faker import random class split_csv_writer: ''' 渡された値をファイルに書き落としていく max_linesを超えたら、別のファイルに変更する。 ''' def __init__(self, dirctory_path, filename_wo_extension, header_data=None, max_lines=100000): self.max_lines = max_lines if header_data == None: self.max_lines = max_lines-1 self.currnet_lines = self.max_lines+1 # 初回にOpenを実行してもらうため。 self.currnet_file_post_index = 0 self.filename = filename_wo_extension self.f = None self.dirctory_path = dirctory_path self.header_data = header_data self.delete_existing_files() def close(self): # デストラクタでも呼んでいる self.currnet_file_post_index = self.currnet_file_post_index+1 if self.f != None: self.f.flush() # 実際には、ファイルに書き込みしてくれないことがあったので追加。 self.f.close() self.f = None def delete_existing_files(self): p = Path(self.dirctory_path) r = self.filename+"*.csv" for existing_file_path in p.glob(r): print("削除します ", existing_file_path) os.remove(existing_file_path) def __del__(self): self.close() def open(self): if self.f == None: pass else: self.close() real_filename = self.dirctory_path + self.filename + \ "_{0:08d}.csv".format(self.currnet_file_post_index) os.makedirs(self.dirctory_path, exist_ok=True) self.f = open(real_filename, 'w', encoding='utf-8') self.csv_writer = csv.writer( self.f, delimiter=',', quotechar='"', lineterminator='\n') self.currnet_lines = 0 print("新規作成 ", real_filename) def writerow(self, input_data): ''' input_dataには、リストかタプルでデータを与える。 ''' if self.currnet_lines > self.max_lines: self.open() if self.header_data != None: self.writerow(self.header_data) self.csv_writer.writerow(input_data) self.currnet_lines = self.currnet_lines+1 class split_csv_reader: def __init__(self, dirctory_path, readfilename_wo_extention, skipHeader=False): self.filename = readfilename_wo_extention self.currentFileIndex = -1 self.fp = None self.csv_reader = None self.skipHeader = skipHeader self.dirctory_path = dirctory_path self.set_readFileNames() def set_readFileNames(self): self.readFileNames = [] p = Path(self.dirctory_path) r = self.filename+"*.csv" for existing_file_path in p.glob(r): self.readFileNames.append(existing_file_path) # ⃣print(self.readFileNames) def __iter__(self): # next()はselfが実装してるのでそのままselfを返す return self def __next__(self): if self.csv_reader is None: # 1個目のファイルを開く self.nextfile() try: value = next(self.csv_reader) return value except StopIteration: # 終端まで来たら、このStopIterationが投げられる。 try: self.nextfile() value = next(self.csv_reader) return value except StopIteration: # 次のファイルがなかったので、例外を投げてイテレータを終わる。 # ファイルがロックされている場合もここに来るので、問題になる可能性あり。 raise (StopIteration) except: # ここには来ない。 raise (StopIteration) def nextfile(self): self.currentFileIndex = self.currentFileIndex + 1 if self.fp is not None: self.fp.close() if self.currentFileIndex > len(self.readFileNames)-1: # 次のファイルはないので例外を投げる raise(StopIteration) else: self.fp = open( self.readFileNames[self.currentFileIndex], mode='r', newline='\n') self.csv_reader = csv.reader(self.fp, delimiter=',', quotechar='"') if self.skipHeader is True: next(self.csv_reader) # ⃣print(value) # 動作確認用プログラム if __name__ == "__main__": dirname = r"C:/lib_split_test/" # 最後はos.sepで終わるように指定する filename = r"lib_split_test" print("#書き込みのテスト") headerdata = ("#", "Name", "score") writer = split_csv_writer( dirname, filename, header_data=headerdata, max_lines=3) fake = Faker() for i in range(1, 10+1): # 最後の値は実行されないrange(1,10+1)で、1~10 data = [i, fake.name(), random.random()] writer.writerow(data) print(data) writer.close() print("#読み込みのテスト") reader = split_csv_reader(dirname, filename, skipHeader=True) for item in reader: print(item)
実行結果
(base) C:\dev\ > python C:\dev\lib_sprit_csv_reader_writer.py #書き込みのテスト 削除します C:\lib_split_test\lib_split_test_00000000.csv 削除します C:\lib_split_test\lib_split_test_00000001.csv 削除します C:\lib_split_test\lib_split_test_00000002.csv 削除します C:\lib_split_test\lib_split_test_00000003.csv 新規作成 C:/lib_split_test/lib_split_test_00000000.csv [1, 'Carol Martinez', 0.2993282973465532] [2, 'Monica Skinner', 0.47771227744058886] [3, 'Stephanie Zimmerman', 0.30639552562401595] 新規作成 C:/lib_split_test/lib_split_test_00000001.csv [4, 'Terry Williams', 0.2800113471343493] [5, 'Scott Grant', 0.8271274374443526] [6, 'Jose Daniels', 0.4170927481515181] 新規作成 C:/lib_split_test/lib_split_test_00000002.csv [7, 'Adam Austin', 0.2850528257749132] [8, 'Krista Williams', 0.9258438865231986] [9, 'Jared Adkins', 0.6205699038539508] 新規作成 C:/lib_split_test/lib_split_test_00000003.csv [10, 'Ryan Morales', 0.9635161039757013] #読み込みのテスト ['1', 'Carol Martinez', '0.2993282973465532'] ['2', 'Monica Skinner', '0.47771227744058886'] ['3', 'Stephanie Zimmerman', '0.30639552562401595'] ['4', 'Terry Williams', '0.2800113471343493'] ['5', 'Scott Grant', '0.8271274374443526'] ['6', 'Jose Daniels', '0.4170927481515181'] ['7', 'Adam Austin', '0.2850528257749132'] ['8', 'Krista Williams', '0.9258438865231986'] ['9', 'Jared Adkins', '0.6205699038539508'] ['10', 'Ryan Morales', '0.9635161039757013']