Python : How to access file from different directo

2020-02-14 10:32发布

问题:

I have the following project structure

SampleProject
     com
       python
          example
             source
                utils
                   ConfigManager.py
     conf
        constants.cfg

How to access constants.cfg from ConfigManager.py.

I have a limitation

  1. I can not give full path(absolute path) of constants.cfg because if I run in different PC it should work with out any modification
  2. Also if I represent something like below, I can access the file. But I don't want to give back slash every time

    filename = ..\\..\\..\\..\\..\\..\\constants.cfg`
    

Currently I am doing something like this. But this works only when constants.cfg and ConfigManager.py are in same directory

currentDir =  os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
file = open(os.path.join(currentDir,'constants.cfg'))     

回答1:

If conf is a Python package then you could use pkgutil.get_data():

import pkgutil

data = pkgutil.get_data("conf", "constants.cfg")

Or if setuptools is installed – pkg_resources.resource_string():

import pkg_resources

data = pkg_resources.resource_string('conf', 'constants.cfg')

If constants.cfg is not in a package then pass its path as a command-line parameter, or set it in an environment variable e.g., CONFIG_MANAGER_CONSTANTS_PATH, or read from a fixed set of default paths e.g., os.path.expanduser("~/.config/ConfigManager/constants.cfg"). To find a place where to put user data, you could use appdirs module.

You can't use os.getcwd() that returns current working directory if you may run ConfigManager.py from different directories. Relative path "../../..." won't work for the same reason.

If you are certain that the relative position of ConfigManager.py and constants.cfg in the filesystem won't change:

import inspect
import os
import sys

def get_my_path():
    try:
        filename = __file__ # where we were when the module was loaded
    except NameError: # fallback
        filename = inspect.getsourcefile(get_my_path)
    return os.path.realpath(filename)

# path to ConfigManager.py
cm_path = get_my_path()
# go 6 directory levels up
sp_path = reduce(lambda x, f: f(x), [os.path.dirname]*6, cm_path)
constants_path = os.path.join(sp_path, "conf", "constants.cfg")


回答2:

If you had some module in the root of the project tree, say config_loader.py that looked like this:

import os

def get_config_path():
    relative_path = 'conf/constants.cfg'
    current_dir = os.getcwd()
    return os.join(current_dir, relative_path)

And then in ConfigManager.py or any other module that needs the configs:

import config_loader

file_path = config_loader.get_config_path()
config_file = open(file_path)

You could even have your config_loader.py just return the config file.



回答3:

You can use the pathlib package in Python 3.0+

This gets the path to any file contained in the SampleProject folder across different platforms.

from pathlib import Path
def get_file(path):
    """
    returns the absolute path of a file
    :var
    str path
        the file path within the working dir
    :returns
    PureWindowsPath or PurePosixPath object
        type depends on the operating system in use
    """
    def get_project_root() -> Path:
    """Returns project root folder."""
    return Path(__file__).parent.parent

    return get_project_root().joinpath(path)

Then simply call the function with the file_path as an argument:

filePath = get_file('com/python/example/source/utils/configManager.py')

And then the usual procedure:

while open(filePath) as f:
    <DO YOUR THING>