Let's say I have my directory set up like this (as an example):
Main
Scripts
read.f95
Files
file.txt
How would I go about using relative path to read in file.txt in my read.f95 file?
I tried using relative path as
open(10, file='./Files/file.txt') and
open(10, file='../Files/file.txt')
but I am getting a path error on both ways. I have found this question, but the issue there was a too long filename, which is not what I am asking about.
Let's say you have structure like this:
.
|-- code
| |-- relative
| `-- relative.F90
`-- data
`-- data.dat
and you want to run your code from the directory that contains both: code and data. In that case, you can always concatenate location of your current directory and the location of data:
program relative
implicit none
real :: x, y
character (len=255) :: cwd
call getcwd(cwd)
open (10, file = trim(cwd)//'/data/data.dat', status = 'old')
read (10, *) x, y
close(10)
write(*, *) x, y
end program
while data file: data.dat looks following way
0.1 0.2
Once you run it, you will get what you want:
> ./code/relative
0.100000001 0.200000003
However, you have to be extra careful with this approach. It will work only in certain locations - it will work as long as data/data.dat is present. It might be useful in case you submit jobs into batch. Let's say you have no idea where you code will end up (in terms of explicit location). In that case, you can't hardcode it - it makes no sense. So, you have two choices: either you can use some wrapper script and pass location into your code via arguments, or, you can make sure that directory structure looks like you want and you know that everything is in place. In that case, using getcwd makes perfect sense.
Related
How can I read from a parent directory using the OPEN clause? Let's say
OPEN (11,file='../inf/input.dat',form='formatted',status='old')
, which doesn't work. I get:
forrtl: severe (29): file not found, unit 11, file /home/cg/compile/comp/../inf/input.dat
I would like to read from the parent directory just before inf. Is that possible?
Unfortunately there is no unique way to do this, since paths are OS dependent. In order to this in a robust way you might need to define a function that look for the OS while preprocessing (cf. compilation flags e.g. here).
For *nix systems (Unix, including OSX, and Linux) the option you provided should suffice
../
in the path goes to the previous directory.
However in windows there is no way that I know to go in the above directory (I don't have a Windows system with me at the moment).
However you can workaround this limitation with the GetModuleFileName API function. (note that this will not work in the systems above)
CHARACTER*(*) pathname ! full name
INTEGER L ! length
L= GetModuleFileName(NULL,pathname,LEN(pathname))
Fullname will now contain the full path where you run your program, so you can do all sort of string operation you want.
If you want to go above one level
Idx = index(trim(pathname), '/', .True.)
Finds the index of the last '/' character in the pathname (you might need to look for the one before the last).
outfile_path=pathname(:idx)+'/inf/input.dat'
will be now the path you want.
I have been searching for hours but cant find a solution to this as yet. Apologies it is probably really simple.
My program is using CreateDirectory to create a new directory and then set the path to it to receive a number of data files:
if (CreateDirectory(dateTime.c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
SetCurrentDirectory(dateTime.c_str());
}
Once all the data files have been generated I would like to move back up one directory without specifying the absolute path. Something equivalent to cd.. or ../ Does anyone know the best way to do this?
One possible approach is to get the current directory (GetCurrentDirectory) before changing to a new one and once complete, then change back the desired directory; akin to a push/pop.
In the sample I've left out error checking and buffer size requirements for simplicity.
TCHAR resetDir[1024] = {};
GetCurrentDirectory(1024, resetDir);
//... Do some work, change directories etc...
// Reset the directory
SetCurrentDirectory(resetDir);
Side note: the current directory when the process is launched is not necessarily the same as the directory the process image is in (the exe path).
Relative changes can be done with a simple
SetCurrentDirectory(_T(".."));
Although basing the relative from the current directory would also work (and may be preferable);
SetCurrentDirectory((currentDir + _T("\\..")).c_str());
Internally, cd command ends using SetCurrentDirectory. So to get something equivalent to cd.. or cd ../ you can simply use:
cr = ::SetCurrentDirectory("..");
cr should be non zero if it succeded and 0 if it failed. In the latter case use GetLastError to get further information.
So trying to finish a very simple script that has given me a unbelievably hard time. It's supposed to iterate through specified directories and open all text files in them and append them all with the same specified string.
The issue is it's not doing anything to the files at all. Using print to test my logic I've replaced lines 10 and 11 with print f (the write and close functions), and get the following output:
<open file '/Users/russellculver/documents/testfolder/.DS_Store', mode 'a+' at
So I think it is storing the correct files in the f variable for the write function, however I am not familiar with how Mac's handle DS_STORE or the exact role it plays in temporary location tracking.
Here is the actual script:
import os
x = raw_input("Enter the directory path here: ")
def rootdir(x):
for dirpaths, dirnames, files in os.walk(x):
for filename in files:
try:
with open(os.path.join(dirpaths, filename), 'a+') as f:
f.write('new string content')
f.close()
except:
print "Directory empty or unable to open file."
return x
rootdir(x)
And the exact return in Terminal after execution:
Enter the directory path here: /Users/russellculver/documents/testfolder
Exit status: 0
logout
[Process completed]
Yet nothing written to the .txt files in the provided directory.
The way the indentation is in the question, you return from the function right after writing the first file; either of the for-loops never finish. Which is relatively easy to surmise from the fact that you only get one output file printed.
Since you're not doing anything with the result of the rootdir function, I would just remove the return statement entirely.
An aside: there is no need to use f.close() when you open a file with the with statement: it will automatically be closed (even upon an exception). That is in fact what the with statement was introduced for (see the pep on context managers if necessary).
To be complete, here's the function the way I would have (roughly) written it:
def rootdir(x):
for dirpaths, dirnames, files in os.walk(x):
for filename in files:
path = os.path.join(dirpaths, filename)
try:
with open(path, 'a+') as f:
f.write('new string content')
except (IOError, OSError) as exc:
print "Directory empty or unable to open file:", path
(Note that I'm catching only the relevant I/O errors; any other exceptions (though unlikely) will not be caught, as they are likely not to be related to non-existing/unwritable file.)
Return was indented wrong, ending the iteration after a single loop. Wasn't even necessary so was removed entirely.
This script is an improvement on the previously posted one but it is
still giving me an error of "Failed to execute (CADToGeodatabase)"
It is able to iterate through the directories and subdirectories, list
the dwg files, create the geodatabase but not able to populate it with
the feature datasets and feature classes due to the error!. Please help!
import os, os.path, arcpy
from arcpy import env
env.workspace = "J:/2010"
# Set workspace and variables
gdb = r"C:\data\2010.gdb"
arcpy.env.workspace = gdb
# Create a FileGDB for the fds
arcpy.CreateFileGDB_management("C:/data", "2010.gdb")
reference_scale = "1500"
for root, dirs, files in os.walk("J:/2010/"):
for file in files:
if file.endswith('.dwg'):
print "current file is: " + file
outDS = arcpy.ValidateTableName(os.path.splitext("d" +
os.path.basename(file))[0])
arcpy.CADToGeodatabase_conversion(file, gdb, outDS, reference_scale)
The line saying def recursive_file_gen(r"J:\2010"): looks strange to me. I don't think you can put a literal string there. I am surprised that this runs at all. Maybe you meant to do something like def recursive_file_gen(directory=r"J:\2010"): or simply def recursive_file_gen():.
Also, I think the line saying yield os.path.join(root, file) needs to be indented more to be considered inside of the inner for loop.
I don't see specifically what is causing the script to work only in one subdirectory. I will need more details about what is happening.
EDIT: I didn't notice that the recursive_file_gen function is not being used at all. I don't know what is causing the problem. I think someone who is more familiar with arcpy would be more helpful to you.
I am using Qsettings for non gui products to store its settings into xml files. This is written as a library which gets used in C, C++ programs. There will be 1 xml file file for each product. Each product might have more than one sub products and they are written into xml by subproduct grouping as follows -
File: "product1.xml"
<product1>
<subproduct1>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproduct1>
...
<subproductn>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproductn>
</product1>
File: productn.xml
<productn>
<subproduct1>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproduct1>
...
<subproductn>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproductn>
</productn>
The code in one process does the following -
settings = new QSettings("product1.xml", XmlFormat);
settings.setValue("settings1",<value>)
sleep(20);
settings.setValue("settings2", <value2>)
settings.sync();
When the first process goes to sleep, I start another process which does the following -
settings = new QSettings("product1.xml", XmlFormat);
settings.remove("settings1")
settings.setValue("settings3", <value3>)
settings.sync();
I would expect the settings1 to go away from product1.xml file but it still persist in the file - product1.xml at the end of above two process. I am not using QCoreApplication(..) in my settings library. Please point issues if there is anything wrong in the above design.
This is kind of an odd thing that you're doing, but one thing to note is that the sync() call is what actually writes the file to disk. In this case if you want your second process to actually see the changes you've made, then you'll need to call sync() before your second process accesses the file in order to guarantee that it will actually see your modifications. Thus I would try putting a settings.sync() call right before your sleep(20)
Maybe you have to do delete settings; after the sync() to make sure it is not open, then do the writing in the other process?
Does this compile? What implementation of XmlFormat are you using and which OS? There must be some special code in your project for storing / reading to and from Xml - there must be something in this code which works differently from what you expect.