none
Zugriff auf den AppData-Ordner RRS feed

  • Frage

  • Ich würde gern einige Dateien für mein Programm im AppData-Ordner speichern, wofür ich allerdings dort einen Unterordner anlegen müsste.

    Ich habe es folgendermaßen versucht:

    if(!System.IO.Directory.Exists("%appdata%/hamitgerkansprojects"))
          {
            System.IO.Directory.CreateDirectory("%appdata%/hamitgerkansprojects");
          }
    
    Allerdings erstellt das Programm dan im Unterordner bin/Debug der Projeltmappe einen Ordner nit dem Namen "%appdata%" und darin den Ordner "hamitgerkansprojects", was ja nicht korrekt ist, weil ich mit der Verwendung von %appdata% den AppData-Ordner ansprechen wollte.

    Samstag, 2. Juli 2011 12:43

Antworten

  • Hallo Hamit,

    > Ich würde gern einige Dateien für mein Programm im AppData-Ordner speichern, wofür ich allerdings dort einen Unterordner anlegen müsste

    Die Umgebungsvariable %APPDATA% verweist auf das Verzeichnis, in dem programmspezifische Daten für den aktuellen Roamingbenutzer gespeichert werden (
    %LOCALAPPDATA% hingegen auf das lokale Verzeichnis für den aktuellen Benutzer). Auf diese Verzeichnisse verweisen ebenfalls zwei Enumerationselemente: Environment.SpecialForders.ApplicationData bzw. Environment.SpecialForders.LocalApplicationData.

    Wenn Du aber Programmdaten für alle Benutzer Deines Programms speichern möchtest (vom Programm gemeinsam genutzte Daten), dann müßtest Du das neue Verzeichnis eher unter %ALLUSERSPROFILE%, d.h. Environment.SpecialForders.CommonApplicationData erstellen.

    Da die Umgebungsvariablen in vielen Fällen nicht, oder nicht richtig gesetzt sind, empfiehlt sich eher die Verwendung von Environment.SpecialFolders.

    Verwendest Du aber trotzdem Umgebungsvariablen, so mußt Du diese vor der Verwendung expandieren:

    string expandedPath = Environment.ExpandEnvironmentVariables("%appdata%//hamitgerkansprojects");
    System.IO.Directory.CreateDirectory(expandedPath); // wird nur erstellt wenn nicht vorhanden
    

    Generell ist es vorteilhaft wenn man Pfade über System.IO.Path.Combine zusammenfügt, z.B. string myDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolders.ApplicationData), "SubDirectory").

    Vorsicht: Der Name des Verzeichnisses ("hamitgerkansprojects") verstößt logisch gegen einige Grundsätze:

    1. Environment.SpecialFolders.ApplicationData ist für benutzerspezifische Daten der Applikation und nicht des Benutzers vorgesehen ("projects" legt nahe, dass es sich hier um Projekte von Hamit handelt). Diese sollten, wenn es sich um Dokumente handelt, am besten unter SpecialFolders.Personal/MyDocuments + Unterverz. abgelegt werden.

    2. Die Erwähnung des Benutzernamens (Hamit) im Pfadnamen macht bei der Verwendung von Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) nicht viel Sinn, da hier alle Verzeichnisse benutzerbezogen sind und der Name sowieso schon im Pfad steht.

    3. Normalerweise steht unter %appdata% als Verzeichnisname der Name der Anwendung, also z.B. C:\Users\Hamit Gerkan\AppData\Roaming\SuperApp.

    Das Speichern von Daten unter SpecialFolder.ApplicationData hat noch einen weiteren Haken. Wenn Deine Anwendung für alle Benutzer installiert wird, gibt es zur Installationszeit keinen korrekten Speicherort dafür, d.h. eventuelle Daten die Du vorab nach SpecialFolder.ApplicationData schreiben möchtest, dürfen nicht während der Installation sondern erst beim ersten Start der Anwendung nach ApplicationData geschrieben werden.

    Auf die Probleme von ApplicationData bei der Verwendung von ClickOnce-Deployment, gehe ich hier nicht ein.

    Ach ja, fast hätte ich's vergessen: Du kannst natürlich außer über Umgebungsvariable, SpecialFoders-Enumerationselemente auch noch über Application.CommonAppDataPath, Application.LocalUserAppDataPath bzw. Application.UserAppDataPath auf bekannte Verzeichnisse zugreifen. Diese letzten drei Properties haben den Vorteil, dass sie je nachdem ob die Anwendung über ClickOnce oder normal installiert wurde, autom. auf entspr. Verzeichnisse verzweigen (ClickOnce => AppDomain.CurrentDomain.GetData("DataDirectory"), sonst => strukturierter Pfad z.B. Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData))\Firma\Produkt\Version). 

    Dazu kommen unter Windows 7 weitere Möglichkeiten hinzu, auf die ich hier ebenfalls nicht eingehe.
     

    Environment.SpecialFolder Enumeration
    http://msdn.microsoft.com/de-de/library/system.environment.specialfolder.aspx

    Environment.ExpandEnvironmentVariables-Methode:
    http://msdn.microsoft.com/de-de/library/system.environment.expandenvironmentvariables.aspx

    KNOWNFOLDERID (unter Remarks stehen die Standardpfade):
    http://msdn.microsoft.com/en-us/library/dd378457(v=vs.85).aspx

    Technical requirements for the Windows 7 Client Software Logo Program
    http://www.microsoft.com/download/en/details.aspx?id=3859


    Gruß
    Marcel





    Samstag, 2. Juli 2011 15:21
    Moderator
  • Hallo Hamit,

    dazu ist einiges zu sagen. Im Prinzip solltest Du immer erstmal die .NET Methoden für die Pfade benutzen und nicht Dinge wie "%appdata%" obwohl das unter Windows sehr oft funktionieren wird. Ich verzichte mal auf eigene Bemerkungen, da diese Dinge sehr gut in den Artikeln beschrieben sind.

    Also erstmal die wichtigsten Möglichkeiten dazu:

    Pfad für die Anwendungsdaten eines Benutzers:
    [Application.UserAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.userappdatapath.aspx

    Pfad für die Anwendungsdaten eines lokalen Benutzers, der kein Roaming verwendet:
    [Application.LocalUserAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.localuserappdatapath.aspx

    Pfad für die Anwendungsdaten, die von allen Benutzern gemeinsam genutzt werden:
    [Application.CommonAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.commonappdatapath.aspx

    [Environment.SpecialFolder-Enumeration (System)]
    http://msdn.microsoft.com/de-de/library/system.environment.specialfolder.aspx
    CommonApplicationData:
        Das Verzeichnis, das als allgemeines Repository für programmspezifische Daten verwendet
        wird, die von allen Benutzern verwendet werden.
    LocalApplicationData:
        Das Verzeichnis, das als allgemeines Repository für programmspezifische Daten verwendet
        wird, die von einem aktuellen Benutzer verwendet werden, der kein Roamingbenutzer ist.

    Hier detailliertere Möglichkeiten ab Vista und später, mit denen man sehr dedizierte Ordner-Positionen angeben kann:
    [KNOWNFOLDERID (Windows)]
    http://msdn.microsoft.com/en-us/library/dd378457(VS.85).aspx
    [CSIDL (Windows)]
    http://msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx -> CSIDL_APPDATA

    [ReadMe.txt - Shell known folder sample (CSShellKnownFolders)]
    http://code.msdn.microsoft.com/CSShellKnownFolders-94aa920a/sourcecode?fileId=21702&pathId=1556858234

    ========================================

    Trotzdem will ich Dir einmal Deinen Code explizit sauber umwandeln:

     

       string appDataVerzeichnis = Environment.GetEnvironmentVariable("appData");
       string hamitVerzeichnis = Path.Combine(appDataVerzeichnis, "hamitgerkansprojects");
       if(!Directory.Exists(hamitVerzeichnis)) Directory.CreateDirectory(hamitVerzeichnis);
    
    

    Allerdings denke ich, es ist besser die reine .NET Methode zu benutzen, als die Umgebungsvariable - also etwa:

     

       string appDataVerzeichnis = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
       string hamitVerzeichnis = Path.Combine(appDataVerzeichnis, "hamitgerkansprojects");
       if(!Directory.Exists(hamitVerzeichnis)) Directory.CreateDirectory(hamitVerzeichnis);
    

    Wichtig ist auch, dass man im allgemeinen AppData-Verzeichnis normal Erstellerbesitzer-Berechtigungen hat.
    Man sollte diesen Berechtigungstyp "verstehen". Er birgt gewisse Risiken.

     

     


    ciao Frank
    Samstag, 2. Juli 2011 18:34
  • Hallo Hamit,

    schau mal hier, da stehen zwei Lösungswege:

      http://stackoverflow.com/questions/867485/c-getting-the-path-of-appdata

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Samstag, 2. Juli 2011 13:11
    Moderator

Alle Antworten

  • Hallo Hamit,

    schau mal hier, da stehen zwei Lösungswege:

      http://stackoverflow.com/questions/867485/c-getting-the-path-of-appdata

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Samstag, 2. Juli 2011 13:11
    Moderator
  • Hallo Hamit,

    > Ich würde gern einige Dateien für mein Programm im AppData-Ordner speichern, wofür ich allerdings dort einen Unterordner anlegen müsste

    Die Umgebungsvariable %APPDATA% verweist auf das Verzeichnis, in dem programmspezifische Daten für den aktuellen Roamingbenutzer gespeichert werden (
    %LOCALAPPDATA% hingegen auf das lokale Verzeichnis für den aktuellen Benutzer). Auf diese Verzeichnisse verweisen ebenfalls zwei Enumerationselemente: Environment.SpecialForders.ApplicationData bzw. Environment.SpecialForders.LocalApplicationData.

    Wenn Du aber Programmdaten für alle Benutzer Deines Programms speichern möchtest (vom Programm gemeinsam genutzte Daten), dann müßtest Du das neue Verzeichnis eher unter %ALLUSERSPROFILE%, d.h. Environment.SpecialForders.CommonApplicationData erstellen.

    Da die Umgebungsvariablen in vielen Fällen nicht, oder nicht richtig gesetzt sind, empfiehlt sich eher die Verwendung von Environment.SpecialFolders.

    Verwendest Du aber trotzdem Umgebungsvariablen, so mußt Du diese vor der Verwendung expandieren:

    string expandedPath = Environment.ExpandEnvironmentVariables("%appdata%//hamitgerkansprojects");
    System.IO.Directory.CreateDirectory(expandedPath); // wird nur erstellt wenn nicht vorhanden
    

    Generell ist es vorteilhaft wenn man Pfade über System.IO.Path.Combine zusammenfügt, z.B. string myDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolders.ApplicationData), "SubDirectory").

    Vorsicht: Der Name des Verzeichnisses ("hamitgerkansprojects") verstößt logisch gegen einige Grundsätze:

    1. Environment.SpecialFolders.ApplicationData ist für benutzerspezifische Daten der Applikation und nicht des Benutzers vorgesehen ("projects" legt nahe, dass es sich hier um Projekte von Hamit handelt). Diese sollten, wenn es sich um Dokumente handelt, am besten unter SpecialFolders.Personal/MyDocuments + Unterverz. abgelegt werden.

    2. Die Erwähnung des Benutzernamens (Hamit) im Pfadnamen macht bei der Verwendung von Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) nicht viel Sinn, da hier alle Verzeichnisse benutzerbezogen sind und der Name sowieso schon im Pfad steht.

    3. Normalerweise steht unter %appdata% als Verzeichnisname der Name der Anwendung, also z.B. C:\Users\Hamit Gerkan\AppData\Roaming\SuperApp.

    Das Speichern von Daten unter SpecialFolder.ApplicationData hat noch einen weiteren Haken. Wenn Deine Anwendung für alle Benutzer installiert wird, gibt es zur Installationszeit keinen korrekten Speicherort dafür, d.h. eventuelle Daten die Du vorab nach SpecialFolder.ApplicationData schreiben möchtest, dürfen nicht während der Installation sondern erst beim ersten Start der Anwendung nach ApplicationData geschrieben werden.

    Auf die Probleme von ApplicationData bei der Verwendung von ClickOnce-Deployment, gehe ich hier nicht ein.

    Ach ja, fast hätte ich's vergessen: Du kannst natürlich außer über Umgebungsvariable, SpecialFoders-Enumerationselemente auch noch über Application.CommonAppDataPath, Application.LocalUserAppDataPath bzw. Application.UserAppDataPath auf bekannte Verzeichnisse zugreifen. Diese letzten drei Properties haben den Vorteil, dass sie je nachdem ob die Anwendung über ClickOnce oder normal installiert wurde, autom. auf entspr. Verzeichnisse verzweigen (ClickOnce => AppDomain.CurrentDomain.GetData("DataDirectory"), sonst => strukturierter Pfad z.B. Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData))\Firma\Produkt\Version). 

    Dazu kommen unter Windows 7 weitere Möglichkeiten hinzu, auf die ich hier ebenfalls nicht eingehe.
     

    Environment.SpecialFolder Enumeration
    http://msdn.microsoft.com/de-de/library/system.environment.specialfolder.aspx

    Environment.ExpandEnvironmentVariables-Methode:
    http://msdn.microsoft.com/de-de/library/system.environment.expandenvironmentvariables.aspx

    KNOWNFOLDERID (unter Remarks stehen die Standardpfade):
    http://msdn.microsoft.com/en-us/library/dd378457(v=vs.85).aspx

    Technical requirements for the Windows 7 Client Software Logo Program
    http://www.microsoft.com/download/en/details.aspx?id=3859


    Gruß
    Marcel





    Samstag, 2. Juli 2011 15:21
    Moderator
  • Hallo Hamit,

    dazu ist einiges zu sagen. Im Prinzip solltest Du immer erstmal die .NET Methoden für die Pfade benutzen und nicht Dinge wie "%appdata%" obwohl das unter Windows sehr oft funktionieren wird. Ich verzichte mal auf eigene Bemerkungen, da diese Dinge sehr gut in den Artikeln beschrieben sind.

    Also erstmal die wichtigsten Möglichkeiten dazu:

    Pfad für die Anwendungsdaten eines Benutzers:
    [Application.UserAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.userappdatapath.aspx

    Pfad für die Anwendungsdaten eines lokalen Benutzers, der kein Roaming verwendet:
    [Application.LocalUserAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.localuserappdatapath.aspx

    Pfad für die Anwendungsdaten, die von allen Benutzern gemeinsam genutzt werden:
    [Application.CommonAppDataPath-Eigenschaft (System.Windows.Forms)]
    http://msdn.microsoft.com/de-de/library/system.windows.forms.application.commonappdatapath.aspx

    [Environment.SpecialFolder-Enumeration (System)]
    http://msdn.microsoft.com/de-de/library/system.environment.specialfolder.aspx
    CommonApplicationData:
        Das Verzeichnis, das als allgemeines Repository für programmspezifische Daten verwendet
        wird, die von allen Benutzern verwendet werden.
    LocalApplicationData:
        Das Verzeichnis, das als allgemeines Repository für programmspezifische Daten verwendet
        wird, die von einem aktuellen Benutzer verwendet werden, der kein Roamingbenutzer ist.

    Hier detailliertere Möglichkeiten ab Vista und später, mit denen man sehr dedizierte Ordner-Positionen angeben kann:
    [KNOWNFOLDERID (Windows)]
    http://msdn.microsoft.com/en-us/library/dd378457(VS.85).aspx
    [CSIDL (Windows)]
    http://msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx -> CSIDL_APPDATA

    [ReadMe.txt - Shell known folder sample (CSShellKnownFolders)]
    http://code.msdn.microsoft.com/CSShellKnownFolders-94aa920a/sourcecode?fileId=21702&pathId=1556858234

    ========================================

    Trotzdem will ich Dir einmal Deinen Code explizit sauber umwandeln:

     

       string appDataVerzeichnis = Environment.GetEnvironmentVariable("appData");
       string hamitVerzeichnis = Path.Combine(appDataVerzeichnis, "hamitgerkansprojects");
       if(!Directory.Exists(hamitVerzeichnis)) Directory.CreateDirectory(hamitVerzeichnis);
    
    

    Allerdings denke ich, es ist besser die reine .NET Methode zu benutzen, als die Umgebungsvariable - also etwa:

     

       string appDataVerzeichnis = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
       string hamitVerzeichnis = Path.Combine(appDataVerzeichnis, "hamitgerkansprojects");
       if(!Directory.Exists(hamitVerzeichnis)) Directory.CreateDirectory(hamitVerzeichnis);
    

    Wichtig ist auch, dass man im allgemeinen AppData-Verzeichnis normal Erstellerbesitzer-Berechtigungen hat.
    Man sollte diesen Berechtigungstyp "verstehen". Er birgt gewisse Risiken.

     

     


    ciao Frank
    Samstag, 2. Juli 2011 18:34
  • OK, danke euch allen, werde alles mal ausprobieren!
    Samstag, 16. Juli 2011 16:56