I have a function deals with xml files after determine it by OpenFileDialog and it supports multi selection of files
openFileDialog1.Multiselect = true;
openFileDialog1.Filter = "*.xml|*.XML";
openFileDialog1.Title="Please Select Xml file to convert ";
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
{
foreach (string file in openFileDialog1.FileNames)
{
//string lsit contain file names
Filestoconvert.Add(file);
}
}
and the function make process on it.
for (int i = 0; i < Filestoconvert.Count; i++)
{
XmlProcess( Filestoconvert[i]);
}
but when select files only last selected file pass to the function and other files just read in the list only.
I want to select multiple files and pass it to this function to process these files one by one without passing files manually to it.
Can any one explain how to do that ? Give me piece of code or link?
Without seeing the implementation of XmlProcess it is a guessing game. You say that this method doesn't work as expected, yet you don't show us how this method works. How can you expect anyone to help you?
Nonetheless, if you want to pass multiple files to the function, just change the signature from
void XmlProcess(string file) // should be something very similar
to
void XmlProcess(IEnumerable files)
Now you can pass an array, a list or any other object implementing the IEnumerable interface.
Related
I'm trying to create a copy button for files with this specific function:
When I write in the textbox for example "KL5050" and then press the copy button, I want to copy the file KL5050 from a specific folder and paste it to another specific folder without asking or opening any dialog or window, just click, copy and paste.
It doesn't matter the file format, it could be TXT, doc, PDF, JPEG, etc., as long as it matches the text from the textbox to any existing file in the folder it will be copied to another folder.
Also, if the file doesn't exist from the copy folder, get a warning "file not found".
The code that I have so far has two textboxes, the first is called serieBox, that one only requires input data (if is empty opens a window) before proceeding to the next box, then the next box is named recetaBox, which is the one where I type the name of file and then clicking the button, the program will look for the file and copy it to the different folder. So far I don't know where to put the second box, recetaBox. Is not in the code yet.
private void cargarButton_Click(object sender, EventArgs e)
{
if (serieBox.Text == string.Empty)
{
SerieWin openForm = new SerieWin();
openForm.ShowDialog();
}
else
{
try
{
string dircopyFrom = #"C:\From\";
string dircopyTo = #"C:\To\";
string[] files = Directory.GetFiles(dircopyFrom);
foreach (string file1 in files)
{
string filename1 = Path.GetFileName(file1);
File.Copy(file1, dircopyTo + "\\", true);
}
}
catch (Exception ex)
{
}
The only thing you haven't been totally clear on is whether KL5050 is the start, end, whole or part of the FileName but it's easy to fix
string[] files = Directory.GetFiles(dircopyFrom);
foreach (string file in files)
{
var fn = Path.GetFileNameWithoutExtension(file);
if(!fn.Contains(recetaTextBox.Text, StringComparison.OrdinalIgnoreCase))
continue;
fn = Path.GetFileName(file);
File.Copy(file, Path.Combine(dircopyTo, fn), true);
}
} catch(Exception ex){
MessageBox.Show(ex.Message);
}
Take away points:
do some check like Contains, StartsWith, EndsWith etc
use Path.Combine to build paths; .net runs on more than just windows and different systems have different directory separator chars
File.Copy takes a destination path that must contain a FileName too, not just a directory. The destination file can be renamed during copy by tweaking the name
don't ever put an empty catch block. At the very least always do a MessageBox.Show(ex.Message); especially working with files. Having a program that does nothing when a button is clicked is very frustrating. If at least you get a "file is in use by another program" when trying to copy, then you can do something about it.. but if you swallow that exception and throw it away rather than surfacing it then you'll have a really tough time tracking down any problems
if you want a slight efficiency boost you can use the contents of recetaTextBox.Text to form a filter to GetFiles, e.g GetFiles(dircopyFrom, recetaTextBox.Text+"*.*") - that is conceptually equivalent to "StartsWith". You can read more about getfiles that takes a search pattern in the fine manual - pattern matching is very basic though, if you want any advanced stuff like Regex, or even just case sensitivity, you'll need to do it in your own code
the directory you're copying to has to exist. I didn't put anything in the code to ensure this but note that it's safe to call Directory.CreateDirectory(dirCopyTo) even if it already exists, so if there's a chance the dir won't exist, you can always call CreateDirectory before you call copy to make sure it does
My code is searchcing inside a loop if a *txt file has been created.
If file will not be created after x time then i will throw an exception.
Here is my code:
var AnswerFile = #"C:\myFile.txt";
for (int i = 0; i <= 30; i++)
{
if (File.Exists(AnswerFile))
break;
await Task.Delay(100);
}
if (File.Exists(AnswerFile))
{
}
else
{
}
After the loop i check my file if has been created or not. Loop will expire in 3 seconds, 100ms * 30times.
My code is working, i am just looking for the performance and quality of my code. Is there any better approach than mine? Example should i use FileInfo class instead this?
var fi1 = new FileInfo(AnswerFile);
if(fi1.Exists)
{
}
Or should i use filewatcher Class?
You should perhaps use a FileSystemWatcher for this and decouple the process of creating the file from the process of reacting to its presence. If the file must be generated in a certain time because it has some expiry time then you could make the expiry datetime part of the file name so that if it appears after that time you know it's expired. A note of caution with the FileSystemWatcher - it can sometimes miss something (the fine manual says that events can be missed if large numbers are generated in a short time)
In the past I've used this for watching for files being uploaded via ftp. As soon as the notification of file created appears I put the file into a list and check it periodically to see if it is still growing - you can either look at the filesystem watcher lastwritetime event for this or directly check the size of the file now vs some time ago etc - in either approach it's probably easiest to use a dictionary to track the file and the previous size/most recent lastwritedate event.
After a minute of no growth I consider the file uploaded completely and I process it. It might be wise for you to implement a similar delay if using a file system watcher and the files are arriving by some slow generating method
Why you don't retrieve a list of files name, then search in the list? You can use Directory.GetFiles to get the files list inside a directory then search in this list.
This would be more fixable for you since you will create the list once, and reuse it across the application, instead of calling File.Exists for each file.
Example :
var path = #"C:\folder\"; // set the folder path, which contains all answers files
var ext = "*.txt"; // set the file extension.
// GET filename list (bare name) and make them all lowercase.
var files = Directory.GetFiles(path, ext).Select(x=> x.Substring(path.Length, (x.Length - path.Length) - ext.Length + 1 ).Trim().ToLower()).ToList();
// Search for this filename
var search = "myFile";
// Check
if(files.Contains(search.ToLower()))
{
Console.WriteLine($"File : {search} is already existed.");
}
else
{
Console.WriteLine($"File : {search} is not found.");
}
I created a string array that utilizes the Directory.GetFiles function which populates the array with .cs file extensions from all sub directories in my project. This is fine, however, I was trying to write these files to a text document while excluding specific files from the array such as "AssemblyInfo.cs" and "TemporaryGeneratedFiles_xxx.cs" using the contains method to filter files with these names. For the most part, the large majority of these files were not written to the text document, however, there are a few cases where these files manage to show up within the text document.
I've tried using a foreach statement instead of a for loop. I've tried playing around with the str.flush(), str.close(), directoryNames.Dispose(), and directoryNames.Close() by putting them in different spots of the for loop. I tried nesting the if statements instead of using the && operator. The || operator doesn't work in this situation. I've tried using the entire file name and only bits and pieces of the file name and none of this seems to work. At one point I did manage to remove all file that had "Temporary" in it but the "AssemblyInfo.cs" files still remain. I even made a method to completely remove anything with the word temporary or assembly in its file name but that also failed.
FileStream directoryNames = new FileStream(dirListPath, FileMode.OpenOrCreate);
StreamWriter str = new StreamWriter(directoryNames);
string[] allFiles = Directory.GetFiles(dirPath, "*.cs", SearchOption.AllDirectories);
for (int i = 0; i < allFiles.Length; i++)
{
if ((!allFiles[i].Contains("Temporary")) && (!allFiles[i].Contains("Assembly")))
{
str.Write(allFiles[i] + Environment.NewLine);
}
}
str.Flush();
str.Close();
directoryNames.Dispose();
directoryNames.Close();
No error messages occur but as stated above unexpected files pop up where they shouldn't be. Any help would be greatly appreciated.
Thanks to everyone who posted.
After some testing mjwillis was correct. Instead of overwriting the contents in the text file it kept writing to the top of the file and adding on to the contents that were written previously. Fixed it by adding
using (FileStream clearTextDocument = File.Create(dirListPath)) { }
Before the FileStream DirectoryNames line. Feel free to post another way to clear a text document if it's more attractive than this.
As #steve suggested you code ignores case sensitivity.
Try this one.
var allFiles = Directory.EnumerateFiles(dirPath, "*.cs", SearchOption.AllDirectories)
.Where(file => file.IndexOf("Temporary", StringComparison.InvariantCultureIgnoreCase) < 0
&& file.IndexOf("Assembly", StringComparison.InvariantCultureIgnoreCase) < 0);
File.WriteAllLines(dirListPath, allFiles);
PS: This code makes many changes to your code, but in essence they are same.
I inherited some code that makes use of ZipArchive to save some information from the database. It uses BinaryFormatter to do this. When you look at the zip file with 7-zip (for example), you see a couple of folders and a .txt file. All is working well. I simply want to modify the code to also have a folder in the ZipArchive called "temp" that consists of files and folders under C:\temp. Is there an easy way to add a entry (ZipArchiveEntry?) that consist of an entire folder or the disc? I saw "CreateEntryFromFile" in the member methods of ZipArchive, but no CreateEntryFromDirectory. Or perhaps there's some other simple way to do it? Anyone have example code? I should say that C:\temp could have variable number of files and directories (that have child directories and files, etc.) Must I enumerate them somehow, create my own directories use CreateEntryFromFile? Any help is appreciated.
Similarly, when I read the ZipArchive, I want to take the stuff related to C:\temp and just dump it in a directory (like C:\temp_old)
Thanks,
Dave
The answer by user1469065 in Zip folder in C# worked for me. user1469065 shows how to get all the files/directories in the directory (using some cool "yield" statements) and then do the serialization. For completeness, I did add the code to deserialize as user1469065 suggested (at least I think I did it the way he suggested).
private static void ReadTempFileStuff(ZipArchive archive) // adw
{
var sessionArchives = archive.Entries.Where(x => x.FullName.StartsWith(#"temp_directory_contents")).ToArray();
if (sessionArchives != null && sessionArchives.Length > 0)
{
foreach (ZipArchiveEntry entry in sessionArchives)
{
FileInfo info = new FileInfo(#"C:\" + entry.FullName);
if (!info.Directory.Exists)
{
Directory.CreateDirectory(info.DirectoryName);
}
entry.ExtractToFile(#"C:\" + entry.FullName,true);
}
}
}
i just want to know the posted file extension type,
public static void UploadFile(HttpPostedFile file)
{
....
if (file != null && file.ContentLength > 0)
{
string fileName = file.FileName;
string contentType = file.ContentType;
file.SaveAs(path);
}
}
the above code gives us the contentType
but if we change the extension by hand for example if i change untitled.exe to untitled.txt contentType becomes text. but i want to know it is an exe.
is it possible?
or the other way is safe? (i think no)
It is not possible to determine original extension of a file if user has manually changed it before uploading. However some file types have headers that can be used to terminate what type of file it is. Example may be office docs, pdfs... You simply must be carefully when excepting arbitrary file from unknown sources. Extensions are for the most part a Windows feature some other os types do not use or rely on them.
What you are asking about is file identification based on it's signature. This is not 100% guaranteed to work but there are utilities that can help you with this.
For instance TrID has a database of signatures that it can attempt to match the file for you and can optionally rename it as well.
File Identifier is another one.
If you are saving the file and want to keep users from getting you to save files with specific extensions on your system then you can of course check the extension using the FileInfo class. Something like this...
var invalidExtensions = new List<string>() { ".exe", ".dll" };
...
var fileInfo = new FileInfo(file.FileName);
if (invalidExtensions.Contains(fileInfo.Extension.ToLower()))
{
// Do your cleanup on the filename because it's an extension you don't want
// to save...
}