I have a directory filled with multiple excel files that I would like to rename. The names all have leading integers and a '-'. For example: 0123456-Test_01. I would like to rename all of the files within this directory by removing this prefix. 0123456-Test_01 should just be Test_01. I can rename a hard coded instance of a string, but am having trouble getting the files and renaming all of them.
My code is below. Any help is appreciated, as I am clearly new to C#.
public static void Main()
{
//Successfully splits hardcoded string
var temp = "0005689-Test_01".Split('-');
Console.WriteLine(temp[1]);
Console.ReadLine();
//Unsuccessful renaming of all files within directory
List<string> files = System.IO.Directory.GetFiles(#"C:\Users\acars\Desktop\B", "*").ToList();
System.IO.File.Move(#"C:\Users\acars\Desktop\B\", #"C:\Users\acars\Desktop\B\".Split('-'));
foreach (string file in files)
{
var temp = files.Split('-');
return temp[1];
};
}
There are some errors to fix in your code.
The first one is the wrong usage of the variable files. This is the full list of files, not the single file that you want to split and move. As explained comments you should use the iterator result stored in the variable file
The most important problem is the fact that the File.Move method throws an exception if the destination file exists. After removing the first part of your filename string, you cannot be sure that the resulting name is unique in your directory.
So a check for the existance of the file before the Move is mandatory.
Finally, it is better use Directory.EnumerateFiles because this method allows you to start the execution of your moving code without loading first all filenames in memory in a list. (In a folder full of files this could make a noticeable difference in speed)
public static void Main()
{
string workPath = #"C:\Users\acars\Desktop\B";
foreach (string file in Directory.EnumerateFiles(workPath)
{
string[] temp = file.Split('-');
if(temp.Length > 1)
{
string newName = Path.Combine(workPath, temp[1]);
if(!File.Exists(newName))
File.Move(file, newName);
}
}
}
Pay also attention to the comment below from CodeNotFound. You are using an hard-coded path so the problem actually doesn't exist, but if the directory contains a single "-" in its name then you should use something like this to get the last element in the splitted array
string newName = Path.Combine(workPath, temp[temp.Length-1]);
Related
I have an array of filepaths in a directory and I'm trying to move certain files based on alphabet.
string[] filePaths = Directory.GetFiles(#"C:\user\desktop\folder", "*.txt");
foreach (var file in filePaths)
{
if (file.StartsWith("A"))
{
//Move file
The obvious problem is that file.StartWith is pulling the entire filepath (C:\user\desktop\folder\Albert.txt) Which doesn't start with 'A'
So what would be the best way to just target the start of the actual file?
Thanks in advance.
I got it working with Path.GetFileName as per the suggestion by #Jimi
What about this code
var dir = new DirectoryInfo(#"C:\user\desktop\folder");
var files = dir.GetFiles();
foreach (var file in files)
{
if(file.Name.StartsWith("A"))
{
//Move file
You say you're looking to move files by alphabet- if you mean to put files into a folder whose name is the same as the first char of the filename then perhaps:
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //don't hard code the path to the desktop
var root = Path.Combine(desktop, "foldernamehere"); //use path.combine to build paths
foreach(var f in directory.EnumerateFiles(root, "*.txt")){ //prefer EnumerateFiles over GetFiles
var filename = Path.GetFileName(f);
var dest = Path.Combine(root, filename.Remove(1));
Directory.CreateDirectory(dest); //safe to call even if exists, ensures exists
File.Move(f, Path.Combine(dest, filename));
}
See comments for more info
If you have a string that represents a full filename (or directory name), and you want the name without the directory, consider to use Path.GetFileName
string fullFileName = "C:\user\desktop\folder\Albert.txt";
string fileName = Path.GetDirectoryName(fullFileName);
fileName will be "Albert.txt"
With this in mind, your query will be easy:
IEnumerable<string> fullFileNames = ...
char startChar = 'A';
IEnumerable<string> fileNamesThatStartWithStartChar = fullFileNames
.Where(fileName => Path.GetDirectoryName(fileName).StartsWitch(startChar));
In words: from every fileName in the sequence of fullFileName, take the fileName without the directory information. Keep the fileName if this "fileName without directory information" starts with the startChar.
Note: StartsWitch(char) is case sensitive. If you want to check case insensitive, use String.StartsWitch(string, stringComparison)
There's room for improvement!
If you think that there might be a chance that you won't be using all information of all files, consider to use Directory.EnymerateFiles instead of GetFiles. This way, if at the end of your LINQ you decide to use only 3 of the fetched files (or worse: FirstOrDefault(), or Any()), you won't have fetched all files.
I need to copy files from one folder to another but only if their file name is also in a text file. The text file is set up like so
file1.jpg
file2.jpg
file3.jpg
etc
There are around one-million files to copy. I'm using C#.
What would the best way to go about this be? I'm not sure if I should first read all the file names from the text file and put them in to a list then possibly convert the list in to an array then maybe use the array somehow? Or maybe there's a better way to go about it?
I know how to read and write to files and how to copy from one source destination to another. I don't know how to filter out specific files when copying from one source destination to another though.
Any help is greatly appreciated.
Thank you.
The following code will help you the process you want
string source = #"C:\SourcePath\";
string destination = #"C:\DestinationPath\";
string[] strFiles = File.ReadAllText(#"C:\Filename.txt").Split(' ');
for (int i = 0; i < strFiles.Length; i++)
{
File.Copy(source + strFiles[i], destination + strFiles[i]);
}
If the text file is one line with million files name. Use this
string from = #"c:\from" , to =#"d:\to"; // source and destination
StreamReader file = new StreamReader(#"c:\list.txt"); // your files list
string total=file.ReadLine();
string[] tobecopied = total.Split(' ');
foreach(string fil in tobecopied)
{
if(File.Exists(from+#"\"+fil))
{
File.Copy(from+#"\"+fil,to+#"\"+fil);
}
else
{
MessageBox.Show(fil+"Not found ");
}
}
But if the text file have 1 line per 1 file , for example
FIle1.exe
File2.exe
use this
string from = #"c:\from" , to =#"d:\to"; // source and destination
StreamReader file = new StreamReader(#"c:\list.txt"); // your files list
string total="";
string temp="";
while((temp=file.ReadLine())!=null)
{
total+=temp+" ";
}
string[] tobecopied = total.Split(' ');
foreach(string fil in tobecopied)
{
if(File.Exists(from+#"\"+fil))
{
File.Copy(from+#"\"+fil,to+#"\"+fil);
}
else
{
MessageBox.Show(fil+"Not found ");
}
}
These ways also check for file existance.
Hope it works. If someone see error please edit it.
public int RunStageData(string rootDirectory, stringdataFolder)
{
string[] files = new string[] { };
files = Directory.GetFiles(rootDirectory + dataFolder);
string[] tableOrder = new string[] { };
tableOrder = Directory.GetFiles(#"C:\_projects\ExampleProject\src", "TableOrder.txt");
System.IO.StreamReader tableOrderReader = new System.IO.StreamReader(tableOrder[0]);
for (int count = 0; count < files.Length; count++)
{
string currentTableName =tableOrderReader.ReadLine();
//files[count] = Directory.GetFiles(#"C:\_projects\ExampleProject\src", currentTableName);
}
}
Hi everyone, sorry if my code is a bit sloppy. I'm having an issue primarily with the line I have commented out. So basically what I'm trying to do here is to populate a string array of file names based on the ordering of these names in a txt file. So I read the first line from the txt file, then retrieve the name of that file in the directory(assuming it exists) and put it in the first spot of the array, then move on.
For Example if the txt file had these words in the following order:
Dog
Sheep
Cat
I would want the array to have Dog first, then Sheep, then Cat. My issue is that the line that I have commented gives me an error that says "Error 41 Cannot implicitly convert type 'string[]' to 'string'"
I'm guessing the reason for this is that Directory.GetFiles has the possibility of returning multiple files. So, is there another method I could use to achieve the results I'm looking for? Thank you.
I am assuming you want the contents of the file (if you just want the file name and need to check for existance a different solution will be required).
files[count] = File.ReadAllText(Path.Combine(#"C:\_projects\ExampleProject\src", currentTableName));
And a couple other suggestions:
Don't initialize your variables with bogus data, = new string[] {} can be removed
Don't use count as an indexer, it is confusing (count is a property of the array after all)
Use Path.Combine when joining paths. It is much easier as it handles the \ for you.
From your question:
So basically what I'm trying to do here is to populate a string array
of file names based on the ordering of these names in a txt file. So I
read the first line from the txt file, then retrieve the name of that
file in the directory(assuming it exists) and put it in the first spot
of the array, then move on.
So, your TableOrder.txt already contains the files in the correct order, thus you can do:
string[] files = File.ReadAllLines(#"C:\_projects\ExampleProject\src\TableOrder.txt")
If your array files contains only paths, you can do it as:
path = #"C:\_projects\ExampleProject\src\" + currentTableName;
If(File.Exists(path))
{
files[count] = path;
}
I have two lists containing paths to a directory of music files and I want to determine which of these files are stored on both lists and which are only stored on one. The problem lies in that the format of the paths differ between the two lists.
Format example:
List1: file://localhost//FILE/Musik/30%20Seconds%20To%20Mars.mp3
List2: \\FILE\Musik\30 Seconds To Mars.mp3
How do I go about comparing these two file paths and matching them to the same source?
The answer depends on your notion of "same file". If you merely want to check if the file is equal, but not the very same file, you could simply generate a hash over the file's content and compare that. If the hashes are equal (please use a strong hash, like SHA-256), you can be confident that the files are also. Likewise you could of course also compare the files byte by byte.
If you really want to figure that the two files are actually the same file, i.e. just addressed via different means (like file-URL or UNC path), you have a little more work to do.
First you need to find out the true file system path for each of the addresses. For example, you need to find the file system path behind the UNC path and/or file-URL (which typically is the URL itself). In the case of UNC paths, that are shares on a remote computer, you might even be able to do so.
Also, even if you have the local path figured out somehow, you also need to deal with different redirection mechanisms for local paths (on Windows junctions/reparse points/links; on UNIX symbolic or hard links). For example, you could have a share using file system link as source, while the file URL uses the true source path. So to the casual observer they still look like different files.
Having all that said, the "algorithm" would be something like this:
Figure out the source path for the URLs, UNC paths/shares, etc. you have
Figure out the local source path from those paths (considering links/junctions, subst.exe, etc.)
Normalize those paths, if necessary (i.e. a/b/../c is actually a/c)
Compare the resulting paths.
I think the best way to do it is by temporarily converting one of the paths to the other one's format. I would suggest you change the first to match the second.
string List1 = "file://localhost//FILE/Musik/30%20Seconds%20To%20Mars.mp3"
string List2 = "\\FILE\Musik\30 Seconds To Mars.mp3"
I would recommend you use Replace()-method.
Get rid of "file://localhost":
var tempStr = List1.Replace("file://localhost", "");
Change all '%20' into spaces:
tempStr = List1.Replace("%20", " ");
Change all '/' into '\':
tempStr = List1.Replace("/", "\");
VoilĂ ! To strings in matching format!
Use python: you can easily compare the two files like this
>>> import filecmp
>>> filecmp.cmp('file1.txt', 'file1.txt')
True
>>> filecmp.cmp('file1.txt', 'file2.txt')
False
to open the files with the file:// syntax use URLLIB
>>> import urllib
>>> file1 = urllib.urlopen('file://localhost/tmp/test')
for the normal files path use the standard file open.
>>> file2 = open('/pathtofile','r')
I agree completely with Christian, you should re-think structure of the lists, but the below should get you going.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication5
{
class Program
{
public static List<string> SanitiseList(List<string> list)
{
List<string> sanitisedList = new List<string>();
foreach (string filename in list)
{
String sanitisedFilename = String.Empty;
if (!String.IsNullOrEmpty(filename))
{
sanitisedFilename = filename;
// get rid of the encoding
sanitisedFilename = Uri.UnescapeDataString(sanitisedFilename);
// first of all change all back-slahses to forward slashes
sanitisedFilename = sanitisedFilename.Replace(#"\", #"/");
// if we have two back-slashes at the beginning assume its localhsot
if (sanitisedFilename.Substring(0, 2) == "//")
{
// remove these first double slashes and stick in localhost
sanitisedFilename = sanitisedFilename.TrimStart('/');
sanitisedFilename = sanitisedFilename = "//localhost" + "/" + sanitisedFilename;
}
// remove file
sanitisedFilename = sanitisedFilename.Replace(#"file://", "//");
// remove double back-slashes
sanitisedFilename = sanitisedFilename.Replace("\\", #"\");
// remove double forward-slashes (but not the first two)
sanitisedFilename = sanitisedFilename.Substring(0,2) + sanitisedFilename.Substring(2, sanitisedFilename.Length - 2).Replace("//", #"/");
}
if (!String.IsNullOrEmpty(sanitisedFilename))
{
sanitisedList.Add(sanitisedFilename);
}
}
return sanitisedList;
}
static void Main(string[] args)
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
listA.Add("file://localhost//FILE/Musik/BritneySpears.mp3");
listA.Add("file://localhost//FILE/Musik/30%20Seconds%20To%20Mars.mp3");
listB.Add("file://localhost//FILE/Musik/120%20Seconds%20To%20Mars.mp3");
listB.Add(#"\\FILE\Musik\30 Seconds To Mars.mp3");
listB.Add(#"\\FILE\Musik\5 Seconds To Mars.mp3");
listA = SanitiseList(listA);
listB = SanitiseList(listB);
List<string> missingFromA = listB.Except(listA).ToList();
List<string> missingFromB = listA.Except(listB).ToList();
}
}
}
I have a C# app that uses the search functions to find all files in a directory, then shows them in a list. I need to be able to filter the files based on extension (possible using the search function) and directory (eg, block any in the "test" or "debug" directories from showing up).
My current code is something like:
Regex filter = new Regex(#"^docs\(?!debug\)(?'display'.*)\.(txt|rtf)");
String[] filelist = Directory.GetFiles("docs\\", "*", SearchOption.AllDirectories);
foreach ( String file in filelist )
{
Match m = filter.Match(file);
if ( m.Success )
{
listControl.Items.Add(m.Groups["display"]);
}
}
(that's somewhat simplified and consolidated, the actual regex is created from a string read from a file and I do more error checking in between.)
I need to be able to pick out a section (usually a relative path and filename) to be used as the display name, while ignoring any files with a particular foldername as a section of their path. For example, for these files, only ones with +s should match:
+ docs\info.txt
- docs\data.dat
- docs\debug\info.txt
+ docs\world\info.txt
+ docs\world\pictures.rtf
- docs\world\debug\symbols.rtf
My regex works for most of those, except I'm not sure how to make it fail on the last file. Any suggestions on how to make this work?
Try Directory.GetFiles. This should do what you want.
Example:
// Only get files that end in ".txt"
string[] dirs = Directory.GetFiles(#"c:\", "*.txt", SearchOption.AllDirectories);
Console.WriteLine("The number of files ending with .txt is {0}.", dirs.Length);
foreach (string dir in dirs)
{
Console.WriteLine(dir);
}
^docs\\(?:(?!\bdebug\\).)*\.(?:txt|rtf)$
will match a string that
starts with docs\,
does not contain debug\ anywhere (the \b anchor ensures that we match debug as an entire word), and
ends with .txt or .rtf.