73

I was reading some file IO tutorials for C# and have managed to write out some files, but what if the path I'm given contains directories?

For example, I want to create the file called data/my_file except data folder doesn't exist.

The line,

BinaryWriter outFile = new BinaryWriter(File.OpenWrite(path));

where path is the above string, crashes with the message that part of the path doesn't exist, which means C# isn't creating them as required.

I would like C# to handle all of the messy directory creation and checking for me instead of me having to parse the path and create all of the necessary directories. Is this possible? Otherwise, is there a snippet of code that I can just copy over into my project which will handle anything I might be overlooking (since I don't know much about file management).

1

6 Answers 6

159

System.IO.Directory.CreateDirectory() will create all directories and subdirectories in a specified path, should they not already exist.

You can call it, passing the path, to ensure the folder structure is created prior to writing your file.

4
  • Great! Though now I'm kind of wondering why this isn't done automatically. I mean, are there times where you don't want to actually create these directories automatically if needed?
    – MxLDevs
    Commented Jun 8, 2012 at 0:29
  • 15
    It would have been really handy of Microsoft to at least provide a boolean parameter to BinaryWriter asking if you want to create the directories if they don't exist. I guess if you always do it, someone will have a use case where they didn't want that behavior and will complain that they have no control over it.
    – Eric J.
    Commented Jun 8, 2012 at 0:45
  • 1
    It's curious that they did not include such a parameter, considering Directory.GetFiles() has SearchOption to specify top-level or recursive search.
    – Erik
    Commented Apr 15, 2014 at 15:02
  • If you don't want to manually parse the path to get the name of directory that needs to be created, use Path.GetDirectoryName(string) like this: Directory.CreateDirectory(Path.GetDirectoryName(fullPath)). EDIT: it seems H7O's answer already uses this method, but it's not the accepted answer despite the extra info, as it was added a few months later.
    – sisisisi
    Commented Nov 22, 2020 at 7:56
16

here is how I usually do it

Directory.CreateDirectory(Path.GetDirectoryName(filePath));

^ this should take care of ensuring all necessary folders (regardless if some of them already exist) that precedes your file are created. E.g. if you pass it "c:/a/b/c/data/my file.txt", it should ensure "c:/a/b/c/data" path is created.

9

While System.IO.Directory.CreateDirectory() will indeed create directories for you recursively, I came across a situation where I had to come up with my own method. Basically, System.IO doesn't support paths over 260 characters, which forced me to use the Delimon.Win32.IO library, which works with long paths, but doesn't create directories recursively.

Here's the code I used for creating directories recursively:

void CreateDirectoryRecursively(string path)
{
    string[] pathParts = path.Split('\\');

    for (int i = 0; i < pathParts.Length; i++)
    {
        if (i > 0)
            pathParts[i] = Path.Combine(pathParts[i - 1], pathParts[i]);

        if (!Directory.Exists(pathParts[i]))
            Directory.CreateDirectory(pathParts[i]);
    }
}
4
  • 2
    Doesn't Explorer barf on paths over 255 characters? It sucks but I'd sooner truncate it than try to deal with that crap.
    – Casey
    Commented Mar 29, 2015 at 2:49
  • 1
    2y old bump I know but I stumbled upon this answer while fixing a bug and wanted to add a warning to this answer. This will throw "Path is not of a legal form" when using network drives (Paths starting with \\). Commented Mar 10, 2016 at 9:32
  • The code will also fail if the path contains the drive letter.
    – Hans
    Commented May 23, 2017 at 11:30
  • .NET now supports longer paths for operating systems that support them (e.g. Windows 10 Anniversary and later). Even if one is able to assume the code will run on a supported OS, I suggest catching the possible IO exception and providing a clean error message about the directory name length. blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/…
    – Eric J.
    Commented Oct 19, 2018 at 15:26
1

