foreach file in folder, rename and save - c#

I have a simple foreach here where I am have got the folder location using the folderBrowserDialog tool and am now trying to go through each one of the files and replace certain characters within the file name.
I am getting an error which says it cannot find the file when it gets to this part of the code File.Move(_FileName, _NewFileName);
Can anyone shed any light on this? Would be much appreciated.
Thanks
foreach (FileInfo Files in Folder.GetFiles())
{
_FileName = Files.Name;
_NewFileName = _FileName.Replace(" ", "-").Replace(",", "-");
File.Move(_FileName, _NewFileName);
File.Delete(_FileName);
}

You need to use Files.FullName not Files.Name
FullName includes the full path (i.e. C:\test\foo.txt) which is needed by File.Move() and File.Delete() while Name is just the file name itself (i.e. foo.txt).
Edit:
#crashmstr is correct you should not do a string replace on the full path. All in all I'd probably do it this way:
foreach (FileInfo file in Folder.GetFiles())
{
string originalFileName = file.FullName;
string fileName = file.Name.Replace(" ", "-").Replace(",", "-");
string newFileName = Path.Combine(file.DirectoryName, fileName);
File.Move(originalFileName, newFileName);
}
Also keep in mind File.Delete() is not needed here, since the original file won't be there anymore after you move it.

You are trying to remove an item from the collection which you are iterating.
You can store the list of files that you get from Folder.GetFiles() into some variable and iterate over it with foreach.

Related

Copy files from directory recursively smallest first

I want to copy all files in a directory to a destination folder using Visual C# .NET version 3.5, which can be done pretty easily (taken from this answer):
private static void Copy(string sourceDir, string targetDir)
{
Directory.CreateDirectory(targetDir);
foreach (var file in Directory.GetFiles(sourceDir))
File.Copy(file, Path.Combine(targetDir, Path.GetFileName(file)));
foreach (var directory in Directory.GetDirectories(sourceDir))
Copy(directory, Path.Combine(targetDir, Path.GetFileName(directory)));
}
Now, there's one little problem here: I want it to sort all files smallest first, so if the source path is a removable drive, which gets plugged out after some time, it would still have most possible data copied. With upper algorithm, if it takes a directory containing big files first and continues with a directory containing many smaller ones afterwards, there is the chance that the user will plug his drive out while the software is still copying the big file, and nothing will stay on the drive except the incomplete big file.
My idea was to do multiple loops: First, every filepath would be put in a dictionary including its size, then this dictionary would get sorted, and then every file would be copied from source to destination (including folder creation).
I'm afraid this is not a very neat solution, since looping two times about the same just doesn't seem right to me. Also, I'm not sure if my dictionary can store that much information, if the source folder has got too many different files and subfolders.
Are there any better options to choose from?
You could use a simpler method based on the fact that you can get all the files in a directory subtree just asking for them without using recursion.
The missing piece of the problem is the file size. This information could be obtained using the DirectoryInfo class and the FileInfo class while the ordering is just a Linq instruction applied to the sequence of files as in the following example.
private static void Copy(string sourceDir, string targetDir)
{
DirectoryInfo di = new DirectoryInfo(sourceDir);
foreach (FileInfo fi in di.GetFiles("*.*", SearchOption.AllDirectories).OrderBy(d => d.Length))
{
string leftOver = fi.DirectoryName.Replace(sourceDir, "");
string destFolder = Path.Combine(targetDir, leftOver);
// Because the files are listed in order by size
// we could copy a file deep down in the subtree before the
// ones at the top of the sourceDir
// Luckily CreateDirectory doesn't throw if the directory exists
// and automatically creates all the intermediate folders required
Directory.CreateDirectory(destFolder);
// Just write the intended copy parameters as a proof of concept
Console.WriteLine($"{fi.Name} with size = {fi.Length} -> Copy from {fi.DirectoryName} to {Path.Combine(destFolder, fi.Name)}");
}
}
In this example I have changed the File.Copy method with a Console.WriteLine just to have a proof of concept without copying anything, but the substitution is trivial.
Notice also that it is better to use EnumerateFiles instead of GetFiles as explained in the MSDN documentation
I hope this helps!
First; get all files from the source directory, with recursion being optional. Then proceed to copy all files ordered by size to the target directory.
void CopyFiles(string sourceDir, string targetDir, bool recursive = false)
{
foreach (var file in GetFiles(sourceDir, recursive).OrderBy(f => f.Length))
{
var subDir = file.DirectoryName
.Replace(sourceDir, String.Empty)
.TrimStart(Path.DirectorySeparatorChar);
var fullTargetDir = Path.Combine(targetDir, subDir);
if (!Directory.Exists(fullTargetDir))
Directory.CreateDirectory(fullTargetDir);
file.CopyTo(Path.Combine(fullTargetDir, file.Name));
}
}
IEnumerable<FileInfo> GetFiles(string directory, bool recursive)
{
var files = new List<FileInfo>();
if (recursive)
{
foreach (var subDirectory in Directory.GetDirectories(directory))
files.AddRange(GetFiles(subDirectory, true));
}
foreach (var file in Directory.GetFiles(directory))
files.Add(new FileInfo(file));
return files;
}

Why dose File.Exists not work for exe's and shortcuts [duplicate]

I am using .NET 2.0 and Linq is out of question. I would like to check if file exists inside a directory without knowledge of the file extension.
I just need this logic done.
1.Check File exists in Directory using String Filename provided using search pattern leaving out the extension of the File
2.Get the Files if they exists and Databind to provide Download links.If file does not exist then start uploading the File.
Update:
Directory.GetFiles() and DirectoryInfo.GetFiles() indeed solves the part where in i check for File existence. As for the performance regarding FileInfo objects, these were only solution to my requirements of databinding to provide download links
DirectoryInfo root = new DirectoryInfo("your_directory_path");
FileInfo[] listfiles = root.GetFiles("dummy.*");
if (listfiles.Length > 0)
{
//File exists
foreach (FileInfo file in listfiles)
{
//Get Filename and link download here
}
}
else
{
//File does not exist
//Upload
}
Hope this works
To see if a file exists with that name, can you not just use..
However, Directory.GetFiles already includes the full path
string [] files = Directory.GetFiles(Path,"name*");
bool exists = files.Length > 0;
if ( exists)
{
//Get file info - assuming only one file here..
FileInfo fi = new FileInfo(files[0]);
//Or loop through all files
foreach (string s in files)
{
FileInfo fi = new FileInfo(s);
//Do something with fileinfo
}
}
You can use DirectoryInfo.GetFiles() to have a FileInfo[] instead of a String[].

C# absolute path with streamReader

I have an issue with the reading a file in C#
I have two different locations for .exe (both different) and reading the same .xml file. So when I give the path like this:
TextReader textReader = new StreamReader(#"../../../TrajectoryGen/obstacleList.xml");
it is able to read from one location ( which is 3 folders behind as used in the path) but not from another location (which is only 2 folders behind)
How do I fix this problem so that it works from both folders?
First way, this relies on you knowing one of the parent folder's names.
const string FILENAME = "obstacleList.xml";
const string FOLDER = "TrajectoryGen";
string path = Path.GetFullPath(System.Reflection.Assembly.GetExecutingAssembly().Location);
do
{
path = Path.GetDirectoryName(path);
} while (!Path.GetFileName(path).Equals(FOLDER, StringComparison.OrdinalIgnoreCase));
string filepath = String.Format("{0}{1}{2}", path, Path.DirectorySeparatorChar, FILENAME);
^^ You can also use a partial path in the FILENAME like the example below incase you need to into directories once you are at your "base" folder that you know the name of.
Second way blindly continues up directories
const string FILENAME = #"TrajectoryGen\obstacleList.xml";
string path = Path.GetFullPath(System.Reflection.Assembly.GetExecutingAssembly().Location);
string filepath;
do
{
path = Path.GetDirectoryName(path);
//pump
filepath = String.Format("{0}{1}{2}", path, Path.DirectorySeparatorChar, FILENAME);
} while (!File.Exists(filepath));
Both require "using System.IO;" and both have no error handling implemented and will throw NullReferenceException if the file/folder is not found.
I purposely used the do-while loop because the definition of path will included the executable name.

Find all files in a folder

I am looking to create a program that finds all files of a certain type on my desktop and places them into specific folders, for example, I would have all files with .txt into the Text folder.
Any ideas what the best way would be to accomplish this? Thanks.
I have tried this:
string startPath = #"%userprofile%/Desktop";
string[] oDirectories = Directory.GetDirectories(startPath, "");
Console.WriteLine(oDirectories.Length.ToString());
foreach (string oCurrent in oDirectories)
Console.WriteLine(oCurrent);
Console.ReadLine();
It was not successful in finding all of the files.
A lot of these answers won't actually work, having tried them myself. Give this a go:
string filepath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
DirectoryInfo d = new DirectoryInfo(filepath);
foreach (var file in d.GetFiles("*.txt"))
{
Directory.Move(file.FullName, filepath + "\\TextFiles\\" + file.Name);
}
It will move all .txt files on the desktop to the folder TextFiles.
First off; best practice would be to get the users Desktop folder with
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
Then you can find all the files with something like
string[] files = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories);
Note that with the above line you will find all files with a .txt extension in the Desktop folder of the logged in user AND all subfolders.
Then you could copy or move the files by enumerating the above collection like
// For copying...
foreach (string s in files)
{
File.Copy(s, "C:\newFolder\newFilename.txt");
}
// ... Or for moving
foreach (string s in files)
{
File.Move(s, "C:\newFolder\newFilename.txt");
}
Please note that you will have to include the filename in your Copy() (or Move()) operation. So you would have to find a way to determine the filename of at least the extension you are dealing with and not name all the files the same like what would happen in the above example.
With that in mind you could also check out the DirectoryInfo and FileInfo classes.
These work in similair ways, but you can get information about your path-/filenames, extensions, etc. more easily
Check out these for more info:
http://msdn.microsoft.com/en-us/library/system.io.directory.aspx
http://msdn.microsoft.com/en-us/library/ms143316.aspx
http://msdn.microsoft.com/en-us/library/system.io.file.aspx
You can try with Directory.GetFiles and fix your pattern
string[] files = Directory.GetFiles(#"c:\", "*.txt");
foreach (string file in files)
{
File.Copy(file, "....");
}
Or Move
foreach (string file in files)
{
File.Move(file, "....");
}
http://msdn.microsoft.com/en-us/library/wz42302f

How to Add file to the folder only if the file doesnt exist using C#

I have a template file in a folder " c:\template_folder".
At runtime, I will create a new folder " c:\new_folder" and wish to copy the template file to the new_folder only if the file doesnt exist.
description:
for the first time, I will copy the template file to the new_folder and rename it with username... so that after first time the loop finishes, i will have 8 excel files with username as the name of the each file.
for the second loop, if I have to copy the template file to new_folder and rename it to the username, if the file with the user name already exists, then it shouldnt copy the file to the folder.
I am addin the snippet of the code for reference.
foreach (FileInfo fi in templateFile)
{
string oldfilename = null;
string newfilename = null;
if (dir.Exists)
{
fi.CopyTo(Path.Combine(dir.ToString(), fi.Name));
FileInfo fileName = new FileInfo(fi.Name);
oldfilename = Path.Combine(dir.ToString(), fileName.ToString());
newfilename = Path.Combine(dir.ToString(), tempUserName + " " + "E" + tempUserID + " VIPv7.0.xls");
//if( !dir.ToString().Contains(newfilename))
foreach( FileInfo fileList in fileNames)
{
if (fileList.Exists == false)
File.Move(oldfilename, newfilename);
}
}
}
please help me in working this.
thanks
ramm
To conditionally move a file only if it doesn't already exist you would do it like this:
if (!File.Exists(newfilename))
{
File.Move(oldfilename, newfilename);
}
Your code snippet confuses me, so I hope I've answered your question correctly. If I'm missing something please let me know.
Your code doesn't seem correct to me (it doesn't compile), but you can check if a file exists by calling File.Exists(filename), so:
foreach( FileInfo fileList in fileNames)
{
if (!File.Exists(newfilname))
File.Move(oldfilename, newfilename);
}
You want to use File.Exists(path) instead of the commented out line to check if the file exists

Categories