Извлечение расширения из имени файла в Python

Ответы:

1991

Да. Используйте os.path.splitext(см. Документацию по Python 2.X или документацию по Python 3.X ):

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

В отличие от большинства попыток ручного разделения строк, он os.path.splitextбудет корректно обрабатываться /a/b.c/dкак не имеющий расширения .c/d, а не .bashrcкак расширение , и будет обрабатываться как не имеющий расширения вместо расширения .bashrc:

>>> os.path.splitext('/a/b.c/d')
('/a/b.c/d', '')
>>> os.path.splitext('.bashrc')
('.bashrc', '')
nosklo
источник
15
использование basenameнемного сбивает с толку здесь, так os.path.basename("/path/to/somefile.ext")как вернется"somefile.ext"
Jiaaro
17
не endswith()будет ли более портативным и питоническим?
Себастьян Мах
79
@ klingt.net Ну, в таком случае, .asdдействительно расширение !! Если вы думаете об этом, foo.tar.gzэто сжатый gzip файл ( .gz), который является tar-файлом ( .tar). Но это GZIP-файл в первую очередь. Я не ожидал бы, что это возвратит двойное расширение вообще.
nosklo
160
Стандартное соглашение о присвоении имен функциям Python действительно раздражает - почти каждый раз, когда я пересматриваю это, я ошибаюсь, что это так splittext. Если бы они просто сделали что-нибудь, чтобы обозначить разрыв между частями этого имени, было бы намного легче признать, что это splitExtили split_ext. Конечно, я не могу быть единственным человеком, который сделал эту ошибку?
ArtOfWarfare
9
@Vingtoft Вы ничего не упомянули о FileStorage werkzeug в своем комментарии, и этот вопрос не имеет никакого отношения к этому конкретному сценарию. Что-то может быть не так с тем, как вам передают имя файла. os.path.splitext('somefile.ext')=> ('somefile', '.ext'). Не стесняйтесь приводить реальный контрпример без ссылки на стороннюю библиотеку.
Gewthen
400
import os.path
extension = os.path.splitext(filename)[1]
Брайан Нил
источник
15
Из любопытства, почему import os.pathвместо from os import path?
Кисва
2
О, мне просто интересно, была ли какая-то конкретная причина за этим (кроме условностей). Я все еще изучаю Python и хотел узнать больше!
Кисва
55
на самом деле это зависит, если вы используете from os import pathимя, то оно pathбудет занято в вашей локальной области видимости, и другие, глядя на код, могут не сразу узнать, что путь - это путь от модуля os. Где, как будто вы используете import os.pathего, он удерживает его в osпространстве имен, и где бы вы ни делали вызов, люди сразу узнают, что он path()из osмодуля.
dennmat
18
Я знаю, что это не семантически отличается, но я лично считаю, что конструкция _, extension = os.path.splitext(filename)выглядит намного лучше.
Тим Гилберт
3
Если вы хотите, чтобы расширение было частью более сложного выражения, [1] может быть более полезным: if check_for_gzip and os.path.splitext(filename)[1] == '.gz':
gerardw
239

Новое в версии 3.4.

import pathlib

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

Я удивлен, что никто еще не упомянул pathlib, это pathlibкруто!

Если вам нужны все суффиксы (например, если у вас есть .tar.gz), .suffixesвернет список их!

jeromej
источник
13
пример для получения .tar.gz:''.join(pathlib.Path('somedir/file.tar.gz').suffixes)
user3780389
Отличный ответ. Я нашел этот учебник более полезным, чем документация: zetcode.com/python/pathlib
user118967
@ user3780389 Разве "foo.bar.tar.gz" все еще не будет действительным ".tar.gz"? Если это так, ваш фрагмент должен использовать, .suffixes[-2:]чтобы обеспечить получение только .tar.gz максимум.
Джеромей
111
import os.path
extension = os.path.splitext(filename)[1][1:]

Чтобы получить только текст расширения, без точки.

wonzbak
источник
73

Одним из вариантов может быть расщепление от точки:

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

Нет ошибки, если файл не имеет расширения:

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

Но вы должны быть осторожны

>>> "png".split(".")[-1]
'png'    # But file doesn't have an extension
Мурат Чорлу
источник
4
Это расстроится, если вы загрузите x.tar.gz
Кирилл
19
Не совсем. Расширение файла с именем «x.tar.gz» - это «gz», а не «tar.gz». os.path.splitext также дает расширение ".os".
Мурат Чорлу
1
мы можем использовать [1] вместо [-1]. Я не мог понять [-1] со сплитом
user765443
7
[-1], чтобы получить последний элемент из элементов, разделенных точкой. Пример:"my.file.name.js".split('.') => ['my','file','name','js]
Мурат Чорлу
1
@ BenjaminR ну ладно, вы оптимизируете список результатов. ['file', 'tar', 'gz']с 'file.tar.gz'.split('.') против ['file.tar', 'gz'] с 'file.tar.gz'.rsplit('.', 1). да, может быть
Мурат Чорлу
40

Стоит добавить туда пониже, чтобы вы не задавались вопросом, почему JPG не отображаются в вашем списке.

os.path.splitext(filename)[1][1:].strip().lower()
blented
источник
19

Любое из приведенных выше решений работает, но в linux я обнаружил, что в конце строки расширения есть новая строка, которая будет препятствовать успешному совпадению. Добавьте strip()метод до конца. Например:

import os.path
extension = os.path.splitext(filename)[1][1:].strip() 
yamex5
источник
1
Чтобы помочь моему пониманию, не могли бы вы объяснить, какое дополнительное поведение защищает второй индекс / срез? (т.е. [1:]в .splittext(filename)[1][1:]) - заранее спасибо
Сэмюэль Хармер
1
Сам понял: splittext()(в отличие от разделения строки с помощью «.») Включает в себя «.» символ в расширении. Дополнительный [1:]избавляется от этого.
Сэмюэль Хармер
17

При использовании splitext возникают проблемы с файлами с двойным расширением (например file.tar.gz, file.tar.bz2и т. Д.)

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

но должно быть: .tar.gz

Возможные решения здесь

XavierCLL
источник
35
Нет, это должен быть .gz
Роберт Симер
1
сделать это дважды, чтобы получить 2 расширения?
Маазза
1
@maazza да. gunzip somefile.tar.gz какое имя файла на выходе?
FlipMcF
1
Вот почему у нас есть расширение «tgz», которое означает: tar + gzip! : D
Нуно Анисето
1
@peterhil Не думаю, что вы хотите, чтобы ваш скрипт на python знал о приложении, используемом для создания имени файла. Это немного выходит за рамки вопроса. Не выбирайте в этом примере, «filename.csv.gz» также вполне допустимо.
FlipMcF
16

Вы можете найти некоторые замечательные вещи в модуле pathlib (доступно в python 3.x).

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

# Output 
'.txt'
r3t40
источник
14

Хотя это старая тема, но мне интересно, почему никто не упоминает очень простой API Python под названием rpartition в этом случае:

чтобы получить расширение заданного абсолютного пути к файлу, вы можете просто набрать:

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

пример:

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

даст вам: "CSV"

weiyixie
источник
1
Для тех , кто не знаком с API, rpartition возвращает кортеж: ("string before the right-most occurrence of the separator", "the separator itself", "the rest of the string"). Если нет разделителя найден, то возвращается кортеж будет: ("", "", "the original string").
Николай
14

Просто joinвсе 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
источник
12

Удивлен, это еще не упоминалось:

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

Льготы:

  • Работает, как и ожидалось, для всего, что я могу придумать
  • Нет модулей
  • Нет регулярных выражений
  • Кросс-платформенная
  • Легко расширяется (например, без начальных точек для расширения, только последняя часть расширения)

Как функция:

def get_extension(filename):
    basename = os.path.basename(filename)  # os independent
    ext = '.'.join(basename.split('.')[1:])
    return '.' + ext if ext else None
PascalVKooten
источник
1
Это приводит к исключению, когда файл не имеет расширения.
thiruvenkadam
4
Этот ответ абсолютно игнорирует вариант, если имя файла содержит много точек в имени. Пример get_extension ('cmocka-1.1.0.tar.xz') => '.1.0.tar.xz' - неверно.
PADYMKO
@PADYMKO, ИМХО, не следует создавать имена файлов с точками остановки как часть имени файла. Приведенный выше код не должен приводить к «tar.xz»
Douwe van der
2
Просто поменяй на [-1]потом.
PascalVKooten
11

Вы можете использовать splitна filename:

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

Это не требует дополнительной библиотеки

soheshdoshi
источник
10
filename='ext.tar.gz'
extension = filename[filename.rfind('.'):]
staytime
источник
2
Это приводит к тому, что последний символ filenameвозвращается, если имя файла вообще не имеет .. Это потому, что rfindвозвращает, -1если строка не найдена.
Mattst
6

Это техника прямого представления строк: я вижу много упомянутых решений, но думаю, что большинство рассматривает разделение. Сплит, однако, делает это при каждом появлении "." , То, что вы бы предпочли, это раздел.

string = "folder/to_path/filename.ext"
extension = string.rpartition(".")[-1]
Kenstars
источник
2
rpartition уже был предложен @weiyixie .
Николай
5

Другое решение с правым разделением:

# 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])
Арнальдо П. Фигейра Фигейра
источник
5

Даже на этот вопрос уже дан ответ, я бы добавил решение в Regex.

>>> import re
>>> file_suffix = ".*(\..*)"
>>> result = re.search(file_suffix, "somefile.ext")
>>> result.group(1)
'.ext'
Миха
источник
1
Или \.[0-9a-z]+$как в этом посте .
Pault
2

Настоящий однострочник, если вам нравится регулярное выражение. И это не имеет значения, даже если у вас есть дополнительные "." в середине

import re

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

Смотрите здесь для результата: Нажмите здесь

Виктор Ван
источник
0

Это самый простой способ получить имя файла и расширение в одну строку .

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

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

В отличие от других решений, вам не нужно импортировать какой-либо пакет для этого.

Рипон Кумар Саха
источник
2
это не работает для всех файлов или типов, например 'archive.tar.gz
studioj
0

Для забавы ... просто соберите расширения в диктовке и отследите их все в папке. Затем просто потяните нужные вам расширения.

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
источник
Это ужасная идея. Ваш код ломается для любого расширения файла, которое вы ранее не добавили!
Роберт
0

попробуй это:

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. получить все имя файла в списке
  2. разделить имя файла и проверить предпоследнее расширение, это в списке pen_ext или нет?
  3. если да, то присоедините его с последним расширением и установите его как расширение файла
  4. если нет, то просто добавьте последнее расширение как расширение файла
  5. а затем проверить это
Ибнул Хусайнан
источник
1
Это нарушает кучу особых случаев. Смотрите принятый ответ. Это заново изобретать колесо, только с ошибками.
Роберт
я обновил свой ответ
Ибнул Хусайнан
Здравствуйте! Хотя этот код может решить вопрос, в том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, получит больше голосов "за". Помните, что вы отвечаете на вопрос для читателей в будущем, а не только для того, кто спрашивает сейчас. Пожалуйста, измените свой ответ, чтобы добавить объяснения и указать, какие ограничения и предположения применяются.
Брайан
@ Брайан, как это?
Ибнул Хусайнан
Вы только усугубляете это, ломая это по-новому. foo.tarявляется допустимым именем файла. Что произойдет, если я добавлю это в ваш код? Как насчет .bashrcили foo? По этой причине есть библиотечная функция ...
Роберт,
-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
источник
-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
источник
-5
name_only=file_name[:filename.index(".")

Это даст вам имя файла до первого «.», Который будет наиболее распространенным.

Wookie
источник
1
Во-первых, ему нужно не имя, а расширение. Во-вторых, даже если ему понадобится имя, оно будет неверным для таких файлов, как:file.name.ext
ya_dimon
Как уже упоминалось @ya_dimon, это не будет работать для имен файлов с точками. Плюс ему нужно расширение!
Умар Дастгир