Перейти к содержимому

Как узнать формат файла python

  • автор:

Определение типа файла без расширения в Python

Определение типа файла без расширения или по его содержимому (если тип указан неверно) можно при помощи стороннего модуля magic .

Установить модуль magic можно через менеджер пакетов pip . Устанавливайте сторонние модули только в виртуальное окружение.

Модуль python-magic — это интерфейс Python для библиотеки ОС идентификации типов файлов libmagic . Эта библиотека идентифицирует типы файлов, проверяя их заголовки в соответствии с предопределенным списком типов файлов. Функция операционной системы magic() доступна в командной строке с помощью командного файла Unix.

(myVenv) $ pip install python-magic
>>> import magic >>> mime = magic.Magic(mime=True) >>> mime.from_file("testdata/test.pf") # 'application/pdf' >>> magic.from_file('iceland.jpg') # 'JPEG image data, JFIF standard 1.01' >>> magic.from_file('iceland.jpg', mime=True) # 'image/jpeg' >>> magic.from_file('greenland.png') # 'PNG image data, 600 x 1000, 8-bit colormap, non-interlaced' >>> magic.from_file('greenland.png', mime=True) # 'image/png' 

Если файл большой, то можно прочитать часть файла в буфер. Рекомендуется использовать по крайней мере первые 2048 байт, так как меньше может привести к неправильной идентификации.

>>> import magic # рекомендуется использовать по крайней мере первые 2048 байт, # так как меньше может привести к неправильной идентификации >>> magic.from_buffer(open("testdata/test.pdf").read(2048)) # 'PDF document, version 1.2' 

Можно даже распознать формат файла упакованного в архив!

>>> import magic >>> f = magic.Magic(uncompress=True) >>> f.from_file('testdata/test.gz') # 'ASCII text (gzip compressed data, was "test", last modified: # Mon 04 Jan 2021 01:55:22 PM MSK, from Unix)' 

Можно также комбинировать параметры флагов.

>>> f = magic.Magic(mime=True, uncompress=True) >>> f.from_file('testdata/test.gz') # 'text/plain' 
  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Функция init() модуля mimetypes
  • Функция guess_type() модуля mimetypes
  • Функции guess_all_extensions() и guess_extensions() модуля mimetypes
  • Функция add_type() модуля mimetypes
  • Функция read_mime_types() модуля mimetypes
  • Класс MimeTypes() модуля mimetypes
  • Словари MIME-типов, загружаемые модулем mimetypes из системы
  • Как определить тип файла по его содержимому

Определение расширения файла в python

Как в python сделать максимально правильно проверку на расширения файла ? Скажем, ко мне попадает имя файла и я хочу сделать проверку на то, является ли его расширения .py или нет.

Отслеживать
задан 30 июн 2016 в 10:55
7,748 17 17 золотых знаков 72 72 серебряных знака 133 133 бронзовых знака
Может проверить, что строка на .py оканчивается?
30 июн 2016 в 10:58
Но учтите, что расширение .py совсем не обязательно значит, что внутри Python-код
30 июн 2016 в 11:39

Если надо определить тип файла по содержимому, то используйте libmagic и какую-нибудь питоновскую обертку на выбор.

30 июн 2016 в 12:10

6 ответов 6

Сортировка: Сброс на вариант по умолчанию

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

Отслеживать
ответ дан 30 июн 2016 в 10:59
3,071 12 12 серебряных знаков 20 20 бронзовых знаков

ко мне попадает имя файла и я хочу сделать проверку на то, является ли его расширения .py

filename.endswith(‘.py’) метод возвращает оканчивается ли filename (строка, содержащая имя файла) на ‘.py’ .

>>> from pathlib import Path >>> Path('my/library/setup.py').suffix == '.py' True 

Если нужно найти все расширения, то можно .suffixes атрибут использовать:

>>> Path('my/library.tar.gz').suffixes ['.tar', '.gz'] 

«максимально правильно» использовать самый простой читаемый код, который работает.

Существенным отличием является случай, когда имя директории задано со слешом на конце, тогда поведение pathlib.Path отличается от os.path.splitext() или str.endswith() :

>>> import os >>> os.path.splitext('pypy/rlib/rsre__gen.py/')[1] == '.py' False # not True. >>> 'pypy/rlib/rsre__gen.py/'.endswith('.py') False # not True. >>> Path('pypy/rlib/rsre__gen.py/').suffix == '.py' True 

Отслеживать
ответ дан 30 июн 2016 в 13:18
52.3k 11 11 золотых знаков 108 108 серебряных знаков 312 312 бронзовых знаков

