Open file in a relative location in Python [duplicate]
Asked Answered
B

14

216

Suppose my python code is executed a directory called main and the application needs to access main/2091/data.txt.

how should I use open(location)? what should the parameter location be?

I found that below simple code will work.. does it have any disadvantages?

file = "\2091\sample.txt"
path = os.getcwd()+file
fp = open(path, 'r+');
Bourke answered 23/8, 2011 at 18:24 Comment(4)
You're using unescaped backslashes. That's one disadvantage.Lyly
Several disadvantages. 1) As per @orip, use forward slashes for paths, even on windows. Your string won't work. Or use raw strings like r"\2091\sample.txt". Or escape them like "\\2091\\sample.txt" (but that is annoying). Also, 2) you are using getcwd() which is the path you were in when you execute the script. I thought you wanted relative to the script location (but now am wondering). And 3), always use os.path functions for manipulating paths. Your path joining line should be os.path.join(os.getcwd(), file) 4) the ; is pointlessTarratarradiddle
And for good measure... 5) use context guards to keep it clean and avoid forgetting to close your file: with open(path, 'r+') as fp:. See here for the best explanation of with statements I've seen.Tarratarradiddle
beside the necessary care on slashes, as just indicated, there is the function os.path.abspath to get easly the full path of the relative path to open. final statement looks like this: os.path.abspath('./2091/sample.txt')Lucrative
T
281

With this type of thing you need to be careful what your actual working directory is. For example, you may not run the script from the directory the file is in. In this case, you can't just use a relative path by itself.

If you are sure the file you want is in a subdirectory beneath where the script is actually located, you can use __file__ to help you out here. __file__ is the full path to where the script you are running is located.

So you can fiddle with something like this:

import os
script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in
rel_path = "2091/data.txt"
abs_file_path = os.path.join(script_dir, rel_path)
Tarratarradiddle answered 23/8, 2011 at 18:59 Comment(6)
I found that below simple code will work..does it have any disadvantages ? <pre> file="\sample.txt" path=os.getcwd()+str(loc)+file fp=open(path,'r+');<code>Bourke
@Arash The disadvantage to that is the cwd (current working directory) can be anything, and won't necessarily be where your script is located.Electrolyse
__file__ is a relative path (at least on my setup, for some reason), and you need to call os.path.abspath(__file__) first. osx/homebrew 2.7Electrolyse
os.path.dirname(file) is not working for me in Python 2.7. It is showing NameError: name '__file__' is not definedFleur
@Fleur I think you are trying it in the console. Try it in a *.py file.Martres
shouldn't you use os.path.join for 2091/data.txt ? woudn't it cause problems in window? \` & /`Anderlecht
C
55

This code works fine:

import os

def read_file(file_name):
    file_handle = open(file_name)
    print file_handle.read()
    file_handle.close()

file_dir = os.path.dirname(os.path.realpath('__file__'))
print file_dir

#For accessing the file in the same folder
file_name = "same.txt"
read_file(file_name)

#For accessing the file in a folder contained in the current folder
file_name = os.path.join(file_dir, 'Folder1.1/same.txt')
read_file(file_name)

#For accessing the file in the parent folder of the current folder
file_name = os.path.join(file_dir, '../same.txt')
read_file(file_name)

#For accessing the file inside a sibling folder.
file_name = os.path.join(file_dir, '../Folder2/same.txt')
file_name = os.path.abspath(os.path.realpath(file_name))
print file_name
read_file(file_name)
Coset answered 6/10, 2015 at 15:6 Comment(5)
For me accessing the file in the parent folder of the current folder did not worked..the .. is added as string..Outgroup
Did not work on Windows. Path to file is correct but Python states "file not found" and shows the path with \\ separators.Derbent
in Ubuntu and python3, I had to take the quotes from '__file__' so it became: fileDir = os.path.dirname(os.path.realpath(__file__))Portion
to avoid using / or \ you can os.path.join(path,'folderA','file.txt')Dosia
It's __file__ not '__file__'.Salmi
N
36

I created an account just so I could clarify a discrepancy I think I found in Russ's original response.

For reference, his original answer was:

import os
script_dir = os.path.dirname(__file__)
rel_path = "2091/data.txt"
abs_file_path = os.path.join(script_dir, rel_path)

