This question already has answers here:
How do I create a file AND any folders, if the folders don't exist?
(9 answers)
Closed 4 years ago.
I've been writing a simple console application as a part of exercise in project. Tasks are rather straightforward:
2nd method has to create nested directory tree where every folder name is Guid.
3rd method has to put empty file in chosen directory tree at specific level.
My main problem lies within 3rd method. Because while it works fine and creates file 'till third level of any directory, beyond that point it always throw "System.IO.DirectoryNotFoundException" - as it "can't find part of the path".
I use string as a container for path, but since it's few Guid set together it gets pretty long. I had similar problem with creating directory, but in order to work I had to simply put #"\?\" prefix behind the path. So is there any way to make it work, or maybe get around that?
Here are method that fails. Specifically it's
File.Create(PathToFile + #"\blank.txt").Dispose();
And part of code which makes string and invokes it:
string ChosenDirectoryPath = currDir.FullName + #"\";
for (int i = 0; i <= Position; i++)
{
ChosenDirectoryPath += ListsList[WhichList][i];
}
if (!File.Exists(ChosenDirectoryPath + #"\blank.txt"))
{
FileMaker(ref ChosenDirectoryPath);
}
Edit:
To be specific, directories are made by method:
public List<string> DirectoryList = new List<string>();
internal static List<List<string>> ListsList = new List<List<string>>();
private static DirectoryInfo currDir = new DirectoryInfo(".");
private string FolderName;
private static string DirectoryPath;
public void DeepDive(List<string> DirectoryList, int countdown)
{
FolderName = GuidMaker();
DirectoryList.Add(FolderName + #"\");
if (countdown <= 1)
{
foreach (string element in DirectoryList)
{
DirectoryPath += element;
}
Directory.CreateDirectory(#"\\?\" + currDir.FullName + #"\" + DirectoryPath);
Console.WriteLine("Folders were nested at directory {0} under folder {1}\n", currDir.FullName, DirectoryList[0]);
ListsList.Add(DirectoryList);
DirectoryPath = null;
return;
}
DeepDive(DirectoryList, countdown-1);
}
Which is pretty messy because of recursion (iteration would be better but i wanted to do it this way to learn something). The point is that directories are made and stored in list of lists.
Creating files works properly but only for the first three nested folders. So the problem is that it is somehow loosing it's path to file in 4th and 5th level, and can't even make those manually. Could it be too long path? And how to fix this.
Here is exception that throws out:
System.IO.DirectoryNotFoundException: „Can't find part of the path
„C:\Some\More\Folders\1b0c7715-ee01-4df8-9079-82ea7990030f\c6c806b0-b69d-4a3a-88d0-1bd8a0e31eb2\9671f2b3-3041-42d5-b631-4719d36c2ac5\6406f00f-7750-4b5a-a45d-cebcecb0b70e\bcacef2b-e391-4799-b84e-f2bc55605d40\blank.txt”.”
So it throws full path to file and yet says that it can't find it.
You problem is that File.Create doesn't create the corresponding directories for you, instead it throws a System.IO.DirectoryNotFoundException.
You have to create those directories yourself, by using System.IO.Directory.CreateDirectory()
If this exception occurs because of a too long path, you can still use the "long path syntax (\\?\)" like you did when creating your directories.
See also this question: How to deal with files with a name longer than 259 characters? there is also a good article linked
Related
Why is it that File.Move(sourceFileName, destFileName) works fine when the source file and destination files are in different partitions, but Directory.Move(sourceDirName, destDirName) don't? It throws
System.IO.IOException: "Source and destination path must have
identical roots. Move will not work across volumes."
I even tried to create a DirectoryInfo instance and use the MoveTo(destDirName) method but without success.
Am I missing something? Do I really have to implement a "move" functionality myself? (the directory I want to move is very large btw).
You should Use Copy Function followed by a remove. As Move only works in the same drive.
Directory.Move has a condition that states that :
IO Exception will be thrown if an attempt was made to move a directory to a different volume.
Another option is, to add a reference to the Microsoft.VisualBasic namespace and use the MoveDirectory method, which can move across volumes.
Microsoft.VisualBasic.FileIO.FileSystem.MoveDirectory(sourceDirName, destDirName);
Although this is not a Vb.Net question but I found no one mentioned this method so I think might help... Only you need to convert it to C# if needed.
Code:
My.Computer.FileSystem.MoveDirectory(SrcDir,DestDir)
This works on different volume seamlessly/ per my experience.
Based on the posts "Copy a directory to a different drive" and "Non-recursive way to get all files in a directory and its subdirectories in Java", I wrote this non-recursive method and it works fine:
public static void Move(string source, string target)
{
if (!Directory.Exists(source))
{
throw new System.IO.DirectoryNotFoundException("Source directory couldn't be found.");
}
if (Directory.Exists(target))
{
throw new System.IO.IOException("Target directory already exists.");
}
DirectoryInfo sourceInfo = Directory.CreateDirectory(source);
DirectoryInfo targetInfo = Directory.CreateDirectory(target);
if (sourceInfo.FullName == targetInfo.FullName)
{
throw new System.IO.IOException("Source and target directories are the same.");
}
Stack<DirectoryInfo> sourceDirectories = new Stack<DirectoryInfo>();
sourceDirectories.Push(sourceInfo);
Stack<DirectoryInfo> targetDirectories = new Stack<DirectoryInfo>();
targetDirectories.Push(targetInfo);
while (sourceDirectories.Count > 0)
{
DirectoryInfo sourceDirectory = sourceDirectories.Pop();
DirectoryInfo targetDirectory = targetDirectories.Pop();
foreach (FileInfo file in sourceDirectory.GetFiles())
{
file.CopyTo(Path.Combine(targetDirectory.FullName, file.Name), overwrite: true);
}
foreach(DirectoryInfo subDirectory in sourceDirectory.GetDirectories())
{
sourceDirectories.Push(subDirectory);
targetDirectories.Push(targetDirectory.CreateSubdirectory(subDirectory.Name));
}
}
sourceInfo.Delete(true);
}
You can also p/invoke SHFileOperation which is the same function Windows Explorer uses to move directories around. It will either perform a true move or recursive-copy-then-delete, as appropriate.
It can also show the same progress UI as explorer, just by setting a flag.
I know this post is a little old... but there is a way around this! Don't try and move the directory, but zip it up and move it as a File.Move(src,dest); and you can then extract it and there you have it!
I had same problem in VB.NET and instead of "Directory.Move" I used MoveFolder with "FileSystemObject".
You can preserve creation dates with this method.
Scripting.FileSystemObject oFSO = new Scripting.FileSystemObject();
oFSO.MoveFolder(sourceDirName, destDirName)
i have this problem to and i like to solve it in this way
string startPath = #".\start";
string zipPath = #".\result.zip";
string extractPath = #".\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
Are there any objects or functions that can iterate through the files in a set directory in XNA Content?
I have a set of images in a directory in my game's content, but as the project goes on, I will be adding more. However, I don't want to have to go and add a line of code every time I add a new image, it would be much better if I was able to just iterate through every file in the directory and load them into an array. Is there any way to do this?
You can use this handy extension method
public static class Extension Methods
{
public static List<T> LoadContentFolder<T>(this ContentManager contentManager, string contentFolder)
{
DirectoryInfo dir = new DirectoryInfo(contentManager.RootDirectory + "/" + contentFolder);
if (!dir.Exists)
throw new DirectoryNotFoundException();
List<T> result = new List<T>();
FileInfo[] files = dir.GetFiles("*.*");
foreach (FileInfo file in files)
{
result.Add(contentManager.Load<T>(contentFolder + "/" + file.Name.Split('.')[0]));
}
return result;
}
}
Remove the "this" keyword from the constuctor if you dont want to extend the class. You can use it like so:
Dictionary<string,Texture2D> folderContent = Content.LoadContentFolder<Texture2D>("FolderName");
FolderName is just a subfolder within your content folder
And access by doing folderContent["MyAssetName"]
Not in XNA 4.0. MS decided to obscure some methods that made this possible in XNA 3.1. Here's an example project showing a workaround for you to review -- it winds up building a file list during the build process which is a kludge, but it gets you to where you want, I think.
Content Manifest Extension Sample
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
After referring many blogs and articles, I have reached at the following code for searching for a string in all files inside a folder. It is working fine in my tests.
QUESTIONS
Is there a faster approach for this (using C#)?
Is there any scenario that will fail with this code?
Note: I tested with very small files. Also very few number of files.
CODE
static void Main()
{
string sourceFolder = #"C:\Test";
string searchWord = ".class1";
List<string> allFiles = new List<string>();
AddFileNamesToList(sourceFolder, allFiles);
foreach (string fileName in allFiles)
{
string contents = File.ReadAllText(fileName);
if (contents.Contains(searchWord))
{
Console.WriteLine(fileName);
}
}
Console.WriteLine(" ");
System.Console.ReadKey();
}
public static void AddFileNamesToList(string sourceDir, List<string> allFiles)
{
string[] fileEntries = Directory.GetFiles(sourceDir);
foreach (string fileName in fileEntries)
{
allFiles.Add(fileName);
}
//Recursion
string[] subdirectoryEntries = Directory.GetDirectories(sourceDir);
foreach (string item in subdirectoryEntries)
{
// Avoid "reparse points"
if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
{
AddFileNamesToList(item, allFiles);
}
}
}
REFERENCE
Using StreamReader to check if a file contains a string
Splitting a String with two criteria
C# detect folder junctions in a path
Detect Symbolic Links, Junction Points, Mount Points and Hard Links
FolderBrowserDialog SelectedPath with reparse points
C# - High Quality Byte Array Conversion of Images
Instead of File.ReadAllText() better use
File.ReadLines(#"C:\file.txt");
It returns IEnumerable (yielded) so you will not have to read the whole file if your string is found before the last line of the text file is reached
I wrote somthing very similar, a couple of changes I would recommend.
Use Directory.EnumerateDirectories instead of GetDirectories, it returns immediately with a IEnumerable so you don't need to wait for it to finish reading all of the directories before processing.
Use ReadLines instead of ReadAllText, this will only load one line in at a time in memory, this will be a big deal if you hit a large file.
If you are using a new enough version of .NET use Parallel.ForEach, this will allow you to search multiple files at once.
You may not be able to open the file, you need to check for read permissions or add to the manifest that your program requires administrative privileges (you should still check though)
I was creating a binary search tool, here is some snippets of what I wrote to give you a hand
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Parallel.ForEach(Directory.EnumerateFiles(_folder, _filter, SearchOption.AllDirectories), Search);
}
//_array contains the binary pattern I am searching for.
private void Search(string filePath)
{
if (Contains(filePath, _array))
{
//filePath points at a match.
}
}
private static bool Contains(string path, byte[] search)
{
//I am doing ReadAllBytes due to the fact that I am doing a binary search not a text search
// There are no "Lines" to seperate out on.
var file = File.ReadAllBytes(path);
var result = Parallel.For(0, file.Length - search.Length, (i, loopState) =>
{
if (file[i] == search[0])
{
byte[] localCache = new byte[search.Length];
Array.Copy(file, i, localCache, 0, search.Length);
if (Enumerable.SequenceEqual(localCache, search))
loopState.Stop();
}
});
return result.IsCompleted == false;
}
This uses two nested parallel loops. This design is terribly inefficient, and could be greatly improved by using the Booyer-Moore search algorithm but I could not find a binary implementation and I did not have the time when I wrote it originally to implement it myself.
the main problem here is that you are searching all the files in real time for every search. there is also the possibility of file access conflicts if 2+ users are searching at the same time.
to dramtically improve performance I would index the files ahead of time, and as they are edited/saved. store the indexed using something like lucene.net and then query the index (again using luence.net) and return the file names to the user. so the user never queries the files directly.
if you follow the links in this SO Post you may have a head start on implementing the indexing. I didn't follow the links, but it's worth a look.
Just a heads up, this will be an intense shift from your current approach and will require
a service to monitor/index the files
the UI project
I think your code will fail with an exception if you lack permission to open a file.
Compare it with the code here: http://bgrep.codeplex.com/releases/view/36186
That latter code supports
regular expression search and
filters for file extensions
-- things you should probably consider.
Instead of Contains better use algorithm Boyer-Moore search.
Fail scenario: file have not read permission.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Getting path relative to the current working directory?
I have code in C# that includes some images from an absolute path to a relative so the image can be found no matter where the application fold is located.
For example the path in my code (and in my laptop for the image) is
C:/something/res/images/image1.jpeg
and I want the path in my code to be
..../images/image1.jpeg
So it can run wherever the folder is put, whatever the name of the C: partition is etc.
I want to have a path in my code which is independant of the application folder location or if it is in another partition, as long as it is in the same folder as the the rest of the solution.
I have this code:
try
{
File.Delete("C:/JPD/SCRAT/Desktop/Project/Resources/images/image1.jpeg");
}
catch (Exception)
{
MessageBox.Show("File not found:C:/Users/JPD/Desktop/Project/images/image1.jpeg");
}
This code only runs if the file and folder are in that certain path, (which is also the location of the code) I wish for that path to be relative so wherever I put the whole folder (code, files etc) the program will still work as long as the code (which is under project folder) is at the same location with the folder images... what should I do?
Relative paths are based from the binary file from which your application is running. By default, your binary files will be outputted in the [directory of your .csproj]/bin/debug. So let's say you wanted to create your images folder at the same level as your .csproj. Then you could access your images using the relative path "../../images/someImage.jpg".
To get a better feel for this, try out the following as a test:
1) create a new visual studio sample project,
2) create an images folder at the same level as the .csproj
3) put some files in the images folder
4) put this sample code in your main method -
static void Main(string[] args)
{
Console.WriteLine(Directory.GetCurrentDirectory());
foreach (string s in Directory.EnumerateFiles("../../images/"))
{
Console.WriteLine(s);
}
Console.ReadLine(); // Just to keep the console from disappearing.
}
You should see the relative paths of all the files you placed in step (3).
see: Getting path relative to the current working directory?
Uri uri1 = new Uri(#"c:\foo\bar\blop\blap");
Uri uri2 = new Uri(#"c:\foo\bar\");
string relativePath = uri2.MakeRelativeUri(uri1).ToString();
Depending on the set up of your program, you might be able to simply use a relative path by skipping a part of the full path string. It's not braggable, so J. Skit might be up my shiny for it but I'm getting the impression that you simply want to make it work. Beauty being a later concern.
String absolutePath = #"c:\beep\boop\HereWeStart\hopp.gif";
String relativePath = absolutePath.Substring(13);
You could then, if you need/wish, exchange the number 13 (which is an ugly and undesirable approach, still working, though) for a dynamically computed one. For instance (assuming that the directory "HereWeStart", where your relative path is starting, is the first occurrence of that string in absolutePath) you could go as follows.
String absolutePath = #"c:\beep\boop\HereWeStart\hopp.gif";
int relativePathStartIndex = absolutePath.IndexOf("HereWeStart");
String relativePath = absolutePath.Substring(relativePathStartIndex);
Also, your question begs an other question. I'd like to know how you're obtaining the absolute path. Perhaps there's an even more clever way to avoid the hustle all together?
EDIT
You could also try the following approach. Forget the Directory class giving you an absolute path. Go for the relative path straight off. I'm assuming that all the files you're attempting to remove are in the same directory. If not, you'll need to add some more lines but we'll cross that bridge when we get there.
Don't forget to mark an answer as green-checked (or explain what's missing or improvable still).
String
deletableTarget = #"\images\image1.jpeg",
hereWeAre = Environment.CurrentDirectory;
MessageBox.Show("The taget path is:\n" + hereWeAre + deletableTarget);
try
{ File.Delete(hereWeAre + deletableTarget); }
catch (Exception exception)
{ MessageBox.Show(exception.Message); }
Also, please note that I took the liberty of changing your exception handling. While yours is working, it's a better style to rely on the built-in messaging system. That way you'll get more professionally looking error messages. Not that we ever get any errors at run-time, right? ;)
I want to make an exact copy of some files, directories and subdirectories that are on my USB drive I:/ and want them to be in C:/backup (for example)
My USB drive has the following structure:
(just to know, this is an example, my drive has more files, directories and subdirectories)
courses/data_structures/db.sql
games/pc/pc-game.exe
exams/exam01.doc
Well, I am not sure how to start with this but my first idea is to get all the files doing this:
string[] files = Directory.GetFiles("I:");
The next step could be to make a loop and use File.Copy specifying the destination path:
string destinationPath = #"C:/backup";
foreach (string file in files)
{
File.Copy(file, destinationPath + "\\" + Path.GetFileName(file), true);
}
At this point everything works good but not as I wanted cause this doesn't replicate the folder structure. Also some errors happen like the following...
The first one happens because my PC configuration shows hidden files for every folder and my USB has an AUTORUN.INF hidden file that is not hidden anymore and the loop tries to copy it and in the process generates this exception:
Access to the path 'AUTORUN.INF' is denied.
The second one happens when some paths are too long and this generates the following exception:
The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the
directory name must be less than 248 characters.
So, I am not sure how to achieve this and validate each posible case of error. I would like to know if there is another way to do this and how (maybe some library) or something more simple like an implemented method with the following structure:
File.CopyDrive(driveLetter, destinationFolder)
(VB.NET answers will be accepted too).
Thanks in advance.
public static void Copy(string src, string dest)
{
// copy all files
foreach (string file in Directory.GetFiles(src))
{
try
{
File.Copy(file, Path.Combine(dest, Path.GetFileName(file)));
}
catch (PathTooLongException)
{
}
// catch any other exception that you want.
// List of possible exceptions here: http://msdn.microsoft.com/en-us/library/c6cfw35a.aspx
}
// go recursive on directories
foreach (string dir in Directory.GetDirectories(src))
{
// First create directory...
// Instead of new DirectoryInfo(dir).Name, you can use any other way to get the dir name,
// but not Path.GetDirectoryName, since it returns full dir name.
string destSubDir = Path.Combine(dest, new DirectoryInfo(dir).Name);
Directory.CreateDirectory(destSubDir);
// and then go recursive
Copy(dir, destSubDir);
}
}
And then you can call it:
Copy(#"I:\", #"C:\Backup");
Didn't have time to test it, but i hope you get the idea...
edit: in the code above, there are no checks like Directory.Exists and such, you might add those if the directory structure of some kind exists at destination path. And if you're trying to create some kind of simple sync app, then it gets a bit harder, as you need to delete or take other action on files/folders that don't exist anymore.
This generally starts with a recursive descent parser. Here is a good example: http://msdn.microsoft.com/en-us/library/bb762914.aspx
You might want to look into the overloaded CopyDirectory Class
CopyDirectory(String, String, UIOption, UICancelOption)
It will recurse through all of the subdirectories.
If you want a standalone application, I have written an application that copies from one selected directory to another, overwriting newer files and adding subdirectories as needed.
Just email me.