2

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?

Chris Marasti-Georg
  • 34,091
  • 15
  • 92
  • 137
  • The directory the app is started from is loaded as the current working directory. It is perfectly allowable to change this and if an obscure part of code does this then you will end up with said behaviour. Turn relative paths into absolute ones. – workmad3 Oct 01 '08 at 15:34

6 Answers6

7

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
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 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 Oct 01 '08 at 16:20
5

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
  • 23,359
  • 7
  • 71
  • 108
  • 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 Oct 01 '08 at 15:34
  • 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 Oct 01 '08 at 15:37
  • Though, erm, I guess you should strip out the exe file name of the location before passing it to Path.Combine :) – OregonGhost Oct 01 '08 at 15:37
2

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
  • 61,417
  • 20
  • 137
  • 189
1

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
  • 9,695
  • 6
  • 32
  • 43
1

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
  • 14,597
  • 18
  • 87
  • 141
0

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
  • 4,530
  • 21
  • 22