This is a great answer because it is trying to dynamically creates an absolute system path to the desired file.

Cory Mawhorter noticed that __file__ is a relative path (it is as well on my system) and suggested using os.path.abspath(__file__). os.path.abspath, however, returns the absolute path of your current script (i.e. /path/to/dir/foobar.py)

To use this method (and how I eventually got it working) you have to remove the script name from the end of the path:

import os
script_path = os.path.abspath(__file__) # i.e. /path/to/dir/foobar.py
script_dir = os.path.split(script_path)[0] #i.e. /path/to/dir/
rel_path = "2091/data.txt"
abs_file_path = os.path.join(script_dir, rel_path)

The resulting abs_file_path (in this example) becomes: /path/to/dir/2091/data.txt

Nib answered 1/9, 2014 at 20:54 Comment(2)
You could even combine both approaches for the simpler os.path.dirname(os.path.abspath(__file__))Jasik
@LukeTaylor Indeed that would be better than trying to replicate the os.path.dirname functionality yourself as I did in my answer last year.Nib
O
29

It depends on what operating system you're using. If you want a solution that is compatible with both Windows and *nix something like:

from os import path

file_path = path.relpath("2091/data.txt")
with open(file_path) as f:
    <do stuff>

should work fine.

The path module is able to format a path for whatever operating system it's running on. Also, python handles relative paths just fine, so long as you have correct permissions.

Edit:

As mentioned by kindall in the comments, python can convert between unix-style and windows-style paths anyway, so even simpler code will work:

with open("2091/data/txt") as f:
    <do stuff>

That being said, the path module still has some useful functions.

Olympium answered 23/8, 2011 at 18:30 Comment(5)
relpath() converts a pathname to a relative path. Since it's already a relative path, it will do nothing.Shiller
It will convert it from a unix-style path to windows-style path if appropriate. Is there another function in the os.path module that would be a better choice?Olympium
Windows will already work fine with a UNIX-style path. At least the NT-based series will (2000, XP, Vista, 7). No conversion is necessary.Shiller
This answer is not quite correct and will cause problems. Relative paths are by default relative to the current working directory (path the script was executed from), and NOT the actual script location. You need to use __file__. Please see my answer.Tarratarradiddle
Did the author of this answer confuse os.path.relpath with os.path.abspath?Raveaux
P
23

I spend a lot time to discover why my code could not find my file running Python 3 on the Windows system. So I added . before / and everything worked fine:

import os

script_dir = os.path.dirname(__file__)
file_path = os.path.join(script_dir, './output03.txt')
print(file_path)
fptr = open(file_path, 'w')
Proceeds answered 1/9, 2018 at 22:14 Comment(4)
Better: file_path = os.path.join(script_dir, 'output03.txt')Halfcaste
I tried on Windows OS that but I didn't have success.Adena
Interesting - can you print script_dir? Then turn it to absolute path as in script_dir = os.path.abspath(os.path.dirname(__file__))Halfcaste
I will try that, if I succeed, I will change the answer.Adena
A
16

Try this:

from pathlib import Path

data_folder = Path("/relative/path")
file_to_open = data_folder / "file.pdf"

f = open(file_to_open)

print(f.read())

Python 3.4 introduced a new standard library for dealing with files and paths called pathlib. It works for me!

Adoration answered 3/8, 2018 at 10:57 Comment(1)
please use with data_folder.open() as f insteadProgressionist
N
7

Code:

import os
script_path = os.path.abspath(__file__) 
path_list = script_path.split(os.sep)
script_directory = path_list[0:len(path_list)-1]
rel_path = "main/2091/data.txt"
path = "/".join(script_directory) + "/" + rel_path

Explanation:

Import library:

import os

Use __file__ to attain the current script's path:

script_path = os.path.abspath(__file__)

Separates the script path into multiple items:

path_list = script_path.split(os.sep)

Remove the last item in the list (the actual script file):

script_directory = path_list[0:len(path_list)-1]

Add the relative file's path:

rel_path = "main/2091/data.txt

Join the list items, and addition the relative path's file:

path = "/".join(script_directory) + "/" + rel_path

Now you are set to do whatever you want with the file, such as, for example:

