Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Using `Environment.SpecialFolder` to Maximize Portability

4.92/5 (7 votes)
26 Apr 2016CPOL3 min read 32.2K   64  
How to avoid some hardcoded paths with the uses of Environment.UserName

The above contains the "parse_me.txt" file, which has the numbers from 1-10 as strings, 1 per line (one, two ... ten), and the "save to desktop.linq" file, which contains our code. Simply extract both to the desktop, and if you have linqpad installed, just double click the linq file and run it.

Introduction

Assumptions

  • You're reading or writing to a file on your computer (in some folder under your user folders, my documents, desktop, etc.), and using some code that looks like:
    C#
    // Path to the file you want to read:
    var path = "C:\Users\Your.User.Name\Documents\LINQPad Queries\Misc Files\parse_me.txt";
    
    // Happily read your file content:
    string[] read_all_lines = System.IO.File.ReadAllLines(path);
  • You're familiar with Linqpad or Visual Studio.
  • You work on 2 different computers. For ease of reference, let's call them Home and Work .
  • You have a file on your Home Desktop, and you want to continue working from Work.
  • You've copied your linqpad query and your Home desktop file to your Work desktop

Following those assumptions, you try to run your query on your Work computer, and realize it fails to work, because the paths are all messed up.

In my case, I keep all my linqpad queries in my documents folder, under the default LINQPad Queries folder. In that folder, I have a "Misc files" folder with some text files I was trying to parse, let's assume it's parse_me.txt.

First, linqpad is being run from C:\ProgramData\LINQPad\Updates40\448 (ymmv). This means you can't use a relative path from where the executable is, and you need to use a full URI to the files. This is why it was encoded as:

C#
// Path to the file you want to read:
var path = "C:\Users\Your.User.Name\Documents\LINQPad Queries\Misc Files\parse_me.txt";

Since I'm keeping the same structure on my machines (so I can just copy the entire queries folder and keep working), the only difference would be the user name on the other machine. So, with this simple workaround, we can have a more generic way to access our file:

C#
// What's the name of the file you want to work with
var file_name = "parse_me.txt";

// Let's assume you're working with the file on your desktop
var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

// This is needed to "paste" the dir and the file name (it'll add the "\" basically).
var file_location = Path.Combine(path,file_name);
    
// Now you can do:
string[] read_all_lines = System.IO.File.ReadAllLines(file_location);

(For more special folders, have a look at this MSDN page).

Now, you can obviously encode the file name as part of the path, but let's assume you want to write the output of your processing to a file, and you want it to be next to your input file. Now you can do:

C#
// Process your file ...

// Output file name
var out_file_name = "exciting_results.txt";

// Again, combining path and file name
file_location = Path.Combine(path,file_name);

// Write your results, in this case, it's a string[]
System.IO.File.WriteAllLines(file_location, some_string_array);

// Let's let the user know we're all good
Console.Out.WriteLine( out_file_name + " saved successfully.");

Done.

Now you can work on both computers, and assuming you have the linq query (or your .NET class / project), and that your input file is in the same "relative" (directory on both machines, your code will work :). In "relative", I mean: both "desktop" folders, or both "my document\my code" folder, etc.

Full Example

Here's a full example using Linqpad and an input / output file combo (If you're not familiar with Linqpad, the .Dump() acts a bit like you console WriteLine(), but will print objects as well).

C#
void Main()
{
    // All this was covered above
    var file_name = "parse_me.txt";
    var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    var file_location = Path.Combine(path,file_name);
    
    // Let's read our data. In our case, it's the numbers 1-10, in words
    string[] read_all_lines = System.IO.File.ReadAllLines(file_location )
                                .Dump("This is our input")
                                ;
    
    // This list will hold all the words with an even number of chars
    var even_length = read_all_lines.Where (line =>line.Length %2 == 0 )
                        .Dump()
                        ;
                        
    // Just for fun, and so as to not repeat ourselves, let's find
    // the uneven by using the Set's Except method.
    // (read: A.Except(B) all the elements from A which are not in B)
    var uneven_lenght = read_all_lines.Except(even_length)
                        .Dump()
                        ;

    // Let's say we want only the first 2 uneven numbers
    // with more than four characters
    var first_two_uneven_longer_than_4 = uneven_lenght
            .Where ( number => number.Length > 4 )
            .Take(2)
            .Dump();
            ;
    
    // And let's save them into our output file
    System.IO.File.WriteAllLines( Path.Combine(path,"exciting_results.txt")
                                 , first_two_uneven_longer_than_4  );
}

The content of the "parse_me.txt" that should be on your desktop looks like:

one
two
three
four
five
six
seven
eight
nine
ten

The results will look like:

This is your user name
Your.User.Name

 

This is our input (result of: ReadAllLines)
5String[] (10 items)4
one
two
three
four
five
six
seven
eight
nine
ten

 

Numbers with even length:
four
five
nine

 

Numbers with uneven length:
one
two
three
six
seven
eight
ten

 

First two numbers longer than 4 characters:
three
seven

Hope you'll find it useful. :)

History

  • 27th April, 2016: Updated the results and added some explanation about how to use the code
  • 27th June, 2014: Initial release
  • 27th June, 2014: Update, thanks to SoMad good pointer

License

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