Click here to Skip to main content
11,645,033 members (63,043 online)
Click here to Skip to main content

Tagged as

Where should I store my data?

, 20 Apr 2012 CPOL 20.9K 25
Rate this:
Please Sign up or sign in to vote.
There is a common theme in development: storing data files in the application folder. This is bad, and wrong, and should be stamped on!

Introduction

Recently, I have been answering questions regarding storing data files, and the problems that result from choosing the wrong location. So, where should you store data? And how do you get the path? 

Background 

Windows has a number of places that are free for data storage and which will not cause "Access Denied" exceptions  when you try to write to them - unfortunately, the default directory is not one of them. If you use code such as:

File.WriteAllText("myFile.txt", "Hello World"); 

Then the system will try to write it to the current folder - which is normally the application executable directory, which in release programs is (or should be) under the "Program Files" or "Program Files(x86)" folder. It is not a good idea to write anything here - you may get an exception, or the user may not be able to locate it with Windows Explorer, or worse: it may well not be on a regular backup schedule folder list. 

If you want to write data to a sensible location, Windows provides three Data folders:

User Data
Roaming User Data
All User Data

And these are accessible in C# via the Environment.SpecialFolder enumeration:

Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)

However it is not a good idea to use these directly, as they are not specific to your application, but general to all.

One way to get an appropriate folder is just to use the Application Properties:

Application.UserAppDataPath
Application.LocalUserAppDataPath
Application.CommonAppDataPath

But I am not in favour of this as the path is specific to your application, and the version number of the assembly: If you issue a new version of your EXE, then it may not be able to find the data that worked with a previous version.

Instead, I prefer to use the Application GUID and the Environment.SpecialFolder enumeration.

When you create an assembly with Visual Studio, it is assigned a Guid value, which does not change during the life of that assembly - be it an EXE file or a Class Library. You can use that Guid to absolutely identify your application, and thus it's data - there is a very, very small chance of any two applications being given the same GUID - which is not the case for application names! How many companies do you think have wanted to call an application "Word", or "Paint"?

The table at the bottom shows the problem with using the Application Properties too blindly.

The code

Include the following in your application data storage class, or in an appropriate Class Library.

/// <summary>
/// Get the Application Guid
/// </summary>
public static Guid AppGuid
    {
    get
        {
        Assembly asm = Assembly.GetEntryAssembly();
        object[] attr = (asm.GetCustomAttributes(typeof(GuidAttribute), true));
        return new Guid((attr[0] as GuidAttribute).Value);
        }
    }
/// <summary>
/// Get the current assembly Guid.
/// <remarks>
/// Note that the Assembly Guid is not necessarily the same as the
/// Application Guid - if this code is in a DLL, the Assembly Guid
/// will be the Guid for the DLL, not the active EXE file.
/// </remarks>
/// </summary>
public static Guid AssemblyGuid
    {
    get
        {
        Assembly asm = Assembly.GetExecutingAssembly();
        object[] attr = (asm.GetCustomAttributes(typeof(GuidAttribute), true));
        return new Guid((attr[0] as GuidAttribute).Value);
        }
    }
/// <summary>
/// Get the current user data folder
/// </summary>
public static string UserDataFolder
    {
    get
        {
        Guid appGuid = AppGuid;
        string folderBase = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        string dir = string.Format(@"{0}\{1}\", folderBase, appGuid.ToString("B").ToUpper());
        return CheckDir(dir);
        }
    }
/// <summary>
/// Get the current user roaming data folder
/// </summary>
public static string UserRoamingDataFolder
    {
    get
        {
        Guid appGuid = AppGuid;
        string folderBase = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
        string dir = string.Format(@"{0}\{1}\", folderBase, appGuid.ToString("B").ToUpper());
        return CheckDir(dir);
        }
    }
/// <summary>
/// Get all users data folder
/// </summary>
public static string AllUsersDataFolder
    {
    get
        {
        Guid appGuid = AppGuid;
        string folderBase = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
        string dir = string.Format(@"{0}\{1}\", folderBase, appGuid.ToString("B").ToUpper());
        return CheckDir(dir);
        }
    }
/// <summary>
/// Check the specified folder, and create if it doesn't exist.
/// </summary>
/// <param name="dir"></param>
/// <returns></returns>
private static string CheckDir(string dir)
    {
    if (!Directory.Exists(dir))
        {
        Directory.CreateDirectory(dir);
        }
    return dir;
    }

Do note that if you include this code in a Class Library, then AppGuid will not be the same as the AssemblyGuid - a Class Library is a separate Assembly, and has it's own Guid. This can be useful, if you want to store information which is to be used by multiple applications - User Login details for example if these are not related to the Windows Login details.

Sample paths generated

Common.AppGuid                     158aa00d-332e-440b-9c2c-47e2fc11c078
Common.AssemblyGuid                8d14ff7e-8d39-4163-a1ba-4fae4a5c361d
Common.UserDataFolder              C:\Users\griff\AppData\Local\{158AA00D-332E-440B-9C2C-47E2FC11C078}\
Application.UserAppDataPath        C:\Users\griff\AppData\Roaming\SetShares\SetShares\1.0.0.0
Common.UserRoamingDataFolder       C:\Users\griff\AppData\Roaming\{158AA00D-332E-440B-9C2C-47E2FC11C078}\
Application.LocalUserAppDataPath   C:\Users\griff\AppData\Local\SetShares\SetShares\1.0.0.0
Common.AllUsersDataFolder          C:\ProgramData\{158AA00D-332E-440B-9C2C-47E2FC11C078}\
Application.CommonAppDataPath      C:\ProgramData\SetShares\SetShares\1.0.0.0

History

Original version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

OriginalGriff
CEO
Wales Wales
Born at an early age, he grew older. At the same time, his hair grew longer, and was tied up behind his head.
Has problems spelling the word "the".
Invented the portable cat-flap.
Currently, has not died yet. Or has he?

You may also be interested in...

Comments and Discussions

 
QuestionSuperb! Pin
Mark@Metro23-Mar-15 17:56
memberMark@Metro23-Mar-15 17:56 
Question[My vote of 2] Static gettters Pin
Истинското Ми-Име26-Jun-14 12:46
memberИстинското Ми-Име26-Jun-14 12:46 
AnswerRe: [My vote of 2] Static gettters Pin
PIEBALDconsult26-Jun-14 12:55
memberPIEBALDconsult26-Jun-14 12:55 
SuggestionChecking Directory exists Pin
PabloInNz10-Jun-14 18:07
memberPabloInNz10-Jun-14 18:07 
GeneralNice work ! Pin
Member 1046110810-Jun-14 16:27
memberMember 1046110810-Jun-14 16:27 
GeneralMy vote of 5 Pin
Maciej Los3-May-14 3:18
mvpMaciej Los3-May-14 3:18 
Questionabout the guid Pin
zebra8811-Jun-13 8:25
memberzebra8811-Jun-13 8:25 
AnswerRe: about the guid Pin
OriginalGriff11-Jun-13 8:34
protectorOriginalGriff11-Jun-13 8:34 
GeneralRe: about the guid Pin
zebra8811-Jun-13 8:42
memberzebra8811-Jun-13 8:42 
GeneralMy vote of 5 Pin
Menon Santosh11-Mar-13 2:05
memberMenon Santosh11-Mar-13 2:05 
QuestionSaving in registry Pin
ProgramFOX19-Jan-13 4:54
member ProgramFOX19-Jan-13 4:54 
Hi,

Internet Explorer saves some history in the Windows Registry. When it's a good idea do this, and where to store your data in the Windows Registry?

Thanks.
In some cases, my signature will be longer than my message...
<em style="color:red"> <b>ProgramFOX</b></em>
ProgramFOX


modified 19-Jan-13 11:20am.

AnswerRe: Saving in registry Pin
PIEBALDconsult19-Jan-13 5:11
memberPIEBALDconsult19-Jan-13 5:11 
QuestionWhat about parent of LocalUserAppDataPath Pin
LesF18-Aug-12 16:01
memberLesF18-Aug-12 16:01 
AnswerRe: What about parent of LocalUserAppDataPath Pin
OriginalGriff18-Aug-12 20:12
mvpOriginalGriff18-Aug-12 20:12 
QuestionOk..but Pin
FatCat_Programmer21-Apr-12 4:16
memberFatCat_Programmer21-Apr-12 4:16 
GeneralGood Tip Pin
perilbrain20-Apr-12 10:08
memberperilbrain20-Apr-12 10:08 
GeneralRe: Good Tip Pin
OriginalGriff20-Apr-12 21:43
mvpOriginalGriff20-Apr-12 21:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150731.1 | Last Updated 20 Apr 2012
Article Copyright 2012 by OriginalGriff
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid