質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

5回答

1788閲覧

(Python)複数のtextファイル読込

club33gold

総合スコア20

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/07/10 16:56

編集2020/07/10 17:22

前提・実現したいこと

初歩的な質問で大変恐縮なのですが、ご教示をお願い致します。

①Pythonで同フォルダ内にある複数のtextファイルを読込み
②一つのtextファイルに結合
③②について、textファイルとして出力をしたいです。

フォルダ名称:Pass
ファイル名:aaa_200701.txt、aaa_200702.txt … aaa_200712.txt

ただしそれぞれに同一のヘッダーがあります。
単純に結合する事は出来たのですが、2ファイル目以降を読み込む際、ヘッダーは読まないようにしたいです。

・aaa_200701.txtのデータ型
日付 商品 担当者 点数 金額
200701 a1 b1 c1 10 10000

・aaa_200702.txtのデータ型
日付 商品 担当者 点数 金額
200702 a1 b1 c1 8 8000


・【ALL】aaa.txt(※最終的に作りたいデータ)
日付 商品 担当者 点数 金額
200701 a1 b1 c1 10 10000
200702 a1 b1 c1 8 8000


この場合、どのようなコードを使用すれば良いでしょうか?

試したこと

■使用したコード

①②について

import glob, codecs

for file in glob.glob("Pass/aaa*.txt"):
file_data = open(file, "r",encoding="utf-8")
print(file_data.read())

file_data.close

→ただし2ファイル目以降のヘッダーも読んでしまうのでNG

③について

