My winform app uses xml files to store data, where should I store them so Vista users can write to them?
Thanks
Do you want your application data to be user-specific? Then you should consider putting it in C:\Users\%username%\%appname%\...
Otherwise, @Mike_G's not wrong to suggest simply putting it in the same directory as your app.
EDIT: Except, as your Comment there notes, C:\Program Files\...
isn't writable, in which case I would probably consider making it user-specific (with good defaults) in all cases, unless I had a good reason to want it consolidated in a single place. If that were the case, I would make it part of the app's configuration and let the user determine where they want (and can) save the data.
Environment.GetFolderPath should tell you where Windows would like you to store things.
For user-specific data,
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
typically returns C:\Users\%user%\AppData\Roaming
For common data,
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
typically returns C:\ProgramData.
This will also do the right thing under older flavours of Windows; XP will typically return C:\Documents and Settings\%user%\Application Data and C:\Documents and Settings\All Users\Application Data.
Try using IsolatedStorage from the .Net Framework. It will do this work for you.
The Framework can manage those locations for you, instead of managing drives and folders and files and such. It's purpose is to have an area where you don't have to worry about user permissions.
The below code sequence is straight out of MSDN, but shows exactly how you would use these files.
using System;
using System.IO;
using System.IO.IsolatedStorage;
public class ReadingAndWritingToFiles{
public static int Main(){
// Get an isolated store for this assembly and put it into an
// IsolatedStoreFile object.
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
// This code checks to see if the file already exists.
string[] fileNames = isoStore.GetFileNames("TestStore.txt");
foreach (string file in fileNames){
if(file == "TestStore.txt"){
Console.WriteLine("The file already exists!");
Console.WriteLine("Type \"StoreAdm /REMOVE\" at the command line to delete all Isolated Storage for this user.");
// Exit the program.
return 0;
}
}
writeToFile(isoStore);
Console.WriteLine("The file \"TestStore.txt\" contains:");
// Call the readFromFile and write the returned string to the
//console.
Console.WriteLine(readFromFile(isoStore));
// Exit the program.
return 0;
}// End of main.
// This method writes "Hello Isolated Storage" to the file.
private static void writeToFile(IsolatedStorageFile isoStore){
// Declare a new StreamWriter.
StreamWriter writer = null;
// Assign the writer to the store and the file TestStore.
writer = new StreamWriter(new IsolatedStorageFileStream("TestStore.txt", FileMode.CreateNew,isoStore));
// Have the writer write "Hello Isolated Storage" to the store.
writer.WriteLine("Hello Isolated Storage");
writer.Close();
Console.WriteLine("You have written to the file.");
}// End of writeToFile.
// This method reads the first line in the "TestStore.txt" file.
public static String readFromFile(IsolatedStorageFile isoStore){
// This code opens the TestStore.txt file and reads the string.
StreamReader reader = new StreamReader(new IsolatedStorageFileStream("TestStore.txt", FileMode.Open,isoStore));
// Read a line from the file and add it to sb.
String sb = reader.ReadLine();
// Close the reader.
reader.Close();
// Return the string.
return sb.ToString();
}// End of readFromFile.
}
If the data is for all users, then you could try using the "Shared Documents" area. On XP, this is located at C:\Documents and Settings\All Users\Documents. I'm not sure about Vista, but it's likely in C:\Users instead.
why not in the applications directory (the same one the app is installed in)?
Use the Environment.GetFolderPath to get the most appropriate folder in an OS-independent manner.
In particular, you need one of the following SpecialFolder values:
ApplicationData
- if the files are roaming, per-user and are for the application use only and don't represent documents the user might care about.LocalApplicationData
- if the files are non-roaming, per-user and are for the application use only and don't represent documents the user might care about.CommonApplicationData
- if the files are roaming, common for all user and are for the application use only and don't represent documents the user might care about. NOTE: On Vista this maps to C:\ProgramData
, which is by default read-only for regular users (due to the fact that changing files in there might affect behavior of programs used by admins). You can either explicitly change the permissions on your app subfolder, or choose one of the other options.MyDocuments
- if the files are per-user and represent documents.Note that there's no SpecialFolder
enum value like CommonDocuments
that would represent machine-wide document store, even though there is a folder intended to serve like one (C:\Documents and Settings\All Users\Documents
on XP and C:\Users\Public\Documents
on Vista). You will have to find the OS version yourself and choose the appropriate folder if you want to write to these locations.
Internally Environment.GetFolderPath
uses the Win32 API SHGetFolderPath. The enumeration used by SHGetFolderPath
gives you the well-known locations for several other special folders (including Common Documents). You might use directly SHGetFolderPath
; you can find it's p/invoke definition and the corresponding CSIDL enum definition on PInvoke.net.
You can also use the IsolatedStorage. However, it is non-roamable, per-user, with limited quota and is not easily accessible to the user from Windows Explorer. As such, it is really a medium/low-trust equivalent to SpecialFolder.ApplicationData
.