Speed up retrieve image into picturebox - c#

I'm currently working on windows form application which allow user to retrieve image after searching at textbox. The problem is the image is load very slow. How can I overcome this problem to speed up the loading? If anyone has suggestions for a faster way to retrieve these images, it would be greatly appreciated. Here is my code:
string baseFolder = #"\\\\jun01\\hr\\photo";
string imgName = "*" + textBoxEmplNo.Text + "*.jpg";
//Bool to see if file is found after checking all
bool fileFound = false;
DirectoryInfo di = new DirectoryInfo(baseFolder);
foreach (var file in di.GetFiles(imgName, SearchOption.AllDirectories))
{
pictureBox1.Visible = true;
pictureBox1.Image = Image.FromFile(file.FullName);
fileFound = true;
break;
}
if (!fileFound)
{
pictureBox1.Visible = true;
pictureBox1.Image = Image.FromFile(#"\\\\jun01\\hr\\photo\\No-image-
found.jpg");
}

It's very likely here that the slowness you are experiencing is due to the wildcard search on all files in a remote directory, and/or potentially transferring a large file over the network for display in the PictureBox. You should time these two operations using a profiler (see for example https://www.simple-talk.com/dotnet/net-performance/the-why-and-how-of-net-profiling/) and consider optimizing the operations that take the most time.
Some possibilities might include pre-downloading all the images before the user makes a selection or downloading on a background thread while displaying a "Please wait" message on the UI.

It could be the case that the code slowness is due to the wildcard search on all files: (e.g. di.GetFiles takes too long)
Too many files in your top folder/subfolders.
The network connection is too slow to fetch file information or photos are too big. (remote directory access could be slow - you can check by copying a big file say 1GB to your remote directory and copy back to your PC)
The photos may be stored with different aspect ratios to your picture box size. (Rendering takes a while if resizing needs to happen)
For starters, let us assume your folder has too many files (1000s), then we need to do a smarter search for the first file folder by folder:
string baseFolder = #"\\\\jun01\\hr\\photo";
string imgName = "*" + textBoxEmplNo.Text + "*.jpg";
var file = FindFirstFile(baseFolder, imgName);
if (!string.IsNullorEmpty(file))
{
pictureBox1.Visible = true;
pictureBox1.Image = Image.FromFile(file);
}
else
{
pictureBox1.Visible = true;
pictureBox1.Image = Image.FromFile(#"\\\\jun01\\hr\\photo\\No-image-found.jpg");
}
where FindFirstFile is taken from Markus's answer as:
public static string FindFirstFile(string path, string searchPattern)
{
string[] files;
try
{
// Exception could occur due to insufficient permission.
files = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
return string.Empty;
}
if (files.Length > 0)
{
return files[0];
}
else
{
// Otherwise find all directories.
string[] directories;
try
{
// Exception could occur due to insufficient permission.
directories = Directory.GetDirectories(path);
}
catch (Exception)
{
return string.Empty;
}
// Iterate through each directory and call the method recursivly.
foreach (string directory in directories)
{
string file = FindFirstFile(directory, searchPattern);
// If we found a file, return it (and break the recursion).
if (file != string.Empty)
{
return file;
}
}
}
return string.Empty;
}

Related

Get progress for saving a zip file in C#?

I have this method below, which when the user clicks the button, the program gets a list of files from a path, and zips them to a location (as long as the paths exist)
I have tested it, and it works well for small folders. When I get over 1gb, the gui was freezing. As a result, I started a new thread to stop that from happening. I tried various ways of getting the progress to display, but I get nothing.
If I manually close the program several minutes in, I get a various size temp file depending on how long I wait, so I know that it is writing the file, I just cant figure out how to tell the progress to show the user.
Any ideas?
Here is my method:
private void btnSyncJobs_Click(object sender, EventArgs e)
{
string startPath = #"J:\TV\Game Of Thrones";
string zipPath = #"j:\result.zip";
string sendPath = #"j:\";
if (Directory.Exists(startPath) && Directory.Exists(sendPath))
{
//MessageBox.Show("Correct","These 2 paths exist.");
if (File.Exists(zipPath))
{
File.Delete(zipPath); //delete existing file in order to save the new one
}
String[] allfiles = System.IO.Directory.GetFiles(startPath, "*.*", System.IO.SearchOption.AllDirectories);
int fileCount = allfiles.Length;
int filesAdded = 0;
double percentComplete = 0.00;
string fileCountString = Convert.ToString(fileCount);
MessageBox.Show("There are " + fileCountString + " files.","Count Notice.");
//create the new zip file
//ZipFile.CreateFromDirectory(startPath, zipPath, CompressionLevel.Fastest, true);
Task.Factory.StartNew(() =>
{
using (ZipFile zip = new ZipFile())
{
if (chkPassword.Checked)
{
zip.Password = txtPassword.Text;
}
foreach (string s in allfiles)
{
zip.AddItem(s);
//filesAdded++;//increment the count of files added
//percentComplete = filesAdded / fileCount;
//string percentLabel = filesAdded + " of "+ fileCount + " completed.";
//lblSyncJobsStatus.Text = percentLabel;
}
zip.Save(zipPath);
}
});
lblSyncJobsStatus.Text = "Completed successfully.";
}
else
{
MessageBox.Show("Error: One or more network drives are not attached.","Error");
lblSyncJobsStatus.Text = "Did not complete successfully.\n Please contact tech support.";
}
}
Just a note- I was testing in my tv folder to test on larger file sizes.
The line '//lblSyncJobsStatus.Text = percentLabel;' had to be commented out, because it can't update a value started in another thread. Even before that, I noticed that it was at 100% before the file was being written.
The ZipFile class does not appear to offer any events or callback opportunities to report progress.
If you're open to using the open source 7-Zip library instead (and the SevenZipSharp .NET wrapper), it looks like it provides a callback for reporting progress.
https://sevenzipsharp.codeplex.com/SourceControl/latest#SevenZip/ArchiveUpdateCallback.cs

C# check driver for file types followed by action

So basically i am making an app that will sync file types is different ways, I want to search the whole of a logical Drive for example C:\ for all text files.How ever once i find all the text files i want to apply an action for example move all text files to one location or email all text files to the users email.
I have found this code from a past Stack overflow post
public List<string> Search()
{
var files = new List<string>();
foreach (DriveInfo d in DriveInfo.GetDrives().Where(x => x.IsReady))
{
try
{
files.AddRange(Directory.GetFiles(d.RootDirectory.FullName, "*.txt", SearchOption.AllDirectories));
}
catch(Exception e)
{
Logger.Log(e.Message); // Log it and move on
}
}
return files;
}
But what i want to know is how do i do somthing when i find the files ?
The code you posted looks like it should fill List<string> files with strings representing names of files that have a .txt extension.
It should be as simple as iterating over the value returned from the function and doing as you please with them.
This code should (untested) check for a target directory, create it if it doesn't exist, and then copy each file returned from Search() to the target path.
List<string> results = Search();
String targetPath = "C:/TargetDirectory/";
if (!System.IO.Directory.Exists(targetPath))
System.IO.Directory.CreateDirectory(targetPath);
foreach (string aFileStr in results)
{
String sourceFile = aFileStr;
String destFile = Path.Combine(targetPath, Path.GetFileName(aFileStr));
System.IO.File.Copy(sourceFile, destFile, true);
}
You would do a foreach on the list of strings that that function returns.
I'm not quite sure if I understand you correctly. If you just want to know how to process your filelist, you could for instance do the following:
var filelist = Search();
foreach (var s in filelist) {
string fn = System.IO.Path.GetFileName(s);
string dest = System.IO.Path.Combine("c:\\tmp", fn);
System.IO.File.Copy(s, dest, true);
}
which will copy all files in filelist to c:\tmp and overwrite files with equal filename.

Copy and overwrite files between two folders(one shared)

I'm making a small application that have to take all the files from a shared folder and copy them in the current folder(the once from where the application it's runned).
One month ago this code was fine:
string seprin_address = #"\\PC-SEPRIN\2port\";
SimpleCopy(seprin_address);
public void SimpleCopy(string sourcePath){
try{
string fileName = "";
string targetPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
bool path = false;
string real_target = "";
for(int i = 0; i < targetPath.Length; i++){
if(targetPath[i] == 'C'){
path = true;
}
if(path){
real_target += targetPath[i];
}
}
// Use Path class to manipulate file and directory paths.
string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
string destFile = System.IO.Path.Combine(targetPath, fileName);
// To copy a folder's contents to a new location:
// Create a new target folder, if necessary.
/*if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}*/
// To copy a file to another location and
// overwrite the destination file if it already exists.
//System.IO.File.Copy(sourceFile, destFile, true);
// To copy all the files in one directory to another directory.
// Get the files in the source folder. (To recursively iterate through
// all subfolders under the current directory, see
// "How to: Iterate Through a Directory Tree.")
// Note: Check for target path was performed previously
// in this code example.
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
MessageBox.Show("Error");
}
// Keep console window open in debug mode.
}
catch(Exception e_p){
lbabel.Text = e_p.Message;
}
}
Now i get the "URI not supported error" when the file.copy it's called.
I think its supernatural but if you have any other ideas i'm all ears.
I would find out if the URI not supported is complaining about source or destination. I would also check to make sure the user that this is running as has permission to the directories in question. Could the users permissions have changed? I have had occasion where I had jobs in scheduled tasks where the user was set and later the password was changed for the user but not on the scheduled task. The same could be true if this is written as a service with a specific user.
as you are saying it was working fine one month ago, there can be two possibilities which is restricting you from accessing the Path.
1.Remote PC Hostname PC-SEPRIN might havebeen changed.Please check the remote pc hostname.
2.check the Shared Folder 2port path properly.
if somebody changes shared folder name or deletes it, you can not access it.
and also please check whether you have permissions to access it or not.

Avoiding a customized Copy Directory function to go on infinite loop when copying folder into himself

I'm trying this function, which copies all files from a folder, and relative subfolders with files to another location:
using System.IO;
private static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
{
bool ret = true;
try
{
SourcePath = SourcePath.EndsWith(#"\") ? SourcePath : SourcePath + #"\";
DestinationPath = DestinationPath.EndsWith(#"\") ? DestinationPath : DestinationPath + #"\";
if (Directory.Exists(SourcePath))
{
if (Directory.Exists(DestinationPath) == false)
Directory.CreateDirectory(DestinationPath);
foreach (string fls in Directory.GetFiles(SourcePath))
{
FileInfo flinfo = new FileInfo(fls);
flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
}
foreach (string drs in Directory.GetDirectories(SourcePath))
{
DirectoryInfo drinfo = new DirectoryInfo(drs);
if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false || drs.Substring(drs.Length-8) == "archive")
ret = false;
}
}
else
{
ret = false;
}
}
catch (Exception e)
{
Console.WriteLine("{0} {1} {2}", e.Message, Environment.NewLine + Environment.NewLine, e.StackTrace);
ret = false;
}
return ret;
}
It works good until you have to copy the folder into another location, but when you have to create a folder in itself (In my example I'm doing a subfolder called "archive" to keep track of the last folder files changes) it goes in infinite loops, because it keeps rescanning itself in the Directory.GetDirectories foreach loop, finding the newly created subfolders and going on nesting the same subfolder over and over until it reaches a "Path name too long max 260 charachters limit exception".
I tried to avoid it by using the condition
|| drs.Substring(drs.Length-8) == "archive")
which should check the directory name, but it doesn't seem to work.
I thought than, different solutions like putting a max subfolders depth scan (I.E max 2 subfolders) so it doesn't keep rescanning all the nested folders, but I can't find such property in Directory object.
I cannot copy the whole thing to a temp folder and then into the real folder because the next time I will scan it, it will rescan archive folder too.
I tought about putting all the directory listing in an ArrayList of Directory objects or so so maybe I can check something like DirName or so but I don't know if such property exists.
Any solution?
This is a case where recursion doesn't really work, as the list of directories and files always changes as you copy. A better solution is to get the list of all files and folders in advance.
You can get all files and directories in a tree using the Directory.GetFiles(String,String,SearchOption) and Directory.GetDirectories(String,String,SearchOption) with SearchOption set to SearchOption.AllDirectories. These will return all files and all directories respectively.
You can follow these steps to copy the files:
Get the list of all source directories and sort them in ascending order. This will ensure that parent directories appear before their child directories.
Create the target directory structure by creating the child directories in their sorted order. You won't get any path conflicts as the sort order ensures you always create the parent folders before the child folders
Copy all the source files to the target directories as before. Order doesn't really matter at this point as the target directory structure already exists.
A quick example:
static void Main(string[] args)
{
var sourcePath = #"c:\MyRoot\TestFolder\";
var targetPath = #"c:\MyRoot\TestFolder\Archive\";
var directories=Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
var files = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);
if(!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
foreach (var directory in directories)
{
var relativePath = GetRelativePath(sourcePath, directory);
var toPath = Path.Combine(targetPath, relativePath);
if (!Directory.Exists(toPath))
{
Directory.CreateDirectory(toPath);
}
}
foreach (var file in files)
{
var relativePath = GetRelativePath(sourcePath, file);
var toPath = Path.Combine(targetPath, relativePath);
if (!File.Exists(toPath))
File.Copy(file,toPath);
}
}
//This is a very quick and dirty way to get the relative path, only for demo purposes etc
private static string GetRelativePath(string rootPath, string fullPath)
{
return Path.GetFullPath(fullPath).Substring(rootPath.Length);
}

copy files from one location to another

I am trying to create a directory and subdirectories and copy files from on one location to another location. The following code works but it doesn't create a parent directory(10_new) if there are sub directories. I am trying to copy all the contents(including subdirectories) from "c:\\sourceLoc\\10" to "c:\\destLoc\\10_new" folder. If "10_new" doesn't exist then I should create this folder. Please assist.
string sourceLoc = "c:\\sourceLoc\\10";
string destLoc = "c:\\destLoc\\10_new";
foreach (string dirPath in Directory.GetDirectories(sourceLoc, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourceLoc, destLoc));
if (Directory.Exists(sourceLoc))
{
//Copy all the files
foreach (string newPath in Directory.GetFiles(sourceLoc, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourceLoc, destLoc));
}
}
From looking at your code, you never check for the existence of the parent folders. You jump to getting all the child folders first.
if (!Directory.Exists(#"C:\my\dir")) Directory.CreateDirectory(#"C:\my\dir");
Here is how to copy all files in a directory to another directory
This is taken from http://msdn.microsoft.com/en-us/library/cc148994.aspx
string sourcePath = "c:\\sourceLoc\\10";
string targetPath = "c:\\destLoc\\10_new";
string fileName = string.Empty;
string destFile = string.Empty;
// To copy all the files in one directory to another directory.
// Get the files in the source folder. (To recursively iterate through
// all subfolders under the current directory, see
// "How to: Iterate Through a Directory Tree.")
// Note: Check for target path was performed previously
// in this code example.
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
Console.WriteLine("Source path does not exist!");
}
Recursive Directory/Sub-directory
public class RecursiveFileSearch
{
static System.Collections.Specialized.StringCollection log = new System.Collections.Specialized.StringCollection();
static void Main()
{
// Start with drives if you have to search the entire computer.
string[] drives = System.Environment.GetLogicalDrives();
foreach (string dr in drives)
{
System.IO.DriveInfo di = new System.IO.DriveInfo(dr);
// Here we skip the drive if it is not ready to be read. This
// is not necessarily the appropriate action in all scenarios.
if (!di.IsReady)
{
Console.WriteLine("The drive {0} could not be read", di.Name);
continue;
}
System.IO.DirectoryInfo rootDir = di.RootDirectory;
WalkDirectoryTree(rootDir);
}
// Write out all the files that could not be processed.
Console.WriteLine("Files with restricted access:");
foreach (string s in log)
{
Console.WriteLine(s);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key");
Console.ReadKey();
}
static void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
// First, process all the files directly under this folder
try
{
files = root.GetFiles("*.*");
}
// This is thrown if even one of the files requires permissions greater
// than the application provides.
catch (UnauthorizedAccessException e)
{
// This code just writes out the message and continues to recurse.
// You may decide to do something different here. For example, you
// can try to elevate your privileges and access the file again.
log.Add(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
// In this example, we only access the existing FileInfo object. If we
// want to open, delete or modify the file, then
// a try-catch block is required here to handle the case
// where the file has been deleted since the call to TraverseTree().
Console.WriteLine(fi.FullName);
}
// Now find all the subdirectories under this directory.
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
// Resursive call for each subdirectory.
WalkDirectoryTree(dirInfo);
}
}
}
}
Before doing File.Copy, check to make sure the folder exists. If it doesn't create it.
This function will check if a path exists, if it doesnt, it will create it. If it fails to create it, for what ever reason, it will return false. Otherwise, true.
Private Function checkDir(ByVal path As String) As Boolean
Dim dir As New DirectoryInfo(path)
Dim exist As Boolean = True
If Not dir.Exists Then
Try
dir.Create()
Catch ex As Exception
exist = False
End Try
End If
Return exist
End Function
Remember, all .Net languages compile down to the CLR (common language runtime) so it does not matter if this is in VB.Net or C#. A good way to convert between the two is: http://converter.telerik.com/
It is impossible to copy or move files with C# in windows 7.
It will instead create a file of zero bytes.

Categories

Resources