Create Directory + Sub Directories - c#

I've got a directory location, how can I create all the directories? e.g. C:\Match\Upload will create both Match and the sub-directory Upload if it doesn't exist.
Using C# 3.0
Thanks

Directory.CreateDirectory(#"C:\Match\Upload") will sort this all out for you. You don't need to create all the subdirectories! The create directory method creates all directories and sub directories for you.

if (!System.IO.Directory.Exists(#"C:\Match\Upload"))
{
System.IO.Directory.CreateDirectory(#"C:\Match\Upload");
}

Here is an example with a DirectoryInfo object that will create the directory and all subdirectories:
var path = #"C:\Foo\Bar";
new System.IO.DirectoryInfo(path).Create();
Calling Create() will not error if the path already exists.
If it is a file path you can do:
var path = #"C:\Foo\Bar\jazzhands.txt";
new System.IO.FileInfo(path).Directory.Create();

for googlers: in pure win32/C++, use SHCreateDirectoryEx
inline void EnsureDirExists(const std::wstring& fullDirPath)
{
HWND hwnd = NULL;
const SECURITY_ATTRIBUTES *psa = NULL;
int retval = SHCreateDirectoryEx(hwnd, fullDirPath.c_str(), psa);
if (retval == ERROR_SUCCESS || retval == ERROR_FILE_EXISTS || retval == ERROR_ALREADY_EXISTS)
return; //success
throw boost::str(boost::wformat(L"Error accessing directory path: %1%; win32 error code: %2%")
% fullDirPath
% boost::lexical_cast<std::wstring>(retval));
//TODO *djg* must do error handling here, this can fail for permissions and that sort of thing
}

Related

How to get all files in a StorageFolder in Windows Phone Runtime?

I want to get all files in a folder and its sub folders. but a flat query like this:
var allFiles = await myFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName);
throws a ArgumentException exception:
A first chance exception of type 'System.ArgumentException' occurred
Additional information: Value does not fall within the expected range.
before I query subfolders one by one, isn't there any other way?
You want all the files and folder which are a descendent of the root folder, not just the shallow enummeration. For most folders the only way to enumerate all the contents and its subfolders content is:
Use StorageFolder.GetFilesAsync() for the files
Use StorageFolder.GetFoldersAsync() to retrieve the all the subfolders
Repeat recursively for all the subfolders you find in step 2.
There is a workaround for this if you are looking for a particular type of media. The instructions are here. These few combinations of locations and CommonFile/FolderQuery options will give a device deep search for media and return the ordered results.
Use CommonFileQuery.OrderByName This is a deep query too so the result will contain all of files from all of subfolders
AND IT WORKS! ;)
MSDN says that you get System.ArgumentException if:
You specified a value other than DefaultQuery from the CommonFileQuery enumeration for a folder that's not a library folder.
https://msdn.microsoft.com/en-us/library/windows/apps/BR211591.aspx
That is strange! Looks like a bug in GetFilesAsync method with all CommaonFileQuery options except DefaultQuery. It is working fine with DefaultQuery.
var allFiles = await myFolder.GetFilesAsync(CommonFileQuery.DefaultQuery);
Hope this helps!
I had the same problem, solved it by preloading file paths recursively:
private static List<string> mContentFilenames = new List<string>();
private static void preloadContentFilenamesRecursive(StorageFolder sf)
{
var files = sf.GetFilesAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (files != null)
{
foreach (var f in files)
{
mContentFilenames.Add(f.Path.Replace('\\','/'));
}
}
var folders = sf.GetFoldersAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (folders != null)
{
foreach (var f in folders)
{
preloadContentFilenamesRecursive(f);
}
}
}
private static void preloadContentFilenames()
{
if (mContentFilenames.Count > 0)
return;
var installed_loc = Windows.ApplicationModel.Package.Current.InstalledLocation;
var content_folder = installed_loc.GetFolderAsync("Content").AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (content_folder != null)
preloadContentFilenamesRecursive(content_folder);
}
private static bool searchContentFilename(string name)
{
var v = from val in mContentFilenames where val.EndsWith(name.Replace('\\', '/')) select val;
return v.Any();
}
No idea why downvoted, there is no other way to get full filelist in WP8.1. MSFT for some strange reason corrupts its apis from version to version. Some of calls now returns "not implemented".

Delete a FolderItem

I want to delete a file stored in an USB flashdrive (actually an android device's sd card).
I ask the user to point the app's folder inside the sd card, and i hold a Shell32.Folder object pointing to it.
I can iterate between the files (FolderItem objects), but how can i delete a file using Shell32 classes?
Usual File.Delete(filePath) does not work, since the FolderItem.Path is a BSTR data type, so maybe the key is to convert from one type to another, but i couldn't find a way to do this.
Any ideas?
EDIT 1:
FolderItem.Path data:
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04e8&pid_6860&ms_comp_mtp&gt-p5100#7&392be4e4&0&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,SECZ9519043CHOHB,12530364416}\{015C008D-013D-0145-D300-D300CB009500}\{015C00EE-013D-0145-0201-37012C010901}\{025901D2-029D-020F-DE01-FE010D02A601}"
This is not a valid path for File.Delete. Any ideas on how to convert that?
EDIT 2:
Method that opens the browse folder window, so the user can point out the app directory, inside his android device's SD card, so i can iterate with folders and files, and sync some data with the server. Done this way due to problems between Win8 and Shell32:
public Shell32.Folder GetShell32NameSpace(Object folder)
{
Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
Object shell = Activator.CreateInstance(shellAppType);
return (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { folder });
}
Using the method above, to get the Folder:
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
Folder androidPath = BrowseForFolder(windowHandle.ToInt32(), "App's data folder", 0, 0);
I create and copy a file into the app's 'data' folder, so the device can recognize a syncing action, tell the user, and close the app:
byte[] data = new UTF8Encoding(true).GetBytes("sync_cable");
if (androidPath != null)
{
foreach (FolderItem dir in androidPath.Items())
{
if (dir.IsFolder && dir.Name == "data")
{
Folder dataFolder = GetShell32NameSpace(dir.Path);
if (dataFolder != null)
{
string tempPath = Path.GetTempPath();
string path = Path.Combine(tempPath, flagFileName);
File.WriteAllBytes(path, data);
Folder localPath = GetShell32NameSpace(tempPath);
if (localPath != null)
{
foreach (FolderItem file in localPath.Items())
{
if (file.Name.Contains(flagFileName))
{
dataFolder.CopyHere(file);
break;
}
}
}
}
break;
}
}
}
After the sync, i want to delete the file, so the app can function normally:
foreach (FolderItem file in dataFolder.Items())
{
if (file.Name.Contains(flagFileName))
{
// THIS THROWS AN 'INVALID PATH' EXCEPTION
// FileInfo fi = new FileInfo(file.Path);
// fi.Delete();
// THIS ALSO THROWS AN 'INVALID PATH' EXCEPTION
// File.Delete(file.Path);
break;
}
}
As mentioned in EDIT 1, file.Path of the file i want to delete, has the following format:
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04e8&pid_6860&ms_comp_mtp&gt-p5100#7&392be4e4&0&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,SECZ9519043CHOHB,12530364416}\{015C008D-013D-0145-D300-D300CB009500}\{015C00EE-013D-0145-0201-37012C010901}\{025901D2-029D-020F-DE01-FE010D02A601}"
EDIT 3:
As suggested here, i tried using P/Invoke to delete the file, with no success.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteFile(string lpFileName);
Calling the method:
foreach (FolderItem file in dataFolder.Items())
{
if (file.Name.Contains(flagFileName))
{
// ...
bool deleted = DeleteFile(file.Path);
// ...
}
}
The method returns false, and the file is not deleted. I looked in the Event Viewer for a clue about what happened, but found nothing.
The part of the path which looks like "\?\" tells you that it's a long path. Sadly the CLR cannot handle long paths (it's limited to MAX_PATH = 260 nonsense). I believe you can use the WinAPI's DeleteFile to accomplish what you want.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363915(v=vs.85).aspx
Use PInvoke and you'll be all set.
http://pinvoke.net/default.aspx/kernel32/DeleteFile.html?diff=y
The guid prefix ("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}") is the standard junction point for MyComputer (see https://msdn.microsoft.com/en-us/library/windows/desktop/cc144096(v=vs.85).aspx).
I suspect the file cannot be deleted using such methods as the shell API DeleteFile because it is not in the file system (you can check it using FolderItem.IsFileSystem) because the android device is connected using MTP.
I have been able to delete such files using FolderItem.InvokeVerb("Delete"). This produces a confirmation dialog which can be dismissed using some version of SendKeys (for example freeware Nirsoft's Nircmd.exe). The following is a VBA sample:
Private Sub SampleDelete()
Const sFolder = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_054c&pid_04cb#10fbd475671683#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,00000000000000000000000005671683,7513636864}\{00000007-0000-0000-0000-000000000000}\{000057F1-0000-0000-66A5-884D99020600}"
Const sFileName = "test.txt"
' requires reference to Shell32.dll
Dim oShell As New Shell32.Shell
Dim oFolder As Shell32.Folder
Dim oFile As Shell32.FolderItem
Set oFolder = oShell.Namespace(sFolder)
If Not oFolder Is Nothing Then
Set oFile = oFolder.ParseName(sFileName)
If Not oFile Is Nothing Then
Debug.Print "File system? " & oFile.IsFileSystem
' dismiss the confirmation dialog
SendKeys "~"
' Alternatively use an external function, like this freeware utility
' Shell "nircmd.exe sendkey enter press", vbHide
oFile.InvokeVerb "Delete"
Else
Debug.Print "File not found"
End If
Else
Debug.Print "Folder not found"
End If
Set oShell = Nothing
Set oFolder = Nothing
Set oFile = Nothing
End Sub

How to create a path using the Windows.Storage API?

System.IO.CreateDirectory() is not available on .NET for Windows Store Apps.
How can I implement this equivalent method? StorageFolder.CreateFolderAsync() creates a subfolder inside the current folder, but in my case I have a path like and need to create all folders that doesn't exist in this path.
The path is inside the app's sandbox in windows.
There's no API with exactly the same behaviour of System.IO.CreateDirectory(), so I implemented it using Windows.Storage classes:
// Any and all directories specified in path are created, unless they already exist or unless
// some part of path is invalid. If the directory already exists, this method does not create a
// new directory.
// The path parameter specifies a directory path, not a file path, and it must in
// the ApplicationData domain.
// Trailing spaces are removed from the end of the path parameter before creating the directory.
public static void CreateDirectory(string path)
{
path = path.Replace('/', '\\').TrimEnd('\\');
StorageFolder folder = null;
foreach(var f in new StorageFolder[] {
ApplicationData.Current.LocalFolder,
ApplicationData.Current.RoamingFolder,
ApplicationData.Current.TemporaryFolder } )
{
string p = ParsePath(path, f);
if (f != null)
{
path = p;
folder = f;
break;
}
}
if(path == null)
throw new NotSupportedException("This method implementation doesn't support " +
"parameters outside paths accessible by ApplicationData.");
string[] folderNames = path.Split('\\');
for (int i = 0; i < folderNames.Length; i++)
{
var task = folder.CreateFolderAsync(folderNames[i], CreationCollisionOption.OpenIfExists).AsTask();
task.Wait();
if (task.Exception != null)
throw task.Exception;
folder = task.Result;
}
}
private static string ParsePath(string path, StorageFolder folder)
{
if (path.Contains(folder.Path))
{
path = path.Substring(path.LastIndexOf(folder.Path) + folder.Path.Length + 1);
return path;
}
return null;
}
To create folders outside your app's sandbox in windows store app, you'll have to add the document library in app-manifest, along with file permissions.
For a much more detailed explanation regarding library and documents, Refer this blog

If a folder does not exist, create it

I use a FileUploader control in my application. I want to save a file to a specified folder. If this folder does not exist, I want to first create it, and then save my file to this folder. If the folder already exists, then just save the file in it.
How can I do this?
Use System.IO.Directory.CreateDirectory.
According to the official ".NET" docs, you don't need to check if it exists first.
System.io   >   Directory   >   Directory.CreateDirectory
Any and all directories specified in path are created, unless they already exist or unless some part of path is invalid. If the directory already exists, this method does not create a new directory, but it returns a DirectoryInfo object for the existing directory.
        — learn.microsoft.com/dotnet/api/
Use the below code as per How can I create a folder dynamically using the File upload server control?:
string subPath ="ImagesPath"; // Your code goes here
bool exists = System.IO.Directory.Exists(Server.MapPath(subPath));
if(!exists)
System.IO.Directory.CreateDirectory(Server.MapPath(subPath));
Just write this line:
System.IO.Directory.CreateDirectory("my folder");
If the folder does not exist yet, it will be created.
If the folder exists already, the line will be ignored.
Reference: Article about Directory.CreateDirectory at MSDN
Of course, you can also write using System.IO; at the top of the source file and then just write Directory.CreateDirectory("my folder"); every time you want to create a folder.
Directory.CreateDirectory explains how to try and to create the FilePath if it does not exist.
Directory.Exists explains how to check if a FilePath exists. However, you don't need this as CreateDirectory will check it for you.
You can create the path if it doesn't exist yet with a method like the following:
using System.IO;
private void CreateIfMissing(string path)
{
bool folderExists = Directory.Exists(Server.MapPath(path));
if (!folderExists)
Directory.CreateDirectory(Server.MapPath(path));
}
This method will create the folder if it does not exist and do nothing if it exists:
Directory.CreateDirectory(path);
You can use a try/catch clause and check to see if it exist:
try
{
if (!Directory.Exists(path))
{
// Try to create the directory.
DirectoryInfo di = Directory.CreateDirectory(path);
}
}
catch (IOException ioex)
{
Console.WriteLine(ioex.Message);
}
using System.IO
if (!Directory.Exists(yourDirectory))
Directory.CreateDirectory(yourDirectory);
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
}
The following code is the best line(s) of code I use that will create the directory if not present.
System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath("~/temp/"));
If the directory already exists, this method does not create a new directory, but it returns a DirectoryInfo object for the existing directory. >
Create a new folder, given a parent folder's path:
string pathToNewFolder = System.IO.Path.Combine(parentFolderPath, "NewSubFolder");
DirectoryInfo directory = Directory.CreateDirectory(pathToNewFolder);
// Will create if does not already exist (otherwise will ignore)
path to new folder given
directory information variable so you can continue to manipulate it as you please.
Use this code if the folder is not presented under the image folder or other folders
string subPath = HttpContext.Current.Server.MapPath(#"~/Images/RequisitionBarCode/");
bool exists = System.IO.Directory.Exists(subPath);
if(!exists)
System.IO.Directory.CreateDirectory(subPath);
string path = HttpContext.Current.Server.MapPath(#"~/Images/RequisitionBarCode/" + OrderId + ".png");
Use the below code. I use this code for file copy and creating a new folder.
string fileToCopy = "filelocation\\file_name.txt";
String server = Environment.UserName;
string newLocation = "C:\\Users\\" + server + "\\Pictures\\Tenders\\file_name.txt";
string folderLocation = "C:\\Users\\" + server + "\\Pictures\\Tenders\\";
bool exists = System.IO.Directory.Exists(folderLocation);
if (!exists)
{
System.IO.Directory.CreateDirectory(folderLocation);
if (System.IO.File.Exists(fileToCopy))
{
MessageBox.Show("file copied");
System.IO.File.Copy(fileToCopy, newLocation, true);
}
else
{
MessageBox.Show("no such files");
}
}
A fancy way is to extend the FileUpload with the method you want.
Add this:
public static class FileUploadExtension
{
public static void SaveAs(this FileUpload, string destination, bool autoCreateDirectory) {
if (autoCreateDirectory)
{
var destinationDirectory = new DirectoryInfo(Path.GetDirectoryName(destination));
if (!destinationDirectory.Exists)
destinationDirectory.Create();
}
file.SaveAs(destination);
}
}
Then use it:
FileUpload file;
...
file.SaveAs(path,true);
string root = #"C:\Temp";
string subdir = #"C:\Temp\Mahesh";
// If directory does not exist, create it.
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
The CreateDirectory is also used to create a sub directory. All you have to do is to specify the path of the directory in which this subdirectory will be created in. The following code snippet creates a Mahesh subdirectory in C:\Temp directory.
// Create sub directory
if (!Directory.Exists(subdir))
{
Directory.CreateDirectory(subdir);
}
Derived/combined from multiple answers, implementing it for me was as easy as this:
public void Init()
{
String platypusDir = #"C:\platypus";
CreateDirectoryIfDoesNotExist(platypusDir);
}
private void CreateDirectoryIfDoesNotExist(string dirName)
{
System.IO.Directory.CreateDirectory(dirName);
}

Check if DirectoryInfo.FullName is special folder

My goal is to check, if DirectoryInfo.FullName is one of the special folders.
Here is what I'm doing for this (Check directoryInfo.FullName to each special folder if they are equal):
DirectoryInfo directoryInfo = new DirectoryInfo("Directory path");
if (directoryInfo.FullName == Environment.GetFolderPath(Environment.SpecialFolder.Windows) ||
directoryInfo.FullName == Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles ||)
...
...
)
{
// directoryInfo is the special folder
}
But there are many special folders (Cookies, ApplicationData, InternetCache, etc.). Is there any way to do this task more efficiently?
Thanks.
Try this following code :
bool result = false;
DirectoryInfo directoryInfo = new DirectoryInfo("Directory path");
foreach (Environment.SpecialFolder suit in Enum.GetValues(typeof(Environment.SpecialFolder)))
{
if (directoryInfo.FullName == Environment.GetFolderPath(suit))
{
result = true;
break;
}
}
if (result)
{
// Do what ever you want
}
hope this help.
I'm afraid the answers given seem to be the only way, I hate the special folders because what ought to be a very simple function -
void CollectFiles(string strDir, string pattern) {
DirectoryInfo di = new DirectoryInfo(strDir);
foreach(FileInfo fi in di.GetFiles(pattern) {
//store file data
}
foreach(DirectoryInfo diInfo in di.GetDirectories()) {
CollectFiles(diInfo);
}
}
Becomes ugly because you have to include
Check If This Is A Special Folder And Deal With It And Its Child Folders Differently ();
Fair enough Microsoft, to have a folder that could exist anywhere, on a remote PC, on a server etc. But really what is wrong with the UNIX/Linux way, use links to folder and if the destination physical folder has to move, alter the link. Then you can itterate them in a nice neat function treating them all as if ordinary folders.
I don't have enough reputation to add a comment so as a +1 to BobRassler's answer, string comparisons might be more useful.
bool isSpecialFolder = false;
DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(tbx_FolderName.Text, fileName));
foreach (Environment.SpecialFolder specialFolder in Enum.GetValues(typeof(Environment.SpecialFolder)))
{
if (directoryInfo.FullName.ToString()
.ToLower() ==
Environment.GetFolderPath(specialFolder)
.ToLower())
{
isSpecialFolder = true;
break;
}
}
if (isSpecialFolder)
{
// something
}
else
{
// something else
}
Use a reflection to get all values from that enum, like here http://geekswithblogs.net/shahed/archive/2006/12/06/100427.aspx and check against collection of generated paths you get.
I ended up using it this way:
public static bool IsSpecialFolder(DirectoryInfo directoryInfo, out Environment.SpecialFolder? _specialFolder) {
bool isSpecialFolder = false;
_specialFolder = null;
string directoryInfo_FullPath = directoryInfo.FullName;
foreach (Environment.SpecialFolder specialFolder in Enum.GetValues(typeof(Environment.SpecialFolder))) {
var specialFolder_FullPath = Environment.GetFolderPath(specialFolder);
if (string.Equals(directoryInfo_FullPath, specialFolder_FullPath, StringComparison.OrdinalIgnoreCase)) {
isSpecialFolder = true;
_specialFolder = specialFolder;
break;
}
}
return isSpecialFolder;
}
If handling strings from dubious sources (the user :-) ), there are three caveats to keep in mind:
Path.Combine vs. Path.Join, since they handle absolute paths (or paths that look like absolute paths) differently.
Path.GetFullPath, which takes a string an produces the full and normalized version of it.
GetFolderPath can return an empty string, which generates a System.ArgumentException: 'The path is empty. (Parameter 'path')' when used for creating a DirectoryInfo.
I like to keep this logic outside the method, but I am not sure if the OrdinalIgnoreCase or any other normalization is still necessary. I guess not.
P.S.: I think in modern lingo the method should be called TrySpecialFolder or something :-)

Categories

Resources