views:

634

answers:

6

I have a C# application that includes the following code:

string file = "relativePath.txt";

//Time elapses...

string contents = File.ReadAllText(file);

This works fine, most of the time. The file is read relative to the directory that the app was started from. However, in testing, it has been found that if left alone for about 5 hours, the app will throw a FileNotFoundException saying that "C:\Documents and Settings\Adminstrator\relativePath.txt" could not be found. If the action that reads the file is run right away though, the file is read from the proper location, which we'll call "C:\foo\relativePath.txt"

What gives? And, what is the best fix? Resolving the file against Assembly.GetEntryAssembly().Location?

+4  A: 

If the file is always in a path relative to the executable assembly, then yes, use Assembly.Location. I mostly use Assembly.GetExecutingAssembly if applicable though instead of Assembly.GetEntryAssembly. This means that if you're accessing the file from a DLL, the path will be relative to the DLL path.

OregonGhost
I was originally using GetExecutingAssembly, but as I thought about it, I wanted this to be relative to the path of the executable, since it is in that executable's config file that the path will be defined. I would also only resolve it if the path is not absolute to begin with...
Chris Marasti-Georg
You can just use Path.Combine(Assembly[whatever].Location, relativePath). If the relativePath is absolute, Path.Combine will return that absolute path and discard the first parameter.
OregonGhost
Though, erm, I guess you should strip out the exe file name of the location before passing it to Path.Combine :)
OregonGhost
+1  A: 

I think the lesson should be don't rely on relative paths, they are prone to error. The current directory can be changed by any number of things in your running process like file dialogs (though there is a property to prevent them changing it), so you can never really guarantee where a relative path will lead at all times unless you use the relative path to generate a fixed one from a known path like Application.StartupPath (though beware when launching from Visual Studio) or some other known path.

Using relative paths will make your code difficult to maintain as a change in a totally unrelated part of your project could cause another part to fail.

Jeff Yates
+5  A: 

One spooky place that can change your path is the OpenFileDialog. As a user navigates between folders it's changing your application directory to the one currently being looked at. If the user closes the dialog in a different directory then you will be stuck in that directory.

It has a property called RestoreDirectory which causes the dialog to reset the path. But I believe the default is "false".

JaredPar
One way would be to store the app root path somewhere (as part of the installation for example) and then use app_root_path\SomePath throughout your code.
Gishu
A: 

If you use an openfiledialog and the remember path property (not sure about the exact name) is true then it will change your current directory I think.

Sijin
+1  A: 

In System.Environment, you have the SpecialFolder enum, that will help you get standard relative paths.

This way at least, the path is gotten internally and handed back to you, so hopefully if the system is changing the path somehow, the code will just handle it.

MagicKat
+1  A: 

if you do somehting like

> cd c:\folder 1

c:\folder 1 > ../folder 2/theApplication.exe

The current working directory of the applicaiton will be c:\folder 1 .

Here is an example program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CWD {
    class Program {
     static void Main (string[] args) {
      Console.WriteLine(Application.StartupPath);
     }
    }
}

Build this in visualstudio then open a command prompt in the debug/bin directory and do

bin/debug > CWD.exe

then do

bin/debug > cd ../../ > bin/debug/CWD.exe

you will see the difference in the startup path.

In relation to the original question... "if left alone for about 5 hours, the app will throw a FileNotFoundException"

Once the application is running, only moving, or removing that file from the expected location should cause this error.

greg

Greg B