96211


CD-ROMのファイル名一覧（ディレクトリ名はいらない）を取得したいと思っています。

[code]

    import glob
    import os
    files = glob.glob(‘e:/**’,recursive=True) //処理1
    fileonly = [f for f in files if os.path.isfile(f)] //処理2
    
[/code]

こんな感じで一覧取得できるのですがリスト内包表記を行なっている部分の処理が時間がかかります。  
time.time()で計測すると、336のファイル及びディレクトリから323のファイルのみを取り出す操作に、  
処理1：1.78秒、処理2：2.72秒かかります。特に2の処理を短縮したいです。

何かコードを見直す方法がありますでしょうか？


CC BY-SA 4.0
2023-09-14T02:10:53.607
96210
2023-09-16T09:11:07.523
44556
question
python
Pythonでファイル名一覧を速く取得したい


コメントにある通り、1段階で処理をすると早く終わります。ただ、ディレクトリを再帰的にたどる記述の分、`glob`
に比べるとコードが増えます。[`os.walk()`](https://docs.python.org/ja/3/library/os.html#os.walk)
を使うと、やや簡潔になるかと思います。

下のコードは、`glob` を使用した質問のコードと異なり、ディレクトリへのシンボリックリンクをたどりません。また `os.path.isfile`
はシンボリックリンクをたどってチェックしますが、下ではそのような処理は有りませんので、リンク先が存在しないシンボリックファイルなども結果に含まれます。

[code]

    import os
    
    root = os.getcwd()
    files = []
    for parent, _, child_files in os.walk(root):
        for f in child_files:
            files.append(os.path.join(parent, f))
    
[/code]

* * *

追記:

### 高速になる理由

上で処理が早く終わる理由は、使用している構文とは関係ありません。今回の処理内容ですと、内包表記に適したAPIは無さそうなので使用していませんが、内包表記で書けるのなら、それでも速度に大きな影響は無いはずです。

今回の処理で時間がかかる部分はIO（ファイルへのアクセス）ですので、これを最小限にすることが大事です。ディレクトリ内のファイルのリストを得るとともに、それらのファイルがディレクトリなのか否かの情報も取得できれば、再度
`os.path.isfile` などでアクセスするより効率的です。これを冒頭では「1段階」と表現しました。

よって、上のようなことが可能なAPIを選択します。例えば `os.scandir()` です。`os.walk()` も内部で `os.scandir()`
を使用しています。

> `listdir()` の代わりに `scandir()`
> を使用すると、ファイルタイプや属性情報も必要とするコードのパフォーマンスが大幅に向上します。これは、オペレーティングシステムがディレクトリのスキャン中にこの情報を提供した場合、`os.DirEntry`
> オブジェクトがその情報を公開するからです。すべての `os.DirEntry` メソッドはシステムコールを実行する場合がありますが、`is_dir()`
> と `is_file()` は、通常はシンボリックリンクにしかシステムコールを必要としません。
>
> [os ——
> os.scandir()](https://docs.python.org/ja/3/library/os.html#os.scandir)


CC BY-SA 4.0
2023-09-14T04:10:43.193
96211
2023-09-16T09:11:07.523
2023-09-16T09:11:07.523
3054
3054
96210
answer