Comment Pythons glob.glob est-il commandé?

199

J'ai écrit le code Python suivant:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os, glob

path = '/home/my/path'
for infile in glob.glob( os.path.join(path, '*.png') ):
    print infile

Maintenant, je reçois ceci:

/home/my/path/output0352.png
/home/my/path/output0005.png
/home/my/path/output0137.png
/home/my/path/output0202.png
/home/my/path/output0023.png
/home/my/path/output0048.png
/home/my/path/output0069.png
/home/my/path/output0246.png
/home/my/path/output0071.png
/home/my/path/output0402.png
/home/my/path/output0230.png
/home/my/path/output0182.png
/home/my/path/output0121.png
/home/my/path/output0104.png
/home/my/path/output0219.png
/home/my/path/output0226.png
/home/my/path/output0215.png
/home/my/path/output0266.png
/home/my/path/output0347.png
/home/my/path/output0295.png
/home/my/path/output0131.png
/home/my/path/output0208.png
/home/my/path/output0194.png

De quelle manière est-il ordonné?

Cela pourrait vous aider à obtenir ma sortie ls -l:

-rw-r--r-- 1 moose moose 627669 2011-07-17 17:26 output0005.png
-rw-r--r-- 1 moose moose 596417 2011-07-17 17:26 output0023.png
-rw-r--r-- 1 moose moose 543639 2011-07-17 17:26 output0048.png
-rw-r--r-- 1 moose moose 535384 2011-07-17 17:27 output0069.png
-rw-r--r-- 1 moose moose 543216 2011-07-17 17:27 output0071.png
-rw-r--r-- 1 moose moose 561776 2011-07-17 17:27 output0104.png
-rw-r--r-- 1 moose moose 501865 2011-07-17 17:27 output0121.png
-rw-r--r-- 1 moose moose 547144 2011-07-17 17:27 output0131.png
-rw-r--r-- 1 moose moose 530596 2011-07-17 17:27 output0137.png
-rw-r--r-- 1 moose moose 532567 2011-07-17 17:27 output0182.png
-rw-r--r-- 1 moose moose 553562 2011-07-17 17:27 output0194.png
-rw-r--r-- 1 moose moose 574065 2011-07-17 17:27 output0202.png
-rw-r--r-- 1 moose moose 552197 2011-07-17 17:27 output0208.png
-rw-r--r-- 1 moose moose 559809 2011-07-17 17:27 output0215.png
-rw-r--r-- 1 moose moose 549046 2011-07-17 17:27 output0219.png
-rw-r--r-- 1 moose moose 566661 2011-07-17 17:27 output0226.png
-rw-r--r-- 1 moose moose 561678 2011-07-17 17:27 output0246.png
-rw-r--r-- 1 moose moose 525550 2011-07-17 17:27 output0266.png
-rw-r--r-- 1 moose moose 565715 2011-07-17 17:27 output0295.png
-rw-r--r-- 1 moose moose 568381 2011-07-17 17:28 output0347.png
-rw-r--r-- 1 moose moose 532768 2011-07-17 17:28 output0352.png
-rw-r--r-- 1 moose moose 535818 2011-07-17 17:28 output0402.png

Il n'est pas trié par nom de fichier ou par taille.

Autres liens: glob,ls