file = open(path)
Nerine answered 22/12, 2018 at 22:9 Comment(1)
Instead of path = "/".join(script_directory) + "/" + rel_path you should use the os module as in path = os.path.join(script_directory, rel_path). Instead of manually parsing the path you should be using script_path = os.path.dirname(__file__)Halfcaste
E
4
import os
def file_path(relative_path):
    dir = os.path.dirname(os.path.abspath(__file__))
    split_path = relative_path.split("/")
    new_path = os.path.join(dir, *split_path)
    return new_path

with open(file_path("2091/data.txt"), "w") as f:
    f.write("Powerful you have become.")
Electrodeposit answered 8/12, 2019 at 15:2 Comment(0)
C
3

If the file is in your parent folder, eg. follower.txt, you can simply use open('../follower.txt', 'r').read()

Catadromous answered 30/12, 2017 at 15:4 Comment(0)
C
3

Get the path of the parent folder, then os.join your relative files to the end.

# get parent folder with `os.path`
import os.path

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# now use BASE_DIR to get a file relative to the current script
os.path.join(BASE_DIR, "config.yaml")

The same thing with pathlib:

# get parent folder with `pathlib`'s Path
from pathlib import Path

BASE_DIR = Path(__file__).absolute().parent

# now use BASE_DIR to get a file relative to the current script
BASE_DIR / "config.yaml"
Clackmannan answered 12/6, 2021 at 11:7 Comment(2)
all upper case names should be reserved for constantsProgressionist
In this case, wouldn't BASE_DIR be a constant? The parent folder of the script being run won't change during runtime.Clackmannan
S
2

Python just passes the filename you give it to the operating system, which opens it. If your operating system supports relative paths like main/2091/data.txt (hint: it does), then that will work fine.

You may find that the easiest way to answer a question like this is to try it and see what happens.

Shiller answered 23/8, 2011 at 18:31 Comment(3)
Not true... the working directory inside a script is the location you ran the script from, not the location of the script. If you run the script from elsewhere (maybe the script is in your system path) the relative path to the subdirectory will not work. Please see my answer on how to get around this.Tarratarradiddle
@Tarratarradiddle - the OP's example uses getcwd(). I read the original description as "relative to where I run the script, regardless of where the code sits".Lyly
@Lyly - the OP added the getcwd() call 3 hrs after the question. No matter... moving on. :)Tarratarradiddle
T
2

Not sure if this work everywhere.

I'm using ipython in ubuntu.

If you want to read file in current folder's sub-directory:

/current-folder/sub-directory/data.csv

your script is in current-folder simply try this:

import pandas as pd
path = './sub-directory/data.csv'
pd.read_csv(path)
Turco answered 21/8, 2014 at 2:20 Comment(0)
P
2

In Python 3.4 (PEP 428) the pathlib was introduced, allowing you to work with files in an object oriented fashion:

from pathlib import Path

working_directory = Path(os.getcwd())
path = working_directory / "2091" / "sample.txt"
with path.open('r+') as fp:
    # do magic

The with keyword will also ensure that your resources get closed properly, even if you get something goes wrong (like an unhandled Exception, sigint or similar)

Progressionist answered 13/12, 2021 at 20:14 Comment(0)
M
1

When I was a beginner I found these descriptions a bit intimidating. As at first I would try For Windows

f= open('C:\Users\chidu\Desktop\Skipper New\Special_Note.txt','w+')
print(f) 

and this would raise an syntax error. I used get confused alot. Then after some surfing across google. found why the error occurred. Writing this for beginners

It's because for path to be read in Unicode you simple add a \ when starting file path

f= open('C:\\Users\chidu\Desktop\Skipper New\Special_Note.txt','w+')
print(f)

And now it works just add \ before starting the directory.

Mattie answered 24/6, 2020 at 19:18 Comment(1)
Backslashes are escape characters for several characters. If you happen to encounter \t like for example \top\directory, than '\t' is interpreted as a tab-character and your 'trick' fails. The best option is to use the raw string format r'C:\Users\chidu\Desktop\Skipper New\Special_Note.txt' which does not try to 'escape' characters.Righteous

© 2022 - 2024 — McMap. All rights reserved.