[R] Trailing path separators and dirname(), file.exists(), file.path()

Dave Gerrard
Fri, 11 Nov 2016 10:51:20 -0000

I've found something irritating in the behaviour of dirname() and
subsequent interactions with file.path() and file.exists().  The problem is
how it and they deal with trailing path separators.   It seems the code is
correct to specification but I think it could be better. Part of the
problem is restricted to Windows and this is alluded to in the docs but the
implications are not fully explicit. Providing a path with a trailing path
separator to dirname() causes the final directory to be removed.


In Linux (R 3.3.1)

> file.path("","p1","p2","p3")
[1] "/p1/p2/p3"
>
dirname(file.path("","p1","p2","p3"))
# p3 is treated as a filename,
not a directory in the path - fine.
[1] "/p1/p2"
>
file.path("","p1","p2","p3","/")
# not the "//" by file.path"
[1] "/p1/p2/p3//"
>
dirname(file.path("","p1","p2","p3","/"))
# p3 is now treated as a
directory  - fine.
[1] "/p1/p2/p3"
> dirname("/p1/p2/p3/") # but when I give a path with no file at
the end.
What I consider a directory, is chopped off as a final filename.
[1] "/p1/p2"



In Windows (R 3.3.1)

>  file.path("","p1","p2","p3") # as
per linux
[1] "/p1/p2/p3"
>
dirname(file.path("","p1","p2","p3"))  #
as per linux
[1] "/p1/p2"
>
file.path("","p1","p2","p3","/")
# N.B. no second "/"
[1] "/p1/p2/p3/"
>
dirname(file.path("","p1","p2","p3","/"))
# last 'directory' lost
[1] "/p1/p2"
> dirname("/p1/p2/p3/") # last 'directory' lost
[1] "/p1/p2"


This is a problem for me when testing for the existence of directories
(e.g. have I already made an output directory for this analysis)

In Windows (R 3.3.1)

> dir.create("temp")
> file.exists("temp")
[1] TRUE
> file.exists("temp/") # R on windows not recognising and removing
the
trailing path separator.
[1] FALSE
> file.exists(dirname("temp/"))
[1] TRUE
> dirname("temp/")
[1] "."


On Linux, I can use a trailing separator, but I still shouldn't use
dirname() :-

> dir.create("temp")
> file.exists("temp")
[1] TRUE
> file.exists("temp/")
[1] TRUE
> file.exists(dirname("temp/"))       # false positive
[1] TRUE
> dirname("temp/")                        # what it is really
testing for.
[1] "."



Does anyone else feel this is not as good as it should be?


I don't know how old this behavious is. I've only tested R 3.3.1 but the
docs for file.path() suggest there may have been some recent tinkering:-

"Trailing path separators are invalid for Windows file paths apart from ?/?
and ?d:/? (although some functions/utilities do accept them), so as from R
3.1.0 a trailing / or \ is removed."

Dave Gerrard

	[[alternative HTML version deleted]]