file=codecs.open(Pass/【ALL】aaa.txt', 'w'))

解決に向けた仮説

(A案)
・aaa_200701.txtは全て読む
・aaa_200702.txt~2行目以降を読む
・上記を【ALL】aaa.txt'として結合?

(B案)
・aaa_200701.txtの1行目のみ読む
・aaa_200701.txt~2行目以降を読む
・上記を【ALL】aaa.txt'として結合?

(C案)
・aaa_200701.txt~をaaa_200701.CSVに変換して読込?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_shinoda

2020/07/10 17:18

「何を質問したいのか」を質問欄に追記おねがいします
guest

回答5

0

ベストアンサー

B案のほうが良いと思います。

  • 余計な分岐が無いので処理が簡潔
  • ヘッダー行だけに何らかの操作を加えるような拡張に対して柔軟

例えば、こんなふうに。

Python

1with open('out.txt', mode='w') as fout: 2 files = glob.glob('aaa*.txt') 3 assert files 4 5 # ヘッダーの出力 6 with open(files[0]) as fin: 7 header = next(fin) 8 fout.write(header) 9 10 # データ行の出力 11 for file in files: 12 with open(file) as fin: 13 next(fin) # ヘッダーのスキップ 14 fout.writelines(fin)

ヘッダーだけheader.txtから読んでくるとか、
ハードコーディングするとか、そのような変更をしたい場面も多々あるでしょう。

そのようなときもヘッダー行の書き込み処理だけをいじれば良いので簡単です。


本筋から逸れますが、
txtファイルではなくcsvファイルとして扱ったほうが後々扱いやすいかもしれません。

...よく見たら、C案がこれに相当するのですね。
ぶっちゃけ拡張子は半分ただの飾りなので、.txtのままCSV扱いもできます。
試したいことがあるなら気軽にトライできますよ。

もうちょっと複雑な処理が必要になるようであれば、テキストのまま扱うと面倒になってきます。

追記:私の頭の中にあるコード

Python

1with open('out.txt', mode='w') as fout: 2 files = glob.glob('aaa*.txt') 3 assert files 4 5 # ヘッダーの出力 6 header = ['日付', '商品CD', '担当CD', '点数', '金額'] 7 hdr2 = ','.join(header) 8 fout.write(hdr2) 9 10 # データ行の出力 11 for file in files: 12 with open(file) as fin: 13 next(fin) # ヘッダーのスキップ 14 fout.writelines(fin)

投稿2020/07/11 02:19

編集2020/07/18 23:56
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

club33gold

2020/07/11 15:19

ありがとうございます。 試しに入力してみましたが、下記のメッセージが出ました。 ------------------------------------------------------------------------ header = next(fin) UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 52: illegal multibyte sequence ------------------------------------------------------------------------ header = next(fin,encoding='utf-8')も試してみましたが、下記の通りです。 ------------------------------------------------------------------------ header = next(fin, encoding='utf-8') TypeError: next() takes no keyword arguments ------------------------------------------------------------------------ こちらの原因は分かりますでしょうか?
club33gold

2020/07/11 16:03 編集

以下で解決しました。 出力された内容も想定と相違ございません。 ------------------------------------------------------------------------ # ヘッダーの出力 with open(files[0], encoding='utf-8') as fin: header = next(fin) fout.write(header) # データ行の出力 for file in files: with open(file, encoding='utf-8') as fin: next(fin) # ヘッダーのスキップ fout.writelines(fin)
club33gold

2020/07/11 16:40

C案:txtファイルではなくcsvファイルとして扱う方が簡易的についても承知致しました。 (※csvの場合は調べると出て来ることが多いです。)
club33gold

2020/07/11 16:44

追加で1点質問です。 今回は最初に読み込んだ対象データの1行目をOut.txtに書き込むフローとして、認識しました。 例えばこちらで作ったヘッダー['日付','商品CD','担当CD','点数','金額']を使う場合、 with open(files[0]) as fin について ①以下に変更 →with open(['日付','商品CD','担当CD','点数','金額']) as fin: ②以下に変更 →header = ['日付','商品CD','担当CD','点数','金額']  with open(header) as fin:に変更 どちらにせよ、TypeError: expected str, bytes or os.PathLike object, not listとなってしまいますので、書式の部分で誤りがあればご教示頂けますと幸いです。
LouiS0616

2020/07/12 04:13

openはファイルを開くために使っているので、ヘッダーの読み込みが不要である場合は必要ありません。 単に with open(files[0]) as fin: から始まる三行を header = ['日付','商品CD','担当CD','点数','金額'] に置き換えれば良いです。
club33gold

2020/07/13 02:04

ありがとうございます! 確認をしたところ、確かにエラーメッセージは消えました。 ただし出力データにもヘッダーが入らず、元データの2行目以降のみ書込がされていました。 大変お手数ですが、こちらの原因をご教示頂けますでしょうか?
LouiS0616

2020/07/13 08:21

失礼、fout.writeの行は消す必要無かったですね。 そのままだとリスト形式で出力されてしまうので、うまく整形してやる必要があります。
club33gold

2020/07/14 08:04

下記に変更致しました。 ---------------------------------------------------------------- header = ['日付','商品CD','担当CD','点数','金額'] hdr2 = str(header)  #文字列にしてから扱う fout.write(hdr2) ---------------------------------------------------------------- こちらで書き込み自体は出来ました。 ただしカンマ区切りがされず[]内が一つの文字情報として貼り付いてしまいました。 またヘッダーとしては書き込まれていませんでした。 A1セル:今回のオリジナル文字列 A2セル:データ行の出力。ただしaaa_200701.txtの1行目にある日付が欠損 B1セル以降:データ行の出力。ただしaaa_200701.txtの2行目以降+aaa_200702.txtの1行目以降 上記のように出力されるのですが、B案のように1行目を読む形と同じ表記にしたいです。 おそらく①カンマ区切りの反映+②改行(/n)で解決すると思うのですが、どのように改修すれば良いでしょうか?
LouiS0616

2020/07/14 10:42

joinについて調べてみて下さい。
club33gold

2020/07/15 09:05

すいません… 改行の問題はクリアしましたが、分割の部分が出来ませんでした。 ----------------------------------------------------------------------------- header = ['日付','商品CD','担当CD','点数','金額'] hdr2 = " ".join(header) #文字列にしてから扱う、joinで文字列に出来る fout.write(hdr2) fout.write("\n") ----------------------------------------------------------------------------- ①カンマ区切りを反映し、A1・B1・C1…にヘッダー情報として書き込みたいです。 大変恐縮ですが、こちらをご教示頂けますでしょうか?
LouiS0616

2020/07/15 10:41

" ".join(header) の意味は分かっていますか?
club33gold

2020/07/15 15:12

項目の間に” ”(スペース)を入れて結合するものと考えています。 そちらを行う事で、スペース区切りで書き込みがされるものと考えました。
LouiS0616

2020/07/17 12:48

そのとおりです。では、『項目の間に”,”(カンマ)を入れて結合する』ためにはどうすれば良いですか?
club33gold

2020/07/18 14:33

その場合は",".join(header) かと思われます。 ただし今回はスペース区切りで貼付となる認識でしたので、" ".join(header)を使用致しました。
LouiS0616

2020/07/18 23:57

カンマ区切りで出力したいのだと思っていましたが、違いましたか? 私がイメージしているコードを回答本文に追記してみました。ちょっと試してみて下さい。
club33gold

2020/07/19 16:22 編集

ありがとうございます。 結論として、” ”・”,”いずれの方法でもインポートとエクスポートが可能になりました。 -------------------------------------------------------------------------------------------- ●問題点と解決したい点 ・エクスポートされたデータをコピーして、エクセルに貼付 ・1行目:ヘッダーはhdr2 = ','.join(header)を使用するとカンマ区切で結合、A1セルに貼付される ・2行目の以降はきちんとA2/B2/C2/D2…に貼付される →1行目についてもA1/B1/C1/D1…に貼付したい  (※ただし読込設定でカンマ区切り等を設定すれば何とか読み込める) ●解決出来た点 ・hdr2 = ”  ”.join(header)を使用 ・2行目以降の値について、区切りのスペースが長い”  ”だったため、こちらを使用 ・結果として、エクスポートされたデータをコピーしてエクセルに貼付した際、きちんと表示される  ようになった。  (※文字列・数字列の概念は今回は不問)
club33gold

2020/07/19 16:23

多大なご教示を頂きまして、誠にありがとうございました。 こちらの内容にてベストアンサーとさせて頂きます。
guest

0

たんに最初の1行を読み飛ばせばいいだけでは。
難しく考える必要はないと思いますが

投稿2020/07/10 22:32

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

club33gold

2020/07/11 15:27

初心者のため、勝手が分からずに申し訳ありません。 単独ファイルで最初の1行を読み飛ばす事は出来るのですが、複数ファイルの場合が分かりませんでした。
guest

0

回答になってないかもしれませんが、個人的にはB案が一番汎用性があり良いと思います。

コードはそこまで難しくは無いはずです。
わからないことがあれば、質問してくだされば幸いです。

投稿2020/07/11 06:55

glyzinieh

総合スコア208

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

p.py

python3

1import glob 2 3def read_file(file_name): 4 with open(file_name) as f: 5 lines = f.read().splitlines() 6 return [lines[0], lines[1::]] 7 8out_file = "all.txt" 9in_files = "20*.txt" 10out_head = None 11with open(out_file, "w") as f: 12 for file in sorted(glob.glob(in_files)): 13 head, rows = read_file(file) 14 if out_head == None: 15 out_head = head 16 f.write(head + "\n") 17 if len(rows) > 0: 18 f.write("\n".join(rows) + "\n")

実行例
イメージ説明

参考情報:

  • [Python]ディレクトリ内にある複数のファイルをソートして読み込む

https://qiita.com/3000manJPY/items/6100452792e16d0ae921

  • python でファイルを read してリストにする時に、改行コードを入れない

https://qiita.com/suzuki-hoge/items/8eac60f7b68044eea6c1

投稿2020/07/11 00:17

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

club33gold

2020/07/11 15:26

ありがとうございます。 試しに入力してみましたが、下記のメッセージが出ました。 ------------------------------------------------------------------------ File "021.py", line 46, in <module> head, rows = read_file(file) File "021.py", line 38, in read_file lines = f.read().splitlines() UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 52: illegal multibyte sequence ------------------------------------------------------------------------ こちらの原因は分かりますでしょうか? (,encoding='utf-8')をどこかに入れる?であれば、ご教示頂けますと幸いです。
club33gold

2020/07/11 15:45

以下で解決しました。 out_file、in_filesは名称変更をしたので、"*****"の伏字表示にしています。 出力された内容も想定と相違ございません。 ------------------------------------------------------------------------ import glob def read_file(file_name): with open(file_name, encoding='utf-8') as f: lines = f.read().splitlines() return [lines[0], lines[1::]] out_file= "*****" in_files= "*****" out_head = None with open(out_file, "w",encoding="utf-8") as f: for file in sorted(glob.glob(in_files)): head, rows = read_file(file) if out_head == None: out_head = head f.write(head + "\n") if len(rows) > 0: f.write("\n".join(rows) + "\n")
club33gold

2020/07/11 16:00 編集

追加で2点質問です。 ・これは質問の最後にあるA案のフローでしょうか? ・確認用としてプロンプト上にout.fileの出力もしたいです。  f = open(out,encoding="utf-8")  print(f.read())  最後に上記を記載する事で動作確認済ですが、より簡単な書き方はありますでしょうか?
katoy

2020/07/13 10:04 編集

A 案です。 with open(out_file, "r") as f: print(f.read()) とするとよいです。 上のコメントのコードでは f.close を忘れがあります。 with を使えば close 忘れ防げます。
club33gold

2020/07/13 02:32

ありがとうございます!
katoy

2020/07/13 10:10

A,B案とも正確には 全部行を読むけど、どうやってヘッダ行を残す・捨てるの制御をするかの方針の差ですね。
guest

0

この問題を解くだけであれば、どの案でも構いません
難易度も大して変わりません

単一の課題であれば、どれか興味のある方法で問いてみましょう

単一の課題でなく、今後コードを拡張して別の問題を解いたり、何かにコードを利用するのであれば、
出題者に
「今後の拡張や利用も考えると、どの案が良いですか?」
と訊いてから進めた方が、無駄がなくてよいかもしれません

投稿2020/07/10 17:31

y_shinoda

総合スコア3272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

club33gold

2020/07/11 15:31

ありがとうございます。 後学のために(難易度が変わらないのであれば)A~C案を全て知りたいですが、一先ずはB案が良いと思います。 理由としては、もしヘッダーがない情報が発生した際、こちらで作成したheader.tableなどとマージすれば良いと考えたためです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問