Martin Thoma
la source
2
La réponse finale semble être que la lscommande elle-même trie les fichiers par nom. 'ls -U' donne une liste non ordonnée de fichiers dans "l'ordre du répertoire".
Brian Peterson
2
Sur Windows, il a été trié, donc je suppose que c'est toujours le cas .. maintenant sur Ubuntu, cela m'a coûté le débogage. Note à vous-même - lisez l'api! : 0)
Yuri Feldman
Le comportement est le même avec os.listdir: * nix OS renvoie les fichiers dans un ordre assez non alphabétique, et (honte à moi d'être surpris!) C'est explicite dans la documentation : "La liste est dans un ordre arbitraire".
Joël

Réponses:

112

Il n'est probablement pas trié du tout et utilise l'ordre dans lequel les entrées apparaissent dans le système de fichiers, c'est-à-dire celui que vous obtenez lors de l'utilisation ls -U. (Au moins sur ma machine, cela produit le même ordre que la liste des globcorrespondances).

Xion
la source
1
Oui, à moins qu'il ne fasse un effort particulier, il affichera simplement les entrées telles que fournies par le système d'exploitation. Identique à la commande "find" sous Unix, elle sauvegarde simplement les entrées dans l'ordre dans lequel elles proviennent de la structure de données utilisée par le système de fichiers sous-jacent. Vous ne devez pas faire d'hypothèses sur son ordre, même si vous voyez que les fichiers semblent apparaître dans l'ordre de création.
Raúl Salinas-Monteagudo
422

L'ordre est arbitraire, mais vous pouvez les trier vous-même

Si vous souhaitez trier par nom:

sorted(glob.glob('*.png'))

trié par heure de modification:

import os
sorted(glob.glob('*.png'), key=os.path.getmtime)

trié par taille:

import os
sorted(glob.glob('*.png'), key=os.path.getsize)

etc.

John La Rooy
la source
1
J'ai des fichiers, où les noms ne sont que des entiers, sans extension, donc je l' utilise: files = glob.glob('teksty/*'). La commande par nom sera-t-elle accordée?
andilabs
3
@mgalgs Non, ce n'était pas la question que je voulais vraiment poser. Ce que je voulais savoir a été répondu par Xion.
Martin Thoma
Et que dire du tri par date de création mais en fonction de l'heure de création. Parce qu'il me répertorie d'abord les fichiers les plus récents. Comment puis-je obtenir une liste des fichiers les plus anciens aux plus récents? Je vous remercie!
joaquindev
1
Notez que getmtime et getsize sont relativement chers - cela peut prendre un certain temps pour beaucoup de fichiers ..
drevicko
53

En vérifiant le code source de glob.globvous voyez qu'il appelle en interne os.listdir, décrit ici:

http://docs.python.org/library/os.html?highlight=os.listdir#os.listdir

Phrase clé: os.listdir (chemin) Renvoie une liste contenant les noms des entrées du répertoire donnés par chemin. La liste est dans un ordre arbitraire. Il n'inclut pas les entrées spéciales "." et '..' même s'ils sont présents dans le répertoire.

Ordre arbitraire . :)

Ray Toal
la source
14

glob.glob () est un wrapper autour de os.listdir () donc le système d'exploitation sous-jacent est responsable de la livraison des données. En général: vous ne pouvez pas faire d'hypothèse sur la commande ici. L'hypothèse de base est: pas de commande. Si vous avez besoin d'un tri: triez au niveau de l'application.

Andreas Jung
la source
13

L'ordre est arbitraire, mais il existe plusieurs façons de les trier. L'un d'eux est le suivant:

#First, get the files:
import glob
import re
files =glob.glob1(img_folder,'*'+output_image_format)
# if you want sort files according to the digits included in the filename, you can do as following:
files = sorted(files, key=lambda x:float(re.findall("(\d+)",x)[0]))
avril
la source
Que apporte votre réponse par rapport aux réponses existantes?
Martin Thoma
2
@MartinThoma J'ai un problème avec le tri qui ne trie pas les noms de fichiers si les nombres entiers présents dans les fichiers ne sont pas remplis par zéro. Le tri commence à 1000, monte jusqu'à ce que l'entier le plus élevé soit, puis recommence à partir du plus petit entier. Si je mets à zéro les numéros, un simple appel trié sur les fichiers les trie parfaitement. Je pense donc que cette solution résout le problème lorsque le tri seul ne fonctionne pas.
Will.Evo
1
@ Will.Evo Essayez d' utiliser natsort: from natsort import natsorted; files = natsorted(files).
Martin Thoma
Votre réponse a aidé!
Vineet
12

J'ai eu un problème similaire, je globrenvoyais une liste de noms de fichiers dans un ordre arbitraire mais je voulais les parcourir dans l'ordre numérique indiqué par le nom du fichier. Voici comment je l'ai réalisé:

Mes fichiers ont été retournés par glob quelque chose comme:

myList = ["c:\tmp\x\123.csv", "c:\tmp\x\44.csv", "c:\tmp\x\101.csv", "c:\tmp\x\102.csv", "c:\tmp\x\12.csv"]

J'ai trié la liste en place, pour ce faire j'ai créé une fonction:

def sortKeyFunc(s):
    return int(os.path.basename(s)[:-4])

Cette fonction renvoie la partie numérique du nom de fichier et convertit en un entier. J'ai ensuite appelé la méthode de tri sur la liste en tant que telle:

myList.sort(key=sortKeyFunc)

Cela a renvoyé une liste en tant que telle:

["c:\tmp\x\12.csv", "c:\tmp\x\44.csv", "c:\tmp\x\101.csv", "c:\tmp\x\102.csv", "c:\tmp\x\123.csv"]
Hornbydd
la source
Je pense qu'il est plus élégant d'utiliser os.path.splitext(os.path.basename(s))[0]au lieu de os.path.basename(s)[:-4], donc la définition de la fonction sera. def sortKeyFunc(s): return int(os.path.splitext(os.path.basename(s))[0])
ePandit
1

Si vous vous demandez ce que glob.glob a fait sur votre système dans le passé et ne pouvez pas ajouter d' sortedappel, l'ordre sera cohérent sur les systèmes de fichiers Mac HFS + et sera l' ordre de traversée sur les autres systèmes Unix. Il aura donc probablement été déterministe à moins que le système de fichiers sous-jacent n'ait été réorganisé, ce qui peut se produire si des fichiers ont été ajoutés, supprimés, renommés, supprimés, déplacés, etc.

crizCraig
la source
Et APFS sur macOS?
Boris
0

De la solution de @Johan La Rooy, le tri des images à l'aide sorted(glob.glob('*.png'))ne fonctionne pas pour moi, la liste de sortie n'est toujours pas classée par leurs noms.

Cependant, cela sorted(glob.glob('*.png'), key=os.path.getmtime)fonctionne parfaitement.

Je suis un peu confus comment le tri par leurs noms ne fonctionne pas ici.

Merci à @Martin Thoma d'avoir publié cette excellente question et à @Johan La Rooy pour les solutions utiles.

Haoyu Wang
la source
-1

Veuillez essayer ce code:

sorted(glob.glob( os.path.join(path, '*.png') ),key=lambda x:float(re.findall("([0-9]+?)\.png",x)[0]))
faris
la source
-3
'''my file name is 
"0_male_0.wav", "0_male_2.wav"... "0_male_30.wav"... 
"1_male_0.wav", "1_male_2.wav"... "1_male_30.wav"... 
"8_male_0.wav", "8_male_2.wav"... "8_male_30.wav"

when I wav.read(files) I want to read them in a sorted torder, i.e., "0_male_0.wav"
"0_male_1.wav"
"0_male_2.wav" ...
"0_male_30.wav"
"1_male_0.wav"
"1_male_1.wav"
"1_male_2.wav" ...
"1_male_30.wav"
so this is how I did it.

Just take all files start with "0_*" as an example. Others you can just put it in a loop
'''

import scipy.io.wavfile as wav
import glob 
from os.path import isfile, join

#get all the file names in file_names. THe order is totally messed up
file_names = [f for f in listdir(audio_folder_dir) if isfile(join(audio_folder_dir, f)) and '.wav' in f] 
#find files that belongs to "0_*" group
filegroup0 = glob.glob(audio_folder_dir+'/0_*')
#now you get sorted files in group '0_*' by the last number in the filename
filegroup0 = sorted(filegroup0, key=getKey)

def getKey(filename):
    file_text_name = os.path.splitext(os.path.basename(filename))  #you get the file's text name without extension
    file_last_num = os.path.basename(file_text_name[0]).split('_')  #you get three elements, the last one is the number. You want to sort it by this number
    return int(file_last_num[2])

C'est comme ça que j'ai fait mon cas particulier. J'espère que c'est utile.

Elizabeth
la source
1
Vous devez modifier votre réponse en fonction de la question.
CodenameLambda
1
La question n'est pas de trier. Je sais (et je savais à l'époque) comment trier. La question concerne l'ordre par défaut.
Martin Thoma
1
Merci pour cet extrait de code, qui peut fournir une aide immédiate. Une explication appropriée améliorerait considérablement sa valeur éducative en montrant pourquoi il s'agit d'une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs ayant des questions similaires, mais pas identiques. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Toby Speight