How to read and update multiple files - c#

I have 10 txt files in Debug\Tests\Text\ (10 txt files). I need to write a program to open all 10 files and updated every single file. I'm not sure how to do it. Now, I'm actually reading the folder and getting the file name and storing the file name in an array. Below is my code:
private void getFilesName()
{
string[] fileArray = Directory.GetFiles(#"Tests\Text");
//looping through the folder and get the fileNames
for (int i = 0; i<fileArray.Length; i++)
{
MessageBox.Show(fileArray[i]); // I'm doing this is to double check i manage to get the file name.
}
}
After doing this, it do read all the text file name, but the challenge now is for me to access the filename and updating every file in it. I have also created another method just for updating the values in the txt files, below is the code:
private bool modifySQLFile()
{
string destFileName = #"Tests\Text\" // I need the fileName?
string[] fileTexts = File.ReadAllLines(destFileName);
int counter = 0;
//Processing the File
foreach(string line in fileTexts)
{
//only read those non-comments line
if(line.StartsWith("--") == false)
{
//Start to replace instances of Access ID
if(line.Contains(Variable) == true)
{
fileTexts[counter] = fileTexts[counter].Replace(Variable, textBox2.Text);
}
}
counter++;
}
//check if file exists in the backup folder
if(File.Exists("Tests\\Text\\file name "+ textBox1.Text +".sql") == true)
{
MessageBox.Show("This file already exist in the backup folder");
return false;
}
else
{
//update the file
File.WriteAllLines(destFileName, fileTexts);
File.Move(destFileName, "Tests\\Text\\file name"+ textBox1.Text +".sql");
MessageBox.Show("Completed");
return true;
}
}

Your problem seems to be passing the filename variable from the loop to the method.
In order to do what you want, add a parameter to the method:
private bool ModifySQLFile(string filename)
{
string[] fileTexts = File.ReadAllLines(filename);
// ...
}
Then call the method with this parameter:
for (int i = 0; i<fileArray.Length; i++)
{
ModifySQLFile(fileArray[i]);
}
But in general you really don't want to treat a formal language as plaintext like you do. It's very easy to break the SQL like that. What if the user wanted to replace the text "insert", or replaces something with "foo'bar"?

First, implement one (file) modification:
private bool modifySQLFile(String file) {
// given source file, let´s elaborate target file name
String targetFile = Path.Combine(
Path.GetDirectoryName(file),
String.Format("{0}{1}.sql",
Path.GetFileNameWithoutExtension(file),
textBox1.Text));
// In case you want a back up
//TODO: given source file name, elaborate back up file name
//String backUpFile = Path.Combine(...);
// Check (validate) before processing: do not override existing files
if (File.Exists(targetFile))
return false;
//TODO: what if back up file exists? Should we override it? skip?
// if line doesn't start with SQL commentary --
// and contains a variable, substitute the variable with its value
var target = File
.ReadLines(file)
.Select(line => (!line.StartsWith("--") && line.Contains(Variable))
? line.Replace(Variable, textBox2.Text)
: line);
// write modified above lines into file
File.WriteAllLines(targetFile, target);
// In case you want a back up
// Move file to backup
//File.Move(file, backUpFile);
return true;
}
Then call it in the loop:
// enumerate all the text files in the directory
var files = Directory
.EnumerateFiles("#"Tests\Text", "*.txt");
//TODO: you may want filter out some files with .Where
//.Where(file => ...);
// update all the files found above
foreach (var file in files) {
if (!modifySQLFile(file))
MessageBox.Show(String.Format("{0} already exist in the backup folder", file));
}
Please, do not do:
Use Magic values: what is #"Tests\Text\" within your modifySQLFile
Mix UI MessageBox.Show(...) and logic: modifySQLFile returns true or false and it's caller who can display message box.
Materialize when it's not required (Directory.GetFiles, File.ReadAllLines)

If you would like to edit the files in parallel. With threads you can parallelize work.
for (int i = 0; i < fileArray.Length; i++)
new Thread(UpdateFileThread).Start(fileArray[i]);
private void UpdateFileThread(object path)
{
string filePath = (string)path;
//ToDo: Edit file
}
In your case you would create 10 Threads. That solution works, but is a bad pattern if you have to deal with more than 10 files.

Below i have posted the real time code ,which i have used project
protected void btnSqlfinder_Click(object sender, EventArgs e)
{
//Defining the path of directory where all files saved
string filepath = # "D:\TPMS\App_Code\";
//get the all file names inside the directory
string[] files = Directory.GetFiles(filepath);
//loop through the files to search file one by one
for (int i = 0; i < files.Length; i++)
{
string sourcefilename = files[i];
StreamReader sr = File.OpenText(sourcefilename);
string sourceline = "";
int lineno = 0;
while ((sourceline = sr.ReadLine()) != null)
{
lineno++;
//defining the Keyword for search
if (sourceline.Contains("from"))
{
//append the result to multiline text box
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("into"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("set"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("delete"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
}
}
}
This code will fetch the multiple files in the given directory,and show the lines as per the keyword in a separate text.
But you can easily change as per your requirement,Kindly let me know your thoughts.
Thanks

Related

How to Search if a File Name exists in a text document?

I am making an app in C# where I am searching if the file exists in the text file or not. If it does not exist then, it would add it in the text file and then append it in a List. But, for some reason the list only takes one file and ends at that point. So, can someone help me with what is the problem in this foreach loop?
static void CheckNewFile()
{
string path_f = #"File_Address_where_Text_file_exists";
var new_file = new List<string>();
if (!File.Exists(path_f)) # Checking if the text file exists or not and then creating it
{
var myFile = File.Create(path_f);
myFile.Close();
}
DirectoryInfo hdDirectoryInWhichToSearch = new DirectoryInfo(#"File_Address_in_which_Files_need_to_be_searched");
FileInfo[] filesInDir = hdDirectoryInWhichToSearch.GetFiles("AC" + "*" + "*.*" + "AC"); # Format of the file to be searched
foreach (FileInfo foundFile in filesInDir) # foreach for the files in the directory
{
string fullName = foundFile.FullName;
int flag = 0;
var lines = File.ReadLines(path_f);
foreach (var line in lines) # Reading line by line and checking if the file exists in the text file before
{
if (String.Equals(line, fullName))
{
flag += 1;
break;
}
}
if (flag < 1)
{
if (new FileInfo(path_f).Length == 0) # File Address is appended in the File
{
//TextWriter tw = new StreamWriter(path_f);
//tw.WriteLine(fullName);
//tw.Close();
}
else
{
//using (var tw = new StreamWriter(path_f, true))
//{
// tw.WriteLine(fullName);
//}
}
new_file.Add(fullName.ToString()); # Adding File Address to the list
flag = 0;
break;
}
}
}
Remove the last break. It is causing the program flow to leave the enclosing foreach loop with the file names.
As the other poster mentioned, you're breaking out of your loop early in the if block.
However, there isn't really a need for the flag (or loop or if block) at all. Your method could be simplified greatly by using a little System.Linq and just using Directory to find the new files by comparing their paths to the contents of the input file.
For example:
static List<string> CheckForNewFiles(string filePath, string searchDir,
string searchPattern)
{
// Create file if it doesn't exist
if (!File.Exists(filePath)) using (File.Create(filePath)) ;
// Get list of files that match search pattern which aren't contained in our file
var newFiles = Directory
.GetFiles(searchDir, searchPattern)
.Where(match => !File.ReadLines(filePath).Contains(match))
.ToList();
// Add the new file paths to our file
File.AppendAllLines(filePath, newFiles);
// Return the list of new files (?)
return newFiles;
}
In use it migth look something like:
public static void Main()
{
Console.WriteLine("Checking for new files...");
var newFiles = CheckForNewFiles(#"c:\temp\paths.txt", #"c:\temp\temp", "*.png");
Console.WriteLine($"{newFiles.Count} files found since last search.");
if (newFiles.Any())
{
Console.WriteLine(" -> " + string.Join(Environment.NewLine + " -> ", newFiles));
}
Console.ReadLine();
}

how to alert the user on duplications in the moving file procces in a Web-Application

I have a source and destination path with the same folder and file names (source has some extra files). my question is when I have cut source locations files and folders and to paste the destination location
how to copied initially the extra files(destination not having files)?
how to through the error after paste the extra files "the folder and files already exist do you want to replace it" message?
after getting the response how can I move and delete the source files?
somebody can help me guys I am stuck with this logic nearly 2 days.
Note: am the beginner of the C# server side code.
thanks, advance. Hi All, thank you for your reply, I have written the same structure with #RezaNoei mentioned my code was
private void DirectoryCopy(string sourceDirName, string destDirName, bool replace, string action)
{
try
{
// Gets the subdirectories for the specified directory.
var dir = new DirectoryInfo(sourceDirName);
var dirs = dir.GetDirectories();
// If the destination directory doesn't exist, creates it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Gets the files in the directory and copy them to the new location.
var files = dir.GetFiles();
foreach (var file in files)
{
var oldPath = Path.Combine(sourceDirName, file.Name);
var temppath = Path.Combine(destDirName, file.Name);
var fileExist = File.Exists(temppath);
if (!fileExist)
{
if (action != "paste")
{
file.CopyTo(temppath, true);
}
else
{
File.Move(oldPath, temppath);
}
}
else if (fileExist && replace)
{
File.Delete(temppath);
if (action != "paste")
{
file.CopyTo(temppath, true);
}
else
{
File.Move(oldPath, temppath);
}
}
}
if (action == "paste")
{
DeleteDirectory(sourceDirName);
}
}
catch (Exception e)
{
throw e;
}
}
Use this Function:
Note: If you are developing a web-application and you want to alert this through Html, it doesn't help you. Please read the Next Section "For Web-Application"
Note2: this function doesn't check for inner folders. so if you have a nested path, we should write a recursive function.
public void Copy(string Source, string Destination)
{
string[] SourceFiles = System.IO.Directory.GetFiles(Source);
for (int i = 0; i < SourceFiles.Length; i++)
{
string DestinationFilePath = System.IO.Path.Combine(Destination, System.IO.Path.GetFileName(SourceFiles[i]));
if (System.IO.File.Exists(DestinationFilePath))
{
var DialogResult = MessageBox.Show($"File `{System.IO.Path.GetFileName(SourceFiles[i])}` Exists in the Destination. Are you want to overwrite this file ?", "File Exist !", MessageBoxButtons.YesNo);
if (DialogResult == DialogResult.Yes)
System.IO.File.Copy(SourceFiles[i], DestinationFilePath, true);
}
else
{
System.IO.File.Copy(SourceFiles[i], DestinationFilePath);
}
}
}
For Web-Application:
You actually need to interact with User. And it make our work more complicated than before.
You will Work with Session and you must keep track of this Operation. I don't know which technology are you using but you must but added these ones to Session:
1-1 **Destination Folder**
1-2 **List of Duplicated SourceFiles**
So:
Next Step is to copy non-duplicated files and Added Duplication on Session:
public void Copy(string Source, string Destination)
{
/// Set Session ....
Session["Destination"] = Destination;
List<string> DuplicatedFiles = new List<string>();
string[] SourceFiles = System.IO.Directory.GetFiles(Source);
for (int i = 0; i < SourceFiles.Length; i++)
{
string DestinationFilePath = System.IO.Path.Combine(Destination, System.IO.Path.GetFileName(SourceFiles[i]));
if (System.IO.File.Exists(DestinationFilePath))
{
// Add into Duplication List
DuplicatedFiles.Add(SourceFiles[i]);
}
else
{
System.IO.File.Copy(SourceFiles[i], DestinationFilePath);
}
}
/// Set Session .....
Session["DouplicatedFiles"] = DuplicatedFiles;
}
above code is psudo and the goal is Clear.
Next Step is to show the result of copying or duplications:
I don'n know how do you want to implement such a view for duplication errors and it will not the part of the answer. anyway you may want to let the user to choose the action on each files separately or whole of them at the same time.
depend on your preferences you will have an ActionMethod (In MVC) or something else in WebForm that will do these things:
(If user doesn't want replace the files, it's easy to forget the action)
public void CopyDuplications(bool Overwrite)
{
if (!Overwrite)
return "OK";
else
{
string Destination = Session["Destination"] as string;
var DuplicatedFiles = Session["DouplicatedFiles"] as List<string>();
for (int i = 0; i< DuplicatedFiles.Count; i++)
{
string DestinationFilePath = System.IO.Path.Combine(Destination, System.IO.Path.GetFileName(DuplicatedFiles[i]));
System.IO.File.Copy(DuplicatedFiles[i], DestinationFilePath, true);
}
}
}

How to create a copy of a file within a folder and get the name of the automatic copy C#?

In an application, the user may open saved files.
My goal is to check wether a file is already open, and offer the user the possibility to open it again only if a local copy is created, so that the same file cannot be modified at the same time.
The workflow would be as follows:
if (File.Exists(strFileName))
bCreateCopy = AlertBox.Display("File already open. Work on a copy?", true/false);
if (bCreateCopy == true)
{
strNewAutomaticFileName = createAutomaticFileName (sourceFile)
File.Copy(sourceFile, strNewAutomaticFileName );
}
Is there a method that does what I need in 'createAutomaticFileName()' ?
I was thinking of creating the typical cannonical names:
sourceFile - copy
sourceFile - copy (1)
sourceFile - copy (2)
Is there a better workaround to accomplish this purpose?
If I proper understood you then try something like:
public string createAutomaticFileName(string sourceFile)
{
var done = true;
int i = 0;
while (done)
{
var newFileName = (i == 0) ? string.Format("{0} - copy ", sourceFile) : string.Format("{0} - copy ({1})", sourceFile, i.ToString());
if (!File.Exists(newFileName))
{
return newFileName;
}
i++;
}
}
This will also suffix the extension:
if (File.Exists(strFileName))
{
bCreateCopy = AlertBox.Display("File already open. Work on a copy?", true/false);
}
if (bCreateCopy == true)
{
strNewAutomaticFileName = createAutomaticFileName(sourceFile)
File.Copy(sourceFile, strNewAutomaticFileName );
}
...
private string createAutomaticFileName(string filePath, int count = 1)
{
var pathWithoutExtension = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath));
var newFilePath = String.Format("{0} - copy ({1}){2}", pathWithoutExtension, count, Path.GetExtension(filePath));
if (File.Exists(newFilePath))
{
return createAutomaticFileName(filePath, ++count);
}
return newFilePath;
}
Of course you need to use it after you already know the initial file exists, like in your example.

FileInfo.MoveTo if file exists - rename

I have an application that moves files from one directory to another, but sometimes a conflict occurs and the file already exists in the destination directory.
When that happens, I want to move the file with a different name - e.g. if the file is named test.txt, I want to name it test.txt.1. That's okay, but how do I do it next time, if the file is again test.txt, but in the destination folder we have both test.txt and test.txt.1.
My problem is that I can't find the last created file so that I can read its index and increment it with 1. Any suggestions?
string sourcePath = "C:\\Files\\test.txt";
string filename = Path.GetFileName(sourcePath);
string pathTo = "C:\\Files\\test\\" + filename;
try
{
var fileInfo = new FileInfo(sourcePath);
fileInfo.MoveTo(pathTo);
}
catch (IOException ex)
{
var fileInfo = new FileInfo(sourcePath);
var file = Directory.GetFiles(pathTo, filename+".1").FirstOrDefault();
if (file == null)
{
fileInfo.MoveTo(pathTo+".1");
}
else
{
//find the old file, read it's last index and increment it with 1
}
}
You can use a function like this..
void MoveFileToPath(string sourceFilePath,string destinationDirectory)
{
int index = 1;
string fileName = Path.GetFileName(sourceFilePath);
string destPath = destinationDirectory+fileName;
while(File.Exists(destPath))
{
destPath = string.Format("{0}{1}.{2}",destinationDirectory,fileName,index);
index++;
}
var fileInfo = new FileInfo(sourceFilePath);
Console.WriteLine("Test:"+destPath);
fileInfo.MoveTo(destPath);
}
I have rewritten your code a little because you were programming against the exception, which is something I really do not encourage.
First, it checks if the original file already exists.
Then, as your original code, it tries to create the file with a .1 indexer. If that is already present, it goes through the directory to locate all files that have the same filename.
Last, it goes to find the last index used and increments it by one.
Note that you could also skip the first if-statement in the else-statement because it will still search for the last index used; and if none is present, the lastIndex will stay 0 (with one increment so it will use 1 as index for the new file).
var fileInfo = new FileInfo(sourcePath);
// Check if the file already exists.
if (!fileInfo.Exists)
fileInfo.MoveTo(pathTo);
else
{
var file = Directory.GetFiles(pathTo, filename + ".1").FirstOrDefault();
if (file == null)
{
fileInfo.MoveTo(pathTo + ".1");
}
else
{
// Get all files with the same name.
string[] getSourceFileNames = Directory.GetFiles(Path.GetDirectoryName(pathTo)).Where(s => s.Contains(filename)).ToArray();
// Retrieve the last index.
int lastIndex = 0;
foreach (string s in getSourceFileNames)
{
int currentIndex = 0;
int.TryParse(s.Split('.').LastOrDefault(), out currentIndex);
if (currentIndex > lastIndex)
lastIndex = currentIndex;
}
// Do something with the last index.
lastIndex++;
fileInfo.MoveTo(pathTo + lastIndex);
}
}
Func<int, string> getFileName= delegate(int i)
{
return string.Format("{0}/{1}{2}.{3}", dir, filenameWithouExt, i, ext);
};
int i = 0;
while(File.Exists(getFileName(i)))
{
i++;
}
fileInfo.MoveTo(getFileName(i));
It depends how much files do you have. You can make it more quicker if you have a lot of files:
int i = 0;
while(File.Exists(getFileName(i)))
{
i+=100;
}
i-=90;
while(File.Exists(getFileName(i)))
{
i+=10;
}
i-=9;
while(File.Exists(getFileName(i)))
{
i+=1;
}
I would prefer to write a method that will return a next index for a file and remove try-catch block:
string sourcePath = "C:\\Files\\test.txt";
string filename = Path.GetFileName(sourcePath);
string pathTo = "C:\\Files\\test\\"; // the destination file name would be appended later
var fileInfo = new FileInfo(sourcePath);
if (!fileInfo.Exists)
{
fileInfo.MoveTo(pathTo);
}
else
{
// Get all files by mask "test.txt.*"
var files = Directory.GetFiles(pathTo, string.Format("{0}.*", filename)).ToArray();
var newExtension = GetNewFileExtension(files); // will return .1, .2, ... .N
fileInfo.MoveTo(Path.Combine(pathTo, string.Format("{0}{1}", filename, newExtension)));
}
And the new method for getting the new index:
public static string GetNewFileExtension(string[] fileNames)
{
int maxIndex = 0;
foreach (var fileName in fileNames)
{
// get the file extension and remove the "."
string extension = Path.GetExtension(fileName).Substring(1);
int parsedIndex;
// try to parse the file index and do a one pass max element search
if(int.TryParse(extension, out parsedIndex))
{
if(parsedIndex > maxIndex)
{
maxIndex = parsedIndex;
}
}
}
// increment max index by 1
return string.Format(".{0}", maxIndex + 1);
}

how to parse multiple file names and get relevant information in C# asp aspx

I've been trying to figure out a way for the program to read all of the files from the path or zip file as input. Than read all of the file names inside of the input folder and split it so I can get information such as what is product id and chip name. Than store the pdf file in the correct db that matches with the product id and chip name.
The product id would be KHSA1234C and chip name LK454154.
Example File name: N3405-H-KAD_K-KHSA1234C-542164143_LK454154_GFK.pdf
public void btnUploadAttach_Click(object sender, EventArgs e)
{
string fName = this.FileUploadCFC.FileName;
string path = #"C:\mydir\";
string result;
result = Path.GetFileNameWithoutExtension(fName);
Console.WriteLine("GetFileNameWithoutExtension('{0}') return '{1}'",
fName, result);
result = Path.GetFileName(path);
Console.WriteLine("GetFileName('{0}') return '{1}'", path, result);
string[] sSplitFileName = fName.ToUpper().Split("-".ToCharArray());
foreach (char file in fName)
{
try
{
result = sSplitFileName[0] + "_" + sSplitFileName[1] + "-" +
sSplitFileName[2] + "_" + sSplitFileName[3] + "_" +
sSplitFileName[4] + "_" + sSplitFileName[5] + "_" +
sSplitFileName[6];
}
catch
{
return;
}
}
}
I don't know if I'm on the right track or not.
Can someone help me? Thank you.
first of all, in order to read all files in a folder you should use Directory.GetFiles, then you will iterate through this folder's files. Then you split file name's.. here you go..
using System.IO;
..
..
..
static void Main(string[] args)
{
string[] filePaths = Directory.GetFiles(#"c:\", "*.pdf");
string result;
foreach (var file in filePaths)
{
result = Path.GetFileNameWithoutExtension(file);
Console.WriteLine("GetFileNameWithoutExtension('{0}') return '{1}'",
file, result);
var sSplitFileName = file.ToUpper().Split('-');
var i = 0;
foreach (var item in sSplitFileName)
{
if (i == 3)
//it is product id
if (i == 7)
//it is chip name
i++;
}
}
}
To make a affirmative statement: You are on the right track - but not there yet :-)
First you need to read the files from your path, you don't do this currently.
Directory.GetFiles() may be the thing to search for. This will return a list of filenames as string[] array.
The you need to iterate over the files and apply the splitting, which looks ok to me in your code.
When you have the parts of your file, you want to decide on the database to use. It may be wise to split the filename your own filename class, that exposes properties for each part of the filename, but this is not required.
Next you need to get the db programming right, there are numerous examples on how to do this. Good luck :-)
Assuming the files all follow the same pattern you can probably just split on all of the deliminator characters '-' and '_'.
class Program
{
static void Main(string[] args)
{
string[] files = Directory.GetFiles(#"C:\mydir\", "*.pdf");
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file);
var tokens = fileName.Split('-', '_');
for(int i=0;i<tokens.Length;i++)
{
string token = tokens[i];
Console.WriteLine("{0}-{1}", i, token);
}
Console.WriteLine();
}
Console.ReadLine();
}
}

Categories

Resources