Creating unique files in another directory - c#

Currently i am taking in multiple .txt files from a directory i have specified (sourceDirectory). I am generating new .csv files with the same name as the .txt files - one .csv file for each .txt file.
However i want to generate these new files in another directory which i have specified (directoryPath). If i run my program once it creates these files in the initial directory, however if i run my program again it now generates the files in the destination directory.
The following is my code where i complete the above:
static void Main(string[] args)
{
string sourceDirectory = #"C:directoryWhereTXTFilesAre";
var txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.txt", SearchOption.AllDirectories);
foreach (string currentFile in txtFiles)
{
readFile(currentFile);
}
string directoryPath = #"C:\destinationForCSVFiles";
}
I then create the new .csv files name based on the original .txt file like this:
static FileStream CreateFileWithUniqueName(string folder, string fileName, int maxAttempts = 1024)
{
var fileBase = Path.GetFileNameWithoutExtension(fileName);
var ext = Path.GetExtension(fileName);
// build hash set of filenames for performance
var files = new HashSet<string> (Directory.GetFiles(folder));
for (var index = 0; index < maxAttempts; index++)
{
// first try with the original filename, else try incrementally adding an index
var name = (index == 0)
? fileName
: String.Format("{0} ({1}){2}", fileBase, index, ext);
// check if exists
var fullPath = Path.Combine(folder, name);
string CSVfileName = Path.ChangeExtension(fullPath, ".csv");
if (files.Contains(CSVfileName))
continue;
// try to create the file
try
{
return new FileStream(CSVfileName, FileMode.CreateNew, FileAccess.Write);
}
catch (DirectoryNotFoundException) { throw; }
catch (DriveNotFoundException) { throw; }
catch (IOException)
{
}
}
I don't see why it's creating the .csv files initially in the same directory that the .txt files are in and then second time i run my code it creates them in the directoryPath.
Desired output: sourceDirectory left as it is with only .txt files and directoryPath to hold the .csv files.
The only other place i call CreateFileWithUniqueName is within my readFile method, the code is below:
using (var stream = CreateFileWithUniqueName(#"C:destinationFilePath", currentFile))
{
Console.WriteLine("Created \"" + stream.Name + "\"");
newFileName = stream.Name;
Globals.CleanedFileName = newFileName;
}

It seems that you are passing the full filename of the source file. This confuses the Path.Combine inside the CreateFileWithUniqueFilename because you are falling in this subtle remarks found on the documentation of Path.Combine
paths should be an array of the parts of the path to combine. If the
one of the subsequent paths is an absolute path, then the combine
operation resets starting with that absolute path, discarding all
previous combined paths.
You can fix it easily with
using (var stream = CreateFileWithUniqueName(#"C:\destinationFilePath",
Path.GetFileName(currentFile)))
{
Console.WriteLine("Created \"" + stream.Name + "\"");
newFileName = stream.Name;
Globals.CleanedFileName = newFileName;
}
Or better extract the filename without path inside the CreateFileWithUniqueName
static FileStream CreateFileWithUniqueName(string folder, string fileName, int maxAttempts = 1024)
{
var fileBase = Path.GetFileName(fileName);
fileBase = Path.GetFileNameWithoutExtension(fileBase);
var ext = Path.GetExtension(fileBase);
also, you should build your CSVfileName using the cleaned filename
var name = (index == 0)
? String.Format("{0}{1}", fileBase, ext);
: String.Format("{0} ({1}){2}", fileBase, index, ext);
var fullPath = Path.Combine(folder, name);
string CSVfileName = Path.ChangeExtension(fullPath, ".csv");
if (files.Contains(CSVfileName))
continue;

Related

How to remove last characters from a string

So I am writing a C# program which combines several text files into one and saves them as a combined text file. One issue I am having, I have a textfield which selects the intended folder the save the compiled reciept, however when selecting the desired folder, it generates a file name to the text box, the filename follwing the final / must be erased every time for the save function to work properly. I am wondering, how to remove all text after the final letter before the last / in the file directory?
Here is the code:
private void RecieptDisplayed_TextChanged(object sender, EventArgs e)
{
try
{
string[] fileAry = Directory.GetFiles(RecieptSelect.Text);
string input = RecieptSelect.Text;
int index = input.LastIndexOf("/");
if (index >= 0)
input = input.Substring(0, index);
MessageBox.Show("Reciepts being processed : " + index);
using (TextWriter tw = new StreamWriter(savefileas.Text + "RecieptsCombined.txt", true))
{
foreach (string filePath in fileAry)
{
using (TextReader tr = new StreamReader(filePath))
{
tw.WriteLine("Reciept for: " + " " + filePath + tr.ReadToEnd()) ;
tr.Close();
tr.Dispose();
}
MessageBox.Show("File Processed : " + filePath);
}
tw.Close();
tw.Dispose();
}
}
You have a string like
var fullpath = #"C:\temp\myfile.txt";
You can use:
var dir = Path.GetDirectoryName(fullpath);
To get
c:\temp
Note that if the path ends with a slash it doesn't remove it before "going up a directory" so c:\temp\ becomes c:\temp. Try to keep your paths free of trailing slashes
Try to always use the Path class when manipulating string that are paths. It has a whole load of useful methods (this isn't an exhaustive list but the ones I use most) like:
GetFileName
GetFileNameWithoutExtension
GetExtension
ChangeExtension
Combine
This last one builds paths, eg:
Path.Combine("c:", "temp", "myfile.txt");
It knows the different operating systems it runs on and builds paths appropriately - if you're using net core on Linux it uses "/" instead of "\" for example. full docs here
Construct a FileInfo object from the string and then use DirectoryName or Directory.
Also, do not concatenate strings to get a file name, use Path.Combine instead.
You are looking for Directory name from given path, you can use existing function to get the directory name, Path.GetDirectoryName()
using System.IO;
...
//Get the directory name
var directoryName = Path.GetDirectoryName(savefileas.Text);
using (TextWriter tw = new StreamWriter(Path.Combine(directoryName, "RecieptsCombined.txt"), true))
{
foreach (string filePath in fileAry)
{
using (TextReader tr = new StreamReader(filePath))
{
tw.WriteLine("Reciept for: " + " " + filePath + tr.ReadToEnd()) ;
tr.Close();
tr.Dispose();
}
MessageBox.Show("File Processed : " + filePath);
}
tw.Close();
tw.Dispose();
}

Delete specific line from a text file which i don't have the name

i need to find and delete all lines wich contain the word "recto",
i did search in stackoverflow forum, but all what i found is do that (delete the line) using path (Directory & FileName).
in my case i want to delete the line contain "recto" in all fils with specific extention (*.txt) in the directory.
thanks for help
here is my code so far
string sourceDir = #"C:\SRCE\";
string destinDir = #"C:\DIST\";
string[] files = Directory.GetFiles(sourceDir);
foreach (string file in files)
{
using (StreamReader sr_ = new StreamReader
(sourceDir + Path.GetFileName(file)))
{
string line = sr_.ReadLine();
if (line.Contains("recto"))
{
File.Copy(file, destinDir + Path.GetFileName(file));
string holdName = sourceDir + Path.GetFileName(file);
}
sr_.DiscardBufferedData();
sr_.Close();
}
}
}
You can try something like this. You were only identifying the files with the word but not making any try to remove it. At the end, you were copying the files that included the word "recto"
string sourceDir = #"C:\SRCE\";
string destinDir = #"C:\DIST\";
string[] files = Directory.GetFiles(sourceDir);
foreach (string file in files)
{
using (StreamReader sr_ = new StreamReader
(sourceDir + Path.GetFileName(file)))
{
string res = string.Empty;
while(!sr_.EndOfStream)
{
var l = sr_.ReadLine();
if (l.Contains("recto"))
{
continue;
}
res += l + Environment.NewLine;
}
var streamWriter = File.CreateText(destinDir + Path.GetFileName(file));
streamWriter.Write(res);
streamWriter.Flush();
streamWriter.Close();
}
}
If the files are not really big you can simplify a lot your code reading all lines in memory, processing the lines with Linq and then rewriting the files
string sourceDir = #"C:\SRCE\";
string destinDir = #"C:\DIST\";
string[] files = Directory.GetFiles(sourceDir);
foreach (string file in files)
{
var lines = File.ReadLines(file);
var result = lines.Where(x => x != "recto").ToArray();
File.WriteAllLines(Path.Combine(destinDir, Path.GetFileName(file)), result);
}

how to get multiple files path in an array

i want to upload multiple pdf files in one file upload control in asp.net and then merg it ,
this is already done when i pass static path and file name
how to do that dynamically
my code is here
if (FileUpload1.HasFile)
{
try
{
HttpFileCollection uploadedVideoFiles = Request.Files;
// Get the HttpFileCollection
for (int i = 0; i < uploadedVideoFiles.Count; i++)
{
HttpPostedFile hpfiles = uploadedVideoFiles[i];
string fname = Path.GetFileName(hpfiles.FileName);
if (hpfiles.ContentLength > 0)
{
hpfiles.SaveAs(Server.MapPath("~/Images/") + Path.GetFileName(hpfiles.FileName));
hpfiles.SaveAs(Server.MapPath(Path.Combine(#"~/Images/", fname)));
string filepath = Server.MapPath(#"~/Images/");
string path = filepath + fname;
}
}
String[] files = #"C:\ENROLLDOCS\A1.pdf,C:\ENROLLDOCS\A#.pdf".Split(',');
MergeFiles(#"C:\ENROLLDOCS\New1.pdf", files);// merg is a method which merg 2 or more than 2 documents
}
catch (Exception ex)
{
Label1.Text = "The file could not be uploaded. The following error occured: " + ex.Message;
}
}
You will need to collect values of path in a List<string> and then pass the result to MergeFiles().
I don't quite follow your code (you'll need to clean it up a bit), but what you need is basically this:
var fileNames =
uploadedVideoFiles.
Select(uvf => {
var fileName = Path.GetFileName(hpfiles.FileName);
var destinatonPath = Path.Combine(Server.MapPath("~/images"), fileName);
uvf.SaveAs(destinatonPath);
return destinationPath;
}).
ToArray();
MergeFiles(#"C:\ENROLLDOCS\New1.pdf", fileNames);
Beware of duplicating file names in ~/images, though.

Versioning file name and saving it to different location

After the else block Path.Combine method combines every part and gives the file name when Console.WriteLine(result); is used. But it doesn't actually create the file with that name.
I want to get the EmployeeDetails.txt file, make a version of it (i.e. renaming the filename) and saves it to C:\Hitory folder.
How to achieve that?
Using File.Move throws FileNotFoundexception
void ModRec()
{
string filename = #"C:\Current\EmployeeDetails.txt";
string current = #"C:\Current\";
string history = #"C:\History\";
FileInfo fileinfo = new FileInfo(filename);
if (fileinfo.Exists)
{
if (!Directory.Exists(history))
{
Directory.CreateDirectory(history);
}
}
else
{
Console.WriteLine("\t\t\tFile doesn't exist!");
Console.ReadLine();
Menu1();
}
var extension = Path.GetExtension(filename);
var fileNamePart = Path.GetFileNameWithoutExtension(filename);
var path = Path.GetDirectoryName(filename);
var version = 0;
string result;
do
{
version++;
result = Path.Combine(path, fileNamePart + "_" + version + extension);
}
while (File.Exists(result));
//File.Move(current, history);
}
Your loop at the end needs to change slightly, because
result = Path.Combine(path, fileNamePart + "_" + version + extension);
is looking in the directory where the file already is, rather than in the history directory where you want it to be, so you'll be scanning for duplicates in the wrong location. The Path.Combine therefore needs to reference the value of history:
result = Path.Combine(history, fileNamePart + "_" + version + extension);
Secondly, you cannot use Move to move a file to a directory in the same way that you can from the command line, you need to specify the two parameters as filenames, so
File.Move(current, history);
becomes
File.Move(filename, result);
The resulting code at the end of your method should therefore look like this:
do
{
version++;
result = Path.Combine(history, fileNamePart + "_" + version + extension);
}
while (File.Exists(result));
File.Move(filename, result);
Incidentally, where you test whether the file already exists, you simply call Menu1 and then carry on. Can you guarantee that that will ensure that the next thing that the user does will create a valid file? I'm guessing that it most likely cannot guarantee that, so you should exit your method at that point, or perhaps put the remainder of the body inside the fileinfo.Exists block.
That leaves the desirability of invoking a menu from inside this method, but that's a design question outside of the scope of what you've asked here.
Try this instead:
void ModRec()
{
string filename = #"C:\Current\EmployeeDetails.txt";
string current = #"C:\Current\";
string history = #"C:\History\";
FileInfo fileinfo = new FileInfo(filename);
if (fileinfo.Exists)
{
if (!Directory.Exists(history))
{
Directory.CreateDirectory(history);
}
}
else
{
Console.WriteLine("\t\t\tFile doesn't exist!");
Console.ReadLine();
Menu1();
}
var extension = Path.GetExtension(filename);
var fileNamePart = Path.GetFileNameWithoutExtension(filename);
var path = Path.GetDirectoryName(filename);
var version = 0;
string result;
do
{
version++;
result = Path.Combine(history, fileNamePart + "_" + version + extension);
}
while (File.Exists(result));
File.Move(filename, result);
}
Path.Combine() does not touch filesystem at all. No files/folders would be ever crated.
Try File.Move(filename, history);. That is, instead of current, which is a directory, move the file (assuming filename is a full path).

Copy file, overwrite if newer

In C#.NET, How to copy a file to another location, overwriting the existing file if the source file is newer than the existing file (have a later "Modified date"), and doing noting if the source file is older?
You can use the FileInfo class and it's properties and methods:
FileInfo file = new FileInfo(path);
string destDir = #"C:\SomeDirectory";
FileInfo destFile = new FileInfo(Path.Combine(destDir, file.Name));
if (destFile.Exists)
{
if (file.LastWriteTime > destFile.LastWriteTime)
{
// now you can safely overwrite it
file.CopyTo(destFile.FullName, true);
}
}
You can use the FileInfo class:
FileInfo infoOld = new FileInfo("C:\\old.txt");
FileInfo infoNew = new FileInfo("C:\\new.txt");
if (infoNew.LastWriteTime > infoOld.LastWriteTime)
{
File.Copy(source path,destination path, true) ;
}
Here is my take on the answer: Copies not moves folder contents. If the target does not exist the code is clearer to read. Technically, creating a fileinfo for a non existent file will have a LastWriteTime of DateTime.Min so it would copy but falls a little short on readability. I hope this tested code helps someone.
**EDIT: I have updated my source to be much more flexable. Because it was based on this thread I have posted the update here. When using masks subdirs are not created if the subfolder does not contain matched files. Certainly a more robust error handler is in your future. :)
public void CopyFolderContents(string sourceFolder, string destinationFolder)
{
CopyFolderContents(sourceFolder, destinationFolder, "*.*", false, false);
}
public void CopyFolderContents(string sourceFolder, string destinationFolder, string mask)
{
CopyFolderContents(sourceFolder, destinationFolder, mask, false, false);
}
public void CopyFolderContents(string sourceFolder, string destinationFolder, string mask, Boolean createFolders, Boolean recurseFolders)
{
try
{
if (!sourceFolder.EndsWith(#"\")){ sourceFolder += #"\"; }
if (!destinationFolder.EndsWith(#"\")){ destinationFolder += #"\"; }
var exDir = sourceFolder;
var dir = new DirectoryInfo(exDir);
SearchOption so = (recurseFolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
foreach (string sourceFile in Directory.GetFiles(dir.ToString(), mask, so))
{
FileInfo srcFile = new FileInfo(sourceFile);
string srcFileName = srcFile.Name;
// Create a destination that matches the source structure
FileInfo destFile = new FileInfo(destinationFolder + srcFile.FullName.Replace(sourceFolder, ""));
if (!Directory.Exists(destFile.DirectoryName ) && createFolders)
{
Directory.CreateDirectory(destFile.DirectoryName);
}
if (srcFile.LastWriteTime > destFile.LastWriteTime || !destFile.Exists)
{
File.Copy(srcFile.FullName, destFile.FullName, true);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + Environment.NewLine + ex.StackTrace);
}
}
In a batch file, this will work:
XCopy "c:\my directory\source.ext" "c:\my other directory\dest.ext" /d

Categories