3

Есть программа, которые берет данные из файла. При запуске программы в консоле требуется ввести имя файла(файл лежит в одной папке с программой). Но при вводе имени выдает ошибку, что такого файла в папке нет. Это решается вводом полного пути до файла (C:\Users....file.dat). Как можно сделать чтобы требовался ввод только имени файла, без пути. (файл лежит в одной папке с программой)

alx
  • 191
  • import sys sys.path.append(здесь путь) – HasmikGaryaka Oct 07 '17 at 09:42
  • @HasmikGaryaka поясните, что этот код делает и как он поможет? – andreymal Oct 07 '17 at 09:48
  • sys.path - список путей, где он ищет файлы – HasmikGaryaka Oct 07 '17 at 09:49
  • Вы явно не понимаете работу с файлами и модулями в питоне. – andreymal Oct 07 '17 at 09:54
  • @andreymal это крайне важный комментарий по теме, спасибо – alx Oct 07 '17 at 09:57
  • Лучше бы дали ответ, если понимаете лучше меняю – HasmikGaryaka Oct 07 '17 at 09:57
  • По теме нужна точная информация, как и откуда запускается скрипт и где этот скрипт вообще лежит. А sys.path к данной проблеме не отностися вообще никак. – andreymal Oct 07 '17 at 10:00
  • Вопрос решился таким образом: import os

    script_dir = os.path.dirname(file) abs_file_path = os.path.join(script_dir, fileName) lines = open(abs_file_path).readlines()

    – alx Oct 07 '17 at 10:02
  • 2
    @HasmikGaryaka, sys.path - список путей, где Python ищет модули, которые можно импортировать через import. Это никак не поможет открыть файл через open. – insolor Oct 07 '17 at 10:10
  • 1
    связанный вопрос: Текущая директория в Python (в секции "Директория со скриптом" упомянуты решения, которые работают и в некоторых крайних случаях таких как: программа в архиве (питон умеет такие модули запускать), программа запущена через symlink (бывает), программа запущена с помощью execfile() (в debugger, IDE, grade tool). – jfs Oct 07 '17 at 15:13
  • так же подходит – alx Oct 08 '17 at 15:07

1 Answers1

1
import sys
import os

вариант с указанием полного пути:

full_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)

или

full_path = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), filename)

вариант с указанием относительного пути:

full_path = os.path.join(os.path.dirname(__file__), filename)

или

full_path = os.path.join(os.path.dirname(sys.argv[0]), filename)

или для Python 3.4+:

from pathlib import Path

full_path = Path(sys.argv[0]).parent.joinpath('my_file.txt')

или

full_path = Path(__file__).parent.joinpath('my_file.txt')

или (спасибо @insolor за подсказку):

full_path = Path(sys.argv[0]).parent / 'my_file.txt'

если нужен полный (абсолютный) путь:

full_path = Path(sys.argv[0]).parent.absolute() / 'my_file.txt'

UPDATE: отличия __file__ и sys.argv[0]:

__file__ - атрибут, указывающий относительный путь к текущему загруженному модулю/скрипту.

sys.argv[0] - относительный путь к главному скрипту, запущенному в OS.

Пример - создадим два файла:

my1.py (модуль который будет импортироваться из основного модуля):

import sys

print('my1.py\t__file__:\t{}'.format(__file__))
print('my1.py\tsys.argv[0]:\t{}'.format(sys.argv[0]))

m2.py (основной скрипт, который мы запускаем):

import sys
import my1

print('my2.py\t__file__:\t{}'.format(__file__))
print('my2.py\tsys.argv[0]:\t{}'.format(sys.argv[0]))

Вывод скрипта m2.py:

my1.py  __file__:       D:\temp\aaa\my1.py
my1.py  sys.argv[0]:    my2.py
my2.py  __file__:       my2.py
my2.py  sys.argv[0]:    my2.py

Вывод: если использовать __file__ в функциях из импортированных модулей, то мы получим имя данного модуля, а не главного скрипта ...

UPDATE 2: бывают случаи когда укзанные выше методы будут работать не совсем правильно - посмотрите следующие связанные вопросы/ответы:

MaxU - stand with Ukraine
  • 149,321
  • 12
  • 59
  • 132
  • Поясните, что этот код делает и как он помог автору? – andreymal Oct 07 '17 at 10:04
  • А также в чём разница между sys.argv[0] и __file__ и зачем вы предлагаете оба – andreymal Oct 07 '17 at 10:07
  • 1
    Вместо joinpath можно сделать Path(sys.argv[0]).parent / 'my_file.txt' – insolor Oct 07 '17 at 10:26
  • @insolor, спасибо, добавил в ответ – MaxU - stand with Ukraine Oct 07 '17 at 10:28
  • @andreymal, добавил описание различий... – MaxU - stand with Ukraine Oct 07 '17 at 10:29
  • это может сломаться для программы из архива, для скрипта, запущенного через symlink, или через execfile(). Посмотрите раздел: Директория со скриптом – jfs Oct 07 '17 at 15:17
  • @jfs, вы имеете ввиду вариант с __file__? – MaxU - stand with Ukraine Oct 07 '17 at 15:19
  • Я упомянул три случая. Если не знаете, то попробуйте и убедитесь в каких именно случаях предложенные вами решения не работают. Упомянутые мной случаи совершенно не обязательно поддерживать, если вы понимаете когда решения могут сломаться. – jfs Oct 07 '17 at 15:22
  • @jfs, спасибо, попробую когда будет больше времени. А что вы имели ввиду под "для программы из архива"? – MaxU - stand with Ukraine Oct 07 '17 at 15:24
  • Питон может импортировать, запускать код из архивов (egg, zip, zipapp) – jfs Oct 07 '17 at 15:34
  • @jfs, хммм, спасибо - про запуск из архивов не знал... – MaxU - stand with Ukraine Oct 07 '17 at 15:36
  • Это говорит, что вы не пытались на ссылку «ваш пакет упакован в архив» нажать в моём ответе :) – jfs Oct 07 '17 at 15:40