Convert a relative path that includes a drive letter to an absolute path for .NET file functions
How can you convert a drive relative path such as D:test.xml
into an absolute path that a function such as XDocument.Load()
will accept. The D drive could have D:\data
as its current working directory, for example, so D:test.xml
would mean D:\data\test.xml
. I've already tried such concoctions as D:.\test.xml
.
Here is the error I get for something like D:te开发者_开发知识库st.xml
:
Invalid URI: A Dos path must be rooted, for example, 'c:\'
You could use GetFullPath
. For example:
// should return "D:\data\test.xml" if the current working dir is "D:\data"
string absolutePath = Path.GetFullPath("D:test.xml");
If the CWD is "D:\Data"
, Path.GetFullPath("D:test.xml")
would indeed return "D:\data\test.xml"
, as it would getting full path directly for "test.xml".
However, if using a different drive letter than the one used for the CWD, the result will not be consistent. For example Path.GetFullPath("C:test.xml")
would return "C:\test.xml".
This is by design. Take a look at http://msdn.microsoft.com/en-us/library/aa365247.aspx#fully_qualified_vs._relative_paths.
If a file name begins with only a disk designator but not the backslash after the colon, it is interpreted as a relative path to the current directory on the drive with the specified letter. Note that the current directory may or may not be the root directory depending on what it was set to during the most recent "change directory" operation on that disk.
[Emphasis added by me]
You should simply use "test.xml" as a relative path and if the current folder is "D:\data", the full path would be resolved to "D:\Data\test.xml". This is also illustrated in the MSDN example for the Load() method: http://msdn.microsoft.com/en-us/library/bb343181.aspx
Please note that "driveLetter:fileName" is not a relative path in .Net. (Please read Update)
You can transform a relative path into a full path using Path.GetFullPath(), but you do not have to do that XDocument.Load(), since it will also accept relative paths.
Update LukeH, thanks for pointing this out! "driveLetter:fileName" are accepted by Path.GetFullPath() and are computed as relative paths to the current directory of the specified drive, as specified here.
The concept of current directory at drive level is inherited from the very old days of the DOS. Not necessarily a feature on which I would build modern applications.
Path.GetFullPath can work. see the doc here
As noted in Luke's answer, the solution is due to how the current working directory is used. As an addendum to that answer here is some background. There is seemingly strange behavior of whether the current working directory is per-drive or not. Here is a blog article from Raymond Chen of Microsoft which explains this.
I had to dig around a bit to find a good link for this, so I've copied the contents as well in case it goes bad.
Why does each drive have its own current directory?
Commenter Dean Earley asks, "Why is there a 'current directory' AND an current drive? Why not merge them?"
Pithy answer: Originally, each drive had its own current directory, but now they don't, but it looks like they do.
Okay, let's unwrap that sentence. You actually know enough to answer the question yourself; you just have to put the pieces together.
Set the wayback machine to DOS 1.0. Each volume was represented by a drive letter. There were no subdirectories. This behavior was carried forward from CP/M.
Programs from the DOS 1.0 era didn't understand subdirectories; they referred to files by just drive letter and file name, for example, B:PROGRAM.LST. Let's fire up the assembler (compilers were for rich people) and assemble a program whose source code is on the A drive, but sending the output to the B drive.
A>asm foo the ".asm" extension on "foo" is implied Assembler version blah blah blah Source File: FOO.ASM Listing file [FOO.LST]: NUL throw away the listing file Object file [FOO.OBJ]: B: send the object file to drive B Since we gave only a drive letter in response to the Object file prompt, the assembler defaults to a file name of FOO.OBJ, resulting in
the object file being generated as B:FOO.OBJ.
Okay, now let's introduce subdirectories into DOS 2.0. Suppose you have want to assemble A:\SRC\FOO.ASM and put the result into B:\OBJ\FOO.OBJ. Here's how you do it:
A> B: B> CD \OBJ B> A: A> CD \SRC A> asm foo Assembler version blah blah blah Source File: FOO.ASM Listing file [FOO.LST]: NUL Object file [FOO.OBJ]: B:
The assembler reads from A:FOO.ASM and writes to B:FOO.OBJ, but since the current directory is tracked on a per-drive basis, the results are A:\SRC\FOO.ASM and B:\OBJ\FOO.OBJ as desired. If the current directory were not tracked on a per-drive basis, then there would be no way to tell the assembler to put its output into a subdirectory. As a result, DOS 1.0 programs were effectively limited to operating on files in the root directory, which means that nobody would put files in subdirectories (because their programs couldn't access them).
From a DOS 1.0 standpoint, changing the current directory on a drive performs the logical equivalent of changing media. "Oh look, a completely different set of files!"
Short attention span.
Remembering the current directory for each drive has been preserved ever since, at least for batch files, although there isn't actually such a concept as a per-drive current directory in Win32. In Win32, all you have is a current directory. The appearance that each drive has its own current directory is a fake-out by cmd.exe, which uses strange environment variables to create the illusion to batch files that each drive has its own current directory.
Dean continues, "Why not merge them? I have to set both the dir and drive if i want a specific working dir."
The answer to the second question is, "They already are merged. It's cmd.exe that tries to pretend that they aren't." And if you want to set the directory and the drive from the command prompt or a batch file, just use the /D option to the CHDIR command:
D:\> CD /D C:\Program Files\Windows NT C:\Program Files\Windows NT> _
(Notice that the CHDIR command lets you omit quotation marks around paths which contain spaces: Since the command takes only one path argument, the lack of quotation marks does not introduce ambiguity.
精彩评论