Extraire l'extension du nom de fichier en Python

Réponses:

1991

Oui. Utilisation os.path.splitext(voir la documentation Python 2.X ou la documentation Python 3.X ):

>>> import os
>>> filename, file_extension = os.path.splitext('/path/to/somefile.ext')
>>> filename
'/path/to/somefile'
>>> file_extension
'.ext'

Contrairement à la plupart des tentatives de fractionnement de chaînes manuelles, os.path.splitexttraitera correctement /a/b.c/dcomme n'ayant pas d'extension au lieu d'avoir une extension .c/d, et il traitera .bashrccomme n'ayant pas d'extension au lieu d'avoir une extension .bashrc:

>>> os.path.splitext('/a/b.c/d')
('/a/b.c/d', '')
>>> os.path.splitext('.bashrc')
('.bashrc', '')
nosklo
la source
15
l'utilisation de basenameest un peu déroutante ici car os.path.basename("/path/to/somefile.ext")reviendrait"somefile.ext"
Jiaaro
17
ne serait pas endswith()plus portable et pythonique?
Sebastian Mach
79
@ klingt.net Eh bien, dans ce cas, .asdc'est vraiment l'extension !! Si vous y réfléchissez, foo.tar.gzc'est un fichier compressé avec gzip ( .gz) qui se trouve être un fichier tar ( .tar). Mais c'est un fichier gzip en premier lieu. Je ne m'attendrais pas du tout à ce qu'il retourne la double extension.
nosklo
160
La convention de dénomination de la fonction Python standard est vraiment ennuyeuse - presque chaque fois que je revois cela, je la prends pour telle splittext. S'ils faisaient juste quelque chose pour signifier la rupture entre les parties de ce nom, il serait beaucoup plus facile de reconnaître que c'est splitExtou split_ext. Je ne peux sûrement pas être la seule personne à avoir fait cette erreur?
ArtOfWarfare
9
@Vingtoft Vous n'avez rien dit sur FileStorage de werkzeug dans votre commentaire et cette question n'a rien à voir avec ce scénario particulier. Quelque chose ne va peut-être pas dans la façon dont le nom de fichier vous est transmis. os.path.splitext('somefile.ext')=> ('somefile', '.ext'). N'hésitez pas à fournir un exemple de compteur réel sans référencer une bibliothèque tierce.
Gewthen
400
import os.path
extension = os.path.splitext(filename)[1]
Brian Neal
la source
15
Par curiosité, pourquoi import os.pathau lieu de from os import path?
kiswa
2
Oh, je me demandais simplement s'il y avait une raison spécifique derrière cela (autre que la convention). J'apprends toujours Python et je voulais en savoir plus!
kiswa
55
cela dépend vraiment, si vous utilisez from os import pathalors le nom pathest repris dans votre portée locale, aussi les autres personnes qui regardent le code peuvent ne pas savoir immédiatement que path est le chemin du module os. Où comme si vous l'utilisiez import os.pathle garde dans l' osespace de noms et où que vous fassiez l'appel, les gens le savent immédiatement path()depuis le osmodule.
dennmat
18
Je sais que ce n'est pas sémantiquement différent, mais je trouve personnellement que la construction _, extension = os.path.splitext(filename)est beaucoup plus jolie.
Tim Gilbert
3
Si vous voulez que l'extension fasse partie d'une expression plus complexe, le [1] peut être plus utile: if check_for_gzip and os.path.splitext(filename)[1] == '.gz':
gerardw
239

Nouveau dans la version 3.4.

import pathlib

print(pathlib.Path('yourPath.example').suffix) # '.example'

Je suis surpris que personne ne l'ait pathlibencore mentionné , c'est pathlibgénial!

Si vous avez besoin de tous les suffixes (par exemple, si vous en avez un .tar.gz), vous .suffixesen retournerez une liste!

jeromej
la source
13
exemple pour obtenir .tar.gz:''.join(pathlib.Path('somedir/file.tar.gz').suffixes)
user3780389
Très bonne réponse. J'ai trouvé ce tutoriel plus utile que la documentation: zetcode.com/python/pathlib
user118967
@ user3780389 Un "foo.bar.tar.gz" ne serait-il pas toujours un ".tar.gz" valide? Si tel est le cas, votre extrait doit être utilisé .suffixes[-2:]pour vous assurer d'obtenir uniquement .tar.gz au maximum.
jeromej
111
import os.path
extension = os.path.splitext(filename)[1][1:]

Pour obtenir uniquement le texte de l'extension, sans le point.

wonzbak
la source
73

Une option peut être la séparation du point:

>>> filename = "example.jpeg"
>>> filename.split(".")[-1]
'jpeg'

Aucune erreur lorsque le fichier n'a pas d'extension:

>>> "filename".split(".")[-1]
'filename'

Mais vous devez faire attention:

>>> "png".split(".")[-1]
'png'    # But file doesn't have an extension
Murat Çorlu
la source
4
Cela serait contrarié si vous téléchargez x.tar.gz
Kirill
19
Pas maintenant. L'extension d'un fichier nommé "x.tar.gz" est "gz" et non "tar.gz". os.path.splitext donne également l'extension ".os".
Murat Çorlu
1
pouvons-nous utiliser [1] plutôt que [-1]. Je ne pouvais pas comprendre [-1] avec split
user765443
7
[-1] pour obtenir le dernier élément des éléments fractionnés par un point. Exemple:"my.file.name.js".split('.') => ['my','file','name','js]
Murat Çorlu
1
@BenjaminR ah ok, vous faites une optimisation sur la liste des résultats. ['file', 'tar', 'gz']avec 'file.tar.gz'.split('.') vs ['file.tar', 'gz'] avec 'file.tar.gz'.rsplit('.', 1). oui, ça pourrait l'être.
Murat Çorlu
40

cela vaut la peine d'ajouter un plus bas pour que vous ne vous demandiez pas pourquoi les JPG n'apparaissent pas dans votre liste.

os.path.splitext(filename)[1][1:].strip().lower()
mélangé
la source
19

N'importe laquelle des solutions ci-dessus fonctionne, mais sur Linux, j'ai trouvé qu'il y a une nouvelle ligne à la fin de la chaîne d'extension qui empêchera les correspondances de réussir. Ajoutez la strip()méthode à la fin. Par exemple:

import os.path
extension = os.path.splitext(filename)[1][1:].strip() 
yamex5
la source
1
Pour aider à ma compréhension, pourriez-vous expliquer le comportement supplémentaire que le deuxième index / tranche protège contre? (c.- [1:]à .splittext(filename)[1][1:]-d. l'entrée) - merci d'avance
Samuel Harmer
1
splittext()Je l'ai compris moi-même: (contrairement à si vous divisez une chaîne en utilisant '.') Inclut le '.' caractère dans l'extension. L'additionnel [1:]s'en débarrasse.
Samuel Harmer
17

Avec splitext il y a des problèmes avec les fichiers à double extension (par exemple file.tar.gz, file.tar.bz2, etc ..)

>>> fileName, fileExtension = os.path.splitext('/path/to/somefile.tar.gz')
>>> fileExtension 
'.gz'

mais devrait être: .tar.gz

Les solutions possibles sont ici

XavierCLL
la source
35
Non, ce devrait être .gz
Robert Siemer
1
faire deux fois pour obtenir les 2 extensions?
maazza
1
@maazza yep. gunzip somefile.tar.gz quel est le nom du fichier de sortie?
FlipMcF
1
C'est pourquoi nous avons l'extension 'tgz' qui signifie: tar + gzip! : D
Nuno Aniceto
1
@peterhil Je ne pense pas que vous souhaitiez que votre script python connaisse l'application utilisée pour créer le nom de fichier. C'est un peu hors de portée de la question. Ne choisissez pas l'exemple, 'filename.csv.gz' est également tout à fait valide.
FlipMcF
16

Vous pouvez trouver de bonnes choses dans le module pathlib (disponible en python 3.x).

import pathlib
x = pathlib.PurePosixPath("C:\\Path\\To\\File\\myfile.txt").suffix
print(x)

# Output 
'.txt'
r3t40
la source
14

Bien qu'il s'agisse d'un sujet ancien, mais je me demande pourquoi il n'y a aucun mention d'une API très simple de python appelée rpartition dans ce cas:

pour obtenir l'extension d'un chemin absolu de fichier donné, vous pouvez simplement taper:

filepath.rpartition('.')[-1]

exemple:

path = '/home/jersey/remote/data/test.csv'
print path.rpartition('.')[-1]

vous donnera: 'csv'

weiyixie
la source
1
Pour ceux qui ne connaissent pas l'API, rpartition retourne un tuple: ("string before the right-most occurrence of the separator", "the separator itself", "the rest of the string"). S'il n'y a pas de séparateur trouvé, le tuple retourné sera: ("", "", "the original string").
Nickolay
14

Juste jointous pathlib suffixes.

>>> x = 'file/path/archive.tar.gz'
>>> y = 'file/path/text.txt'
>>> ''.join(pathlib.Path(x).suffixes)
'.tar.gz'
>>> ''.join(pathlib.Path(y).suffixes)
'.txt'
Alex
la source
12

Surpris, cela n'a pas encore été mentionné:

import os
fn = '/some/path/a.tar.gz'

basename = os.path.basename(fn)  # os independent
Out[] a.tar.gz

base = basename.split('.')[0]
Out[] a

ext = '.'.join(basename.split('.')[1:])   # <-- main part

# if you want a leading '.', and if no result `None`:
ext = '.' + ext if ext else None
Out[] .tar.gz

Avantages:

  • Fonctionne comme prévu pour tout ce à quoi je peux penser
  • Aucun module
  • Aucun regex
  • Multiplateforme
  • Facilement extensible (par exemple, pas de points de tête pour l'extension, uniquement la dernière partie de l'extension)

Comme fonction:

def get_extension(filename):
    basename = os.path.basename(filename)  # os independent
    ext = '.'.join(basename.split('.')[1:])
    return '.' + ext if ext else None
PascalVKooten
la source
1
Il en résulte une exception lorsque le fichier n'a pas d'extension.
thiruvenkadam
4
Cette réponse ignore absolument une variante si un nom de fichier contient de nombreux points dans le nom. Exemple get_extension ('cmocka-1.1.0.tar.xz') => '.1.0.tar.xz' - incorrect.
PADYMKO
@PADYMKO, à mon humble avis, il ne faut pas créer de noms de fichiers avec des points dans le nom de fichier. Le code ci-dessus n'est pas censé aboutir à 'tar.xz'
Douwe van der Leest
2
Remplacez-le [-1]ensuite.
PascalVKooten
11

Vous pouvez utiliser un splitsur filename:

f_extns = filename.split(".")
print ("The extension of the file is : " + repr(f_extns[-1]))

Cela ne nécessite pas de bibliothèque supplémentaire

soheshdoshi
la source
10
filename='ext.tar.gz'
extension = filename[filename.rfind('.'):]
séjour
la source
2
Cela se traduit par le dernier caractère d' filenameêtre retourné si le nom de fichier n'en a pas .du tout. En effet, rfindrenvoie -1si la chaîne n'est pas trouvée.
mattst
6

Il s'agit d'une technique de représentation directe des chaînes: je vois beaucoup de solutions mentionnées, mais je pense que la plupart envisagent le split. Split le fait cependant à chaque occurrence de "." . Ce que vous préférez, c'est la partition.

string = "folder/to_path/filename.ext"
extension = string.rpartition(".")[-1]
Kenstars
la source
2
rpartition a déjà été suggéré par @weiyixie .
Nickolay
5

Une autre solution avec split droit:

# to get extension only

s = 'test.ext'

if '.' in s: ext = s.rsplit('.', 1)[1]

# or, to get file name and extension

def split_filepath(s):
    """
    get filename and extension from filepath 
    filepath -> (filename, extension)
    """
    if not '.' in s: return (s, '')
    r = s.rsplit('.', 1)
    return (r[0], r[1])
Arnaldo P. Figueira Figueira
la source
5

Même cette question est déjà répondue, j'ajouterais la solution dans Regex.

>>> import re
>>> file_suffix = ".*(\..*)"
>>> result = re.search(file_suffix, "somefile.ext")
>>> result.group(1)
'.ext'
Micha
la source
1
Ou \.[0-9a-z]+$comme dans ce post .
pault
2

Un vrai one-liner, si vous aimez les regex. Et cela n'a pas d'importance même si vous avez des "." Supplémentaires. au milieu

import re

file_ext = re.search(r"\.([^.]+)$", filename).group(1)

Voir ici pour le résultat: Cliquez ici

Victor Wang
la source
0

Il s'agit de la méthode la plus simple pour obtenir à la fois le nom de fichier et l'extension en une seule ligne .

fName, ext = 'C:/folder name/Flower.jpeg'.split('/')[-1].split('.')

>>> print(fName)
Flower
>>> print(ext)
jpeg

Contrairement à d'autres solutions, vous n'avez pas besoin d'importer de package pour cela.

Ripon Kumar Saha
la source
2
cela ne fonctionne pas pour tous les fichiers ou types par exemple 'archive.tar.gz
studioj
0

Pour les drôles ... il suffit de rassembler les extensions dans un dict et de les suivre toutes dans un dossier. Tirez ensuite les extensions que vous souhaitez.

import os

search = {}

for f in os.listdir(os.getcwd()):
    fn, fe = os.path.splitext(f)
    try:
        search[fe].append(f)
    except:
        search[fe]=[f,]

extensions = ('.png','.jpg')
for ex in extensions:
    found = search.get(ex,'')
    if found:
        print(found)
eatmeimadanish
la source
C'est une terrible idée. Votre code se casse pour toute extension de fichier que vous n'avez pas déjà ajoutée!
Robert
0

essaye ça:

files = ['file.jpeg','file.tar.gz','file.png','file.foo.bar','file.etc']
pen_ext = ['foo', 'tar', 'bar', 'etc']

for file in files: #1
    if (file.split(".")[-2] in pen_ext): #2
        ext =  file.split(".")[-2]+"."+file.split(".")[-1]#3
    else:
        ext = file.split(".")[-1] #4
    print (ext) #5
  1. obtenir tous les noms de fichiers dans la liste
  2. diviser le nom de fichier et vérifier l'avant-dernière extension, est-ce dans la liste pen_ext ou non?
  3. si oui, joignez-le à la dernière extension et définissez-le comme extension du fichier
  4. sinon, il suffit de mettre la dernière extension comme extension du fichier
  5. puis vérifiez-le
Ibnul Husainan
la source
1
Cela se brise pour un tas de cas spéciaux. Voir la réponse acceptée. C'est réinventer la roue, uniquement en buggy.
Robert
j'ai mis à jour ma réponse
Ibnul Husainan
salut! Bien que ce code puisse résoudre la question, y compris une explication de comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message, et entraînerait probablement plus de votes positifs. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir, pas seulement à la personne qui pose la question maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Brian
@Brian comme ça?
Ibnul Husainan
Vous ne faites qu'empirer les choses, en les cassant de nouvelles façons. foo.tarest un nom de fichier valide. Que se passe-t-il si je jette ça sur votre code? Et pour .bashrcou foo? Il y a une fonction de bibliothèque pour cela pour une raison ...
Robert
-2
# try this, it works for anything, any length of extension
# e.g www.google.com/downloads/file1.gz.rs -> .gz.rs

import os.path

class LinkChecker:

    @staticmethod
    def get_link_extension(link: str)->str:
        if link is None or link == "":
            return ""
        else:
            paths = os.path.splitext(link)
            ext = paths[1]
            new_link = paths[0]
            if ext != "":
                return LinkChecker.get_link_extension(new_link) + ext
            else:
                return ""
DragonX
la source
-3
def NewFileName(fichier):
    cpt = 0
    fic , *ext =  fichier.split('.')
    ext = '.'.join(ext)
    while os.path.isfile(fichier):
        cpt += 1
        fichier = '{0}-({1}).{2}'.format(fic, cpt, ext)
    return fichier
user5535053
la source
-5
name_only=file_name[:filename.index(".")

Cela vous donnera le nom du fichier jusqu'au premier ".", Qui serait le plus courant.

wookie
la source
1
d'abord, il n'a pas besoin du nom, mais de l'extension. Deuxièmement, même s'il aurait besoin d'un nom, ce serait mal avec des fichiers comme:file.name.ext
ya_dimon
Comme mentionné par @ya_dimon, cela ne fonctionnera pas pour les noms de fichiers avec des points. De plus, il a besoin de l'extension!
Umar Dastgir