So, the above didn't work super well for me for basic directory creation. I modified this a bit to handle common cases for drive letters and a path with a file resource on the end.

    public bool CreateDirectoryRecursively(string path)
    {
        try
        {
            string[] pathParts = path.Split('\\');
            for (var i = 0; i < pathParts.Length; i++)
            {
                // Correct part for drive letters
                if (i == 0 && pathParts[i].Contains(":"))
                {
                    pathParts[i] = pathParts[i] + "\\";
                } // Do not try to create last part if it has a period (is probably the file name)
                else if (i == pathParts.Length-1 && pathParts[i].Contains("."))
                {
                    return true;
                }
                if (i > 0) { 
                    pathParts[i] = Path.Combine(pathParts[i - 1], pathParts[i]);
                }
                if (!Directory.Exists(pathParts[i]))
                {
                    Directory.CreateDirectory(pathParts[i]);
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            var recipients = _emailErrorDefaultRecipients;
            var subject = "ERROR: Failed To Create Directories in " + this.ToString() + " path: " + path;
            var errorMessage = Error.BuildErrorMessage(ex, subject);
            Email.SendMail(recipients, subject, errorMessage);
            Console.WriteLine(errorMessage);
            return false;

        }

    }
0

For .Net 6 with nullable checks:

var dstFilePath = Path.Combine(Path.GetTempPath(), "foo", "bar.txt");
var dstDirPath = Path.GetDirectoryName(dstFilePath) ??
                         throw new InvalidOperationException("Dst dir is invalid");
Directory.CreateDirectory(dstDirPath);
-1

Previous answers didn't handle Network paths. Attached code which also handles that.

/// <summary>
/// tests (and creates missing) directories in path containing many 
subDirectories which might not exist.
    /// </summary>
    /// <param name="FN"></param>
    public static string VerifyPath(string FN, out bool AllOK)
    {
        AllOK = true;
        var dir = FolderUtils.GetParent(FN);
        if (!Directory.Exists(dir))//todo - move to folderUtils.TestFullDirectory
        {
            const char DIR = '\\';
            //string dirDel = "" + DIR;

            string[] subDirs = FN.Split(DIR);
            string dir2Check = "";
            int startFrom = 1;//skip "c:\"
            FN = CleanPathFromDoubleSlashes(FN);
            if (FN.StartsWith("" + DIR + DIR))//netPath
                startFrom = 3;//FN.IndexOf(DIR, 2);//skip first two slashes..
            for (int i = 0; i < startFrom; i++)
                dir2Check += subDirs[i] + DIR;//fill in begining

            for (int i = startFrom; i < subDirs.Length - 1; i++)//-1 for the file name..
            {
                dir2Check += subDirs[i] + DIR;
                if (!Directory.Exists(dir2Check))
                    try
                    {
                        Directory.CreateDirectory(dir2Check);
                    }
                    catch { AllOK = false; }
            }
        }
        if (File.Exists(FN))
            FN = FolderUtils.getFirstNonExistingPath(FN);
        if (FN.EndsWith("\\") && !Directory.Exists(FN))
            try { Directory.CreateDirectory(FN); }
            catch
            {
                HLogger.HandleMesssage("couldn't create dir:" + FN, TypeOfExceptions.error, PartsOfSW.FileStructure);
                AllOK = false;
            }

        return FN;

    }

And the "CleanDoubleSlashes function":

  public static string CleanPathFromDoubleSlashes(string basePath)
    {
        if (string.IsNullOrEmpty(basePath) || basePath.Length < 2)//don't clean first \\ of LAN address
            return basePath;
        for (int i = basePath.Length - 1; i > 1; i--)
        {
            if ((basePath[i] == '\\' && basePath[i - 1] == '\\') || (basePath[i] == '/' && basePath[i - 1] == '/'))
            {
                basePath = basePath.Remove(i, 1);//Substring(0, i - 2) + basePath.Substring(i, basePath.Length - 1 - i);
            }
        }
        return basePath;
    }
2
  • Your code provided is for Java and not C#. Also, it is referencing 3rd-party utils which aren't explicitly called out
    – Damian
    Commented Nov 15, 2018 at 14:28
  • You're right I'm calling some 3rd party func FolderUtils.getFirstNonExistingPath(FN); but the code is C#. not Jave.. I use it for C#... And regarding the functiom - you can implement it very easially, if you want... just loop till 1000 end test if directory doesn't exist...
    – ephraim
    Commented Nov 17, 2018 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.