>>> Path(‘Я.и.моя.самая любимая.кошка.jpg.wtf.tar.gz’).suffixes => [‘.и’, ‘.моя’, ‘.самая любимая’, ‘.кошка’, ‘.jpg’, ‘.wtf’, ‘.tar’, ‘.gz’] — чёт мда)

30 июн 2016 в 15:58

Тут надо уточнить, что pathlib в стандартной поставке python появилась только с версии 3.3. Может быть установлена отдельным пакетом

1 июл 2016 в 6:19
@FeroxTL вопрос имеет python-3.x таг. Текущая версия Python 3.5 (Python 3.3 вышел в 2012 году).
1 июл 2016 в 6:32
@andreymal вы какое-то другое поведение ожидали? Приведите ожидаемый результат.
24 июл 2016 в 3:41

Можно использовать библиотеку magic :

import magic mime = magic.Magic(mime=True) mime.from_file("testdata/test.pf") # 'application/pdf' magic.from_file('iceland.jpg') # 'JPEG image data, JFIF standard 1.01' magic.from_file('iceland.jpg', mime=True) # 'image/jpeg' magic.from_file('greenland.png') # 'PNG image data, 600 x 1000, 8-bit colormap, non-interlaced' magic.from_file('greenland.png', mime=True) 

Отслеживать
ответ дан 11 мар 2022 в 12:52
vovakirdan vovakirdan
141 5 5 бронзовых знаков
у вас ответ про mime-тип содержимого файла, а в вопросе речь всего лишь о суффиксе в имени файла.
11 мар 2022 в 13:21

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

11 мар 2022 в 13:33

extension = '/path/to/somefile.ext'.split('.')[-1] print(extension) 

Отслеживать
ответ дан 14 янв 2017 в 16:04

Быстрее всего без всяких массивов и суффиксов:

ext = somefilename[somefilename.rfind(".") + 1:] 

Отслеживать
19.1k 6 6 золотых знаков 30 30 серебряных знаков 44 44 бронзовых знака
ответ дан 6 окт 2017 в 10:05
тогда уж ext = somefilename.rsplit(‘.’, 1)[-1]
6 окт 2017 в 10:51
@dstwo в случае, если файл не имеет расширения, в ext будет вся исходная строка somefilename .
6 окт 2017 в 11:51

#Слишком вручную, но это то что сразу приходит на ум import os t=input('Введите путь к папке: ') docs,music,other=[],[],[] for root, dirs, files in os.walk(t): for file in files: if file[-4::]=='.doc' or file[-5::]=='.docx': docs.append(os.path.join( file)) elif file[-4::]=='.mp3' or file[-4::]=='.wav': music.append(os.path.join( file)) #Сюда вставляем любые форматы else: other.append(os.path.join( file)) print('\nДОКУМЕНТЫ:\n') for el in docs: print(el) print('\nМУЗЫКА:\n') for el in music: print(el) print('\nДРУГОЕ:\n') for el in other: print(el) 

Отслеживать
ответ дан 29 июл 2021 в 7:58
Павел Горбель Павел Горбель

Лучше так не делать. Одно неосторожное движение, т.е. один неправильно посчитанный индекс (например, если случайно написать file[-4::]==’.docx’ вместо -5), и расширение не определится. Если уж знаете про os.path , то имеет смысл использовать os.path.splitext из принятого ответа.

29 июл 2021 в 8:09

Если как строку проверять, то лучше уж через endswith: if file.endswith(‘.doc’) or file.endswith(‘.docx’):

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

Часто возникает ситуация, когда при работе с файлами нужно получить их расширение. Например, при обработке большого количества файлов разных типов, будет полезно знать, какой формат у каждого из них. Допустим, есть файл с именем «example.txt». Задача — получить расширение этого файла, то есть «txt».

Python предоставляет несколько способов для извлечения расширения из имени файла. Рассмотрим некоторые из них.

Использование модуля os

Модуль os в Python предоставляет множество функций для работы с операционной системой. В частности, функция os.path.splitext() разделяет путь к файлу на две части — путь и расширение, и возвращает их в виде кортежа.

import os filename = "example.txt" basename, extension = os.path.splitext(filename) print(extension)

В результате выполнения этого кода будет выведено расширение файла: «.txt». Отметим, что функция возвращает расширение вместе с точкой.

Использование модуля pathlib

Модуль pathlib является более современным и удобным способом работы с файловыми системами. Для извлечения расширения из имени файла можно использовать метод .suffix объекта Path .

from pathlib import Path filename = "example.txt" extension = Path(filename).suffix print(extension)

Также, как и в случае с os.path.splitext() , расширение возвращается вместе с точкой.

Вывод

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

Статья Определение типа файла по его сигнатуре с помощью Python

Вполне возможно, что при разработке приложений вам может понадобиться определение типа файла. И не всегда тип файла можно узнать по расширению. Если в ОС Linux это не составляет больших проблем, так как данная операционная система распознает тип файла не по расширению, а по содержимому, то вот в Windows отсутствие расширения иногда вызывает множество вопросов. Давайте попробуем понять, как можно определить тип файла с помощью Python.

68416866.jpg

К сожалению, в Python встроенного модуля для определения типа файлов нет. Но есть модули сторонних разработчиков. Да, в стандартной поставке есть mimetypes, однако распознавать содержимое файла без расширения он не умеет.

Из сторонних модулей можно выделить magic. С ее помощью довольно точно можно узнать mime-тип файла. Вот только работа данного модуля завязана на библиотеку libmagic1. То есть, по сути это просто оболочка вокруг данной библиотеки. И для работы модуля требуется ее наличие. И если в Linux зачастую она установлена по умолчанию, то вот в Windows понадобиться установить библиотеки DLL. Давайте чуть подробнее рассмотрим, что нужно для того, чтобы работать с данным модулем, его установку и требования.

Что понадобиться?

Для начала необходимо установить сам модуль. Поэтому пишем в терминале команду:

pip install python-magic

В принципе, если вы работаете в Linux, установки библиотеки libmagic1 может и не понадобиться. К примеру, в Linux Mint данная библиотека установлена «из коробки». Однако, если, все же, у вас ее нет, то установка библиотеки в Ubuntu/Debian делается командой:

sudo apt-get install libmagic1

Если вы работаете в операционной системе Windows, то нужно установить DLL с помощью команды:

pip install python-magic-bin

В принципе, на этом все. Для работы модуля больше ничего особо не требуется.

Определение mime-типа файла с помощью magic

Давайте напишем маленький скрипт, для примера, чтобы понять, как работает данная библиотека.
Импортируем в скрипт нужные модули:

from pathlib import Path import magic

Теперь напишем небольшую функцию из одной строки, которая будет принимать путь к файлу и просто печатать его mime-тип.

def mime_magic(path): print(magic.Magic(mime=True).from_file(path))

И теперь, в функции main, вызовем данную функцию и передадим в нее путь к файлу.

def main(): path = input("Введите путь к файлу: ") if not Path(path).exists(): print("Файла не существует!") mime_magic(path) if __name__ == "__main__": main()

Скрипт в сборе

from pathlib import Path import magic def mime_magic(path): print(magic.Magic(mime=True).from_file(path)) def main(): path = input("Введите путь к файлу: ") if not Path(path).exists(): print("Файла не существует!") mime_magic(path) if __name__ == "__main__": main()

Я специально удалил расширение у файла и передал в функцию путь к нему. И вот, что я получил на выходе:

01.png

Однако, как я уже писал ранее, данный модуль — это только обертка python над библиотекой libmagic1. И здесь, если вы пишите переносимое приложение, придется тащить за собой все остальные зависимости. Проверять, установлена ли библиотека или, в случае с Windows устанавливать библиотеки DLL.

Но, есть еще один, более «хардкорный» путь. Ничего нового в нем нет, но он требует получения сигнатуры файла и сравнения со списком или словарем сигнатур для получения типа файла.

Определение типа файла по его сигнатуре

Понятие сигнатура файла известно так же как «магическое число». Это целочисленная или текстовая константа, с помощью которой можно однозначно идентифицировать ресурс или данные. Само по себе, это число не несет никакого смысла. Примером такого магического числа может служить исполняемый файл Windows с расширением .exe. Он начинается с последовательности байт 0x4D5A, и это само по себе символично, так как соответствует ASCII-символам MZ, которые являются инициалами Марка Збиковски являющегося одним из создателей MS-DOS.

В Linux, как я уже писал выше, тип файла определяется по его содержимому, точнее, по его сигнатуре, вне зависимости от его расширения и названия. Для того, чтобы интерпретировать сигнатуру файла можно использовать стандартную утилиту file.

Как же можно использовать это в скрипте python? Для примера я составил небольшой словарик сигнатур файлов. Конечно же, это только очень маленькая часть от огромного количества самых разнообразных сигнатур. Однако, это уже позволяет определить тип некоторых мультимедийных форматов файлов. Данные сигнатуры были взяты из статьи Википедии по этому

Ссылка скрыта от гостей

. Давайте от теории перейдем к практике.

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

import sys from pathlib import Path

Теперь инициализируем словарь с сигнатурами. Конечно же, если бы это был более масштабный проект, имело бы смысл вынести данные сигнатуры в отдельный модуль или json-файл. Но, так как, это лишь пример того, как определить сигнатуру, словарь маленький, а потому выносить его в отдельный модуль не имеет смысла.

signature =

Напишем небольшую функцию, в которой и будет происходить основное действие. Я назвал ее read_file(path). На входе она получает путь к файлу, тип которого требуется определить. А на выходе мы получаем тип файла или сообщение о невозможности определить сигнатуру.

Откроем файл на чтение в байтовом режиме. Считаем первые 256 байт. Этого вполне достаточно для того, чтобы определить тип файла. Переведем полученные данные в шестнадцатеричный вид.

 with open(path, 'rb') as f: file = f.read(256) hex_bytes = " ".join([''.format(byte) for byte in file])

Запустим цикл для итерации по словарю сигнатур. В данном цикле запустим еще один цикл для итерации по полученной сигнатуре с определенным смещением. Сигнатуры типов файлов, которые представлены в моем словаре имею либо нулевое, либо смещение 4 байта. С учетом пробелов, это будет 12 символов. И дальше сравниваем сигнатуру из словаря с текущим куском байт, со смещением имеющим длину текущей сигнатуры. Если сигнатура найдена, возвращаем сообщение с именем файла и его типом. Если же сигнатура не найдена — возвращаем сообщение о неизвестной сигнатуре.

 for hex_ch in signature: for i in [0, 12]: if hex_ch == str(hex_bytes[i:len(hex_ch) + i]): return f'Файл: "" имеет сигнатуру: "" файла' continue return "Неизвестная сигнатура"

Ну и функция main, в которой получаем путь к файлу и вызываем функцию read_file, в которую передаем полученный путь предварительно проверенный на существование.

def main(): path = input("Введите путь к файлу: ") if not Path(path).exists(): print("Файла не существует!") sys.exit(0) print(read_file(path)) if __name__ == "__main__": main()

Полный код скрипта

import sys from pathlib import Path signature = < "66 74 79 70 33 67": "3gp, 3gp2", "FF D8 FF E0": "jpg", "49 46 00 01": "jpeg", "89 50 4E 47 0D 0A 1A 0A": "png", "25 50 44 46 2D": "pdf", "4F 67 67 53": "ogg, oga, ogv", "52 49 46 46": "wav", "57 41 56 45": "wav", "41 56 49 20": "avi", "FF FB": "mp3", "FF F3": "mp3", "FF F2": "mp3", "49 44 33": "mp3", "66 4C 61 43": "flac", "1A 45 DF A3": "mkv, mka, mks, mk3d, webm", "47": "ts, tsv, tsa", "00 00 01 BA": "mpg, mpeg", "00 00 01 B3": "mpg, mpeg", "66 74 79 70 4D 53 4E 56": "mp4", "66 74 79 70 69 73 6F 6D": "mp4", "66 74 79 70 6D 70 34 32": "m4v" >def read_file(path: str) -> str: """ Получение сигнатуры файла. Итерация по словарю сигнатур и сравнение их с полученной сигнатурой в соответствии со смещением. :param path: Путь к файлу. :return: Строка, тип файла или сообщение о неизвестной сигнатуре. """ with open(path, 'rb') as f: file = f.read(256) hex_bytes = " ".join([''.format(byte) for byte in file]) for hex_ch in signature: for i in [0, 12]: if hex_ch == str(hex_bytes[i:len(hex_ch) + i]): return f'Файл: "" имеет сигнатуру: "" файла' continue return "Неизвестная сигнатура" def main(): path = input("Введите путь к файлу: ") if not Path(path).exists(): print("Файла не существует!") sys.exit(0) print(read_file(path)) if __name__ == "__main__": main()

Для теста я выбрал файл mp3 без расширения и файл mp4 скачанный с YouTube. И вот что у меня получилось:

02.png

03.png

04.png

Как видно из вышеприведенных примеров, определение файла по его сигнатуре работает успешно. Однако, для использования в серьезных проектах, думаю, что словарь со списком сигнатур следует несколько видоизменить и добавить группу сигнатур, которая будет определятся смещением, чтобы при итерации считывать смещение из самого словаря.

А на этом пожалуй все.

Спасибо за внимание. Надеюсь, что данная информация будет вам полезна

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *