File access denied while moving file - c#

I'm trying to move files from a to b, but I get an IOException with the Information: Access denied.
I'm pretty sure it's because the file is still open. My question is - how can I check if the file is in use or not, and if it is wait until it's closed.
The exception is thrown at the MoveTo() call in the example below.
public void CreateCheckedStructure() {
List<string> checkedDirNew = RemoveTempFolders(GetAllFromDir(Settings.Default.NewFolder));
List<string> checkedDirCurrent = RemoveTempFolders(GetAllFromDir(Settings.Default.CurrentFolder));
if (checkedDirNew.Count != 0 && checkedDirCurrent.Count != 0) {
MyLog.WriteToLog("Moving Checked Files", MyLog.Messages.Info);
foreach (string checkedNew in checkedDirNew) {
DirectoryInfo dirInfoNew = new DirectoryInfo(checkedNew);
foreach (string checkedCurrent in checkedDirCurrent) {
DirectoryInfo dirInfoCurrent = new DirectoryInfo(checkedCurrent);
if (dirInfoNew.Name.Equals(dirInfoCurrent.Name)) {
string checkedFoldersPath = Settings.Default.CheckedTables + "\\" + dirInfoCurrent.Name + "_" + DateTime.Now.ToString("hh-mm-ss");
Directory.CreateDirectory(checkedFoldersPath);
Directory.CreateDirectory(checkedFoldersPath + "\\New");
Directory.CreateDirectory(checkedFoldersPath + "\\Current");
dirInfoCurrent.MoveTo(checkedFoldersPath + "\\Current\\" + dirInfoNew.Name);
dirInfoNew.MoveTo(checkedFoldersPath + "\\New\\" + dirInfoCurrent.Name);
break;
}
}
}
MyLog.WriteToLog("All Checked Files have been moved", MyLog.Messages.Info);
} else { MyLog.WriteToLog("No Temporary Folder for Zips found",MyLog.Messages.Warning); }
}

you can try this extension method which I wrote to solve similar type of problem
public static async Task<bool> TryToAsync( Action action, int timeoutInSeconds )
{
var timeout = DateTime.Now.AddSeconds( timeoutInSeconds );
while ( DateTime.Now < timeout )
{
try
{
action();
return true;
}
catch ( Exception )
{
await Task.Delay( 200 );
}
}
return false;
}

Related

How can I search for a specific attachment in outlook

I am trying to retrieve a specific attachment in Outlook to save to my folder.
Everything works great but it seems to save all the attachments in the "Inbox" Folder instead of the specific one I am looking for.
This is what I have at the moment:
static void EnumerateFoldersInDefaultStore()
{
Outlook.Application Application = new Outlook.Application();
Outlook.Folder root = Application.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
EnumerateFolders(root);
}
static void EnumerateFolders(Outlook.Folder folder)
{
Outlook.Folders childFolders = folder.Folders;
if (childFolders.Count > 0)
{
foreach (Outlook.Folder childFolder in childFolders)
{
if (childFolder.FolderPath.Contains("Inbox"))
{
Console.WriteLine(childFolder.FolderPath);
EnumerateFolders(childFolder);
}
}
}
Console.WriteLine("Checking in " + folder.FolderPath);
IterateMessages(folder);
}
static void IterateMessages(Outlook.Folder folder)
{
string fileName = "Reports.pdf";
var fi = folder.Items;
if (fi != null)
{
try
{
foreach (Object item in fi)
{
Outlook.MailItem mi = (Outlook.MailItem)item;
var attachments = mi.Attachments;
if (attachments.Count != 0)
{
if (!Directory.Exists(basePath + folder.FolderPath))
{
Directory.CreateDirectory(basePath + folder.FolderPath);
}
for (int i = 1; i <= mi.Attachments.Count; i++)
{
if (fileName != null)
{
if (!Directory.Exists(basePath))
{
Directory.CreateDirectory(basePath);
}
totalfilesize = totalfilesize + mi.Attachments[i].Size;
if (!File.Exists(basePath + mi.Attachments[i].FileName))
{
Console.WriteLine("Saving " + mi.Attachments[i].FileName);
mi.Attachments[i].SaveAsFile(basePath + mi.Attachments[i].FileName);
}
else
{
Console.WriteLine("Already saved " + mi.Attachments[i].FileName);
}
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine("An error occurred: '{0}'", e);
}
}
}
So it basically searches the entire "Inbox" and saves all the attachments but like I said not the one I want only - "Reports.pdf"
What am I doing wrong here?
In static void IterateMessages(Outlook.Folder folder) you currently only check for if (fileName != null) (which should never happen as fileName is always assigned at the beginning of the method).
You need to add a condition to check if the attached file meets your fileName-Criteria, e.g.:
if (mi.Attachments[i].FileName == fileName) {
//Save your attachment
} else {
// naming-critera not met, skip...
}

versioncontrol.GetAllTeamProjects() returning 0

I'm working on a project where I'll have a C# application search all TFS project's .cs files for a string or string patterns. I found some code that looks similar to what I was looking to do here.
namespace TFSSearch
{
class Program
{
static string[] textPatterns = new[] { "void main(", "exception", "RegisterScript" }; //Text to search
static string[] filePatterns = new[] { "*.cs", "*.xml", "*.config", "*.asp", "*.aspx", "*.js", "*.htm", "*.html",
"*.vb", "*.asax", "*.ashx", "*.asmx", "*.ascx", "*.master", "*.svc"}; //file extensions
static void Main(string[] args)
{
try
{
var tfs = TfsTeamProjectCollectionFactory
.GetTeamProjectCollection(new Uri("https://{tfsserver}/tfs"));
tfs.EnsureAuthenticated();
var versionControl = tfs.GetService<VersionControlServer>();
StreamWriter outputFile = new StreamWriter(#"C:\Find.txt");
var allProjs = versionControl.GetAllTeamProjects(true);
foreach (var teamProj in allProjs)
{
foreach (var filePattern in filePatterns)
{
var items = versionControl.GetItems(teamProj.ServerItem + "/" + filePattern, RecursionType.Full).Items
.Where(i => !i.ServerItem.Contains("_ReSharper")); //skipping resharper stuff
foreach (var item in items)
{
List<string> lines = SearchInFile(item);
if (lines.Count > 0)
{
outputFile.WriteLine("FILE:" + item.ServerItem);
outputFile.WriteLine(lines.Count.ToString() + " occurence(s) found.");
outputFile.WriteLine();
}
foreach (string line in lines)
{
outputFile.WriteLine(line);
}
if (lines.Count > 0)
{
outputFile.WriteLine();
}
}
}
outputFile.Flush();
}
}
catch (Exception e)
{
string ex = e.Message;
Console.WriteLine("!!EXCEPTION: " + e.Message);
Console.WriteLine("Continuing... ");
}
Console.WriteLine("========");
Console.Read();
}
// Define other methods and classes here
private static List<string> SearchInFile(Item file)
{
var result = new List<string>();
try
{
var stream = new StreamReader(file.DownloadFile(), Encoding.Default);
var line = stream.ReadLine();
var lineIndex = 0;
while (!stream.EndOfStream)
{
if (textPatterns.Any(p => line.IndexOf(p, StringComparison.OrdinalIgnoreCase) >= 0))
result.Add("=== Line " + lineIndex + ": " + line.Trim());
line = stream.ReadLine();
lineIndex++;
}
}
catch (Exception e)
{
string ex = e.Message;
Console.WriteLine("!!EXCEPTION: " + e.Message);
Console.WriteLine("Continuing... ");
}
return result;
}
}
}
The problem I'm having is when I try to get the projects using versionControl.GetAllTeamProjects(true); allProjs seems to get no information back. It is an empty array of TeamProject. When I debug, tfs.HasAuthenticated is true and it doesn't throw any exceptions. The TFS server is on a https domain. How can I make sure I'm exactly connecting to TFS?
I test at my side, everything works correctly.
Install the Nuget package
Microsoft.TeamFoundationServer.ExtendedClient by running below
command in Package Manager Console:
PM> Install-Package Microsoft.TeamFoundationServer.ExtendedClient -Version 15.112.1
Make sure you specify the correct TFS server,
eg : http://servername:8080/tfs/DefaultCollection
Then check it again.

C# How to rename a file without using File.Move

I have a c# application that connects to a server, gets the datagrid, manipulates each row and then according to each updated row the new row gets uploaded to the server and one file per row gets renamed on the hdd.
The application works totally fine but i analyzed it with the profiler and realised that this line of code:
File.Move(symbolsOldPath, symbolsPath);
takes 80% of the time my application needs to complete its task.
I went through all the questions on StackOverflow and other questions out there if there is a different way for a better performance but i wasnt succesful. The only other way i found was implementing VB to use the Rename method, but as it calls the File.Move method it is no improvement. Do you guys know an alternative way with better performance?
Here is my code of the class that changes the data.
public DataTable ChangeData(DataTable unchangedData, string searchPathSymbols, string searchPathImages, ProgressBar pbForm)
{
pbtemp = pbForm;
int rowCount = unchangedData.Rows.Count;
foreach (DataRow row in unchangedData.Rows)
{
counter++;
if (counter == 10)
{
pbtemp.Value += counter;
counter = 0;
Application.DoEvents();
}
number = row[1].ToString();
symbolsPath = row[2].ToString();
symbolsPathCopy = symbolsPath;
imagesPath = row[3].ToString();
imagesPathCopy = imagesPath;
aliasSymbols = symbolsPath.Substring(0, symbolsPath.IndexOf('>') + 1);
if (symbolsPath == imagesPath)
{
if (aliasSymbols.Contains("Symbole"))
{
if (!string.IsNullOrEmpty(symbolsPath))
{
SymbolsChanger(searchPathSymbols, row);
row[3] = row[2];
}
}
else
{
if (!string.IsNullOrEmpty(imagesPath))
{
ImagesChanger(searchPathImages, row);
row[2] = row[3];
}
}
}
else
{
if (!string.IsNullOrEmpty(symbolsPath))
{
SymbolsChanger(searchPathSymbols, row);
}
if (!string.IsNullOrEmpty(imagesPath))
{
ImagesChanger(searchPathImages, row);
}
}
}
pbtemp.Value += (rowCount - pbtemp.Value);
return unchangedData;
}
private void SymbolsChanger(string searchPathSymbols, DataRow row)
{
string symbolsOldPath;
//Symbols
//Get and delete Alias and get filepath
int countAliasSymbolsIndex = symbolsPath.LastIndexOf('>') + 1;
symbolsPath = symbolsPath.Remove(0, countAliasSymbolsIndex);
symbolsOldPath = searchPathSymbols + "\\" + symbolsPath;
//Remove and replace numbers
int startSymbolsIndex = 0;
int endSymbolsIndex = symbolsPath.IndexOf('_') == -1 ? symbolsPath.LastIndexOf('.') : symbolsPath.IndexOf('_');
int countSymbolsIndex = endSymbolsIndex - startSymbolsIndex;
symbolsPath = symbolsPath.Remove(startSymbolsIndex, countSymbolsIndex);
string nameSymbols = number + symbolsPath;
symbolsPath = searchPathSymbols + "\\" + nameSymbols;
try
{
//Rename file
File.Move(symbolsOldPath, symbolsPath);
}
catch(FileNotFoundException)
{
try
{
File.Move(symbolsPath, symbolsPath);
}
catch (FileNotFoundException)
{
logArrayDataChange.Add(symbolsPathCopy);
}
}
row[2] = aliasSymbols + nameSymbols;
}
private void ImagesChanger(string searchPathImages, DataRow row)
{
string imagesOldPath;
//Images
//Get and delete Alias and get filepath
string aliasImage = imagesPath.Substring(0, imagesPath.IndexOf('>') + 1);
int countAliasImagesIndex = imagesPath.LastIndexOf('>') + 1;
imagesPath = imagesPath.Remove(0, countAliasImagesIndex);
imagesOldPath = imagesPath.StartsWith("\\") == true ? searchPathImages + imagesPath : searchPathImages + "\\" + imagesPath;
//Remove and replace numbers
int startImagesIndex = imagesPath.LastIndexOf("\\") == -1 ? 0 : imagesPath.LastIndexOf("\\");
int endImagesIndex = imagesPath.IndexOf('_') == -1 ? imagesPath.LastIndexOf('.') : imagesPath.IndexOf('_');
int countImagesIndex = endImagesIndex - startImagesIndex;
imagesPath = imagesPath.Remove(startImagesIndex + 1, countImagesIndex - 1);
int insertIndex = imagesPath.LastIndexOf("\\") == -1 ? 0 : imagesPath.LastIndexOf("\\");
string nameImages = imagesPath.Insert(insertIndex + 1, number);
imagesPath = searchPathImages + "\\" + nameImages;
try
{
//Rename file
File.Move(imagesOldPath, imagesPath);
}
catch (FileNotFoundException)
{
try
{
File.Move(imagesPath, imagesPath);
}
catch (FileNotFoundException)
{
logArrayDataChange.Add(imagesPathCopy);
}
}
row[3] = aliasImage + nameImages;
}
}
}
I would keep File.Move to do the job. Besides a little overhead (checks), File.Move uses only the native MoveFile Windows call to move the file:
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern bool MoveFile(String src, String dst);
You can call that method yourself, but I doubt it will get any faster than that.
From the documentation it seems that move is already built to rename efficiently:
The MoveFile function will move (rename) either a file or a directory ...

Asp.Net Mvc Delete file issue

I have an issue with Files.
I am doing an image importer so clients put their files on an FTP server and then they can import it in the application.
During the import process I copy the file in the FTP Folder to another folder with File.copy
public List<Visuel> ImportVisuel(int galerieId, string[] images)
{
Galerie targetGalerie = MemoryCache.GetGaleriById(galerieId);
List<FormatImage> listeFormats = MemoryCache.FormatImageToList();
int i = 0;
List<Visuel> visuelAddList = new List<Visuel>();
List<Visuel> visuelUpdateList = new List<Visuel>();
List<Visuel> returnList = new List<Visuel>();
foreach (string item in images)
{
i++;
Progress.ImportProgress[Progress.Guid] = "Image " + i + " sur " + images.Count() + " importées";
string extension = Path.GetExtension(item);
string fileName = Path.GetFileName(item);
string originalPath = HttpContext.Current.Request.PhysicalApplicationPath + "Uploads\\";
string destinationPath = HttpContext.Current.Server.MapPath("~/Images/Catalogue") + "\\";
Visuel importImage = MemoryCache.GetVisuelByFilName(fileName);
bool update = true;
if (importImage == null) { importImage = new Visuel(); update = false; }
Size imageSize = importImage.GetJpegImageSize(originalPath + fileName);
FormatImage format = listeFormats.Where(f => f.width == imageSize.Width && f.height == imageSize.Height).FirstOrDefault();
string saveFileName = Guid.NewGuid() + extension;
File.Copy(originalPath + fileName, destinationPath + saveFileName);
if (format != null)
{
importImage.format = format;
switch (format.key)
{
case "Catalogue":
importImage.fileName = saveFileName;
importImage.originalFileName = fileName;
importImage.dossier = targetGalerie;
importImage.dossier_id = targetGalerie.id;
importImage.filePath = "Images/Catalogue/";
importImage.largeur = imageSize.Width;
importImage.hauteur = imageSize.Height;
importImage.isRoot = true;
if (update == false) { MemoryCache.Add(ref importImage); returnList.Add(importImage); }
if (update == true) visuelUpdateList.Add(importImage);
foreach (FormatImage f in listeFormats)
{
if (f.key.StartsWith("Catalogue_"))
{
string[] keys = f.key.Split('_');
string destinationFileName = saveFileName.Insert(saveFileName.IndexOf('.'), "-" + keys[1].ToString());
string destinationFileNameDeclinaison = destinationPath + destinationFileName;
VisuelResizer declinaison = new VisuelResizer();
declinaison.Save(originalPath + fileName, f.width, f.height, 1000, destinationFileNameDeclinaison);
Visuel visuel = MemoryCache.GetVisuelByFilName(fileName.Insert(fileName.IndexOf('.'), "-" + keys[1].ToString()));
update = true;
if (visuel == null) { visuel = new Visuel(); update = false; }
visuel.parent = importImage;
visuel.filePath = "Images/Catalogue/";
visuel.fileName = destinationFileName;
visuel.originalFileName = string.Empty;
visuel.format = f;
//visuel.dossier = targetGalerie; On s'en fout pour les déclinaisons
visuel.largeur = f.width;
visuel.hauteur = f.height;
if (update == false)
{
visuelAddList.Add(visuel);
}
else
{
visuelUpdateList.Add(visuel);
}
//importImage.declinaisons.Add(visuel);
}
}
break;
}
}
}
MemoryCache.Add(ref visuelAddList);
// FONCTION à implémenter
MemoryCache.Update(ref visuelUpdateList);
return returnList;
}
After some processes on the copy (the original file is no more used)
the client have a pop-up asking him if he wants to delete the original files in the ftp folder.
If he clicks on Ok another method is called on the same controller
and this method use
public void DeleteImageFile(string[] files)
{
for (int i = 0; i < files.Length; i++)
{
File.Delete(HttpContext.Current.Request.PhysicalApplicationPath + files[i].Replace(#"/", #"\"));
}
}
This method works fine and really delete the good files when I use it in other context.
But here I have an error message:
Process can't acces to file ... because it's used by another process.
Someone have an idea?
Thank you.
Here's the screenshot of Process Explorer
There are couple of thing you can do here.
1) If you can repro it, you can use Process Explorer at that moment and see which process is locking the file and if the process is ur process then making sure that you close the file handle after your work is done.
2) Use try/catch around the delete statement and retry after few seconds to see if the file handle was released.
3) If you can do it offline you can put in some queue and do the deletion on it later on.
You solve this by using c# locks. Just embed your code inside a lock statement and your threads will be safe and wait each other to complete processing.
I found the solution:
in my import method, there a call to that method
public void Save(string originalFile, int maxWidth, int maxHeight, int quality, string filePath)
{
Bitmap image = new Bitmap(originalFile);
Save(ref image, maxWidth, maxHeight, quality, filePath);
}
The bitmap maintains the file opened blocking delete.
just added
image.Dispose();
in the methos and it work fine.
Thank you for your help, and thank you for process explorer. Very useful tool

Backup Windows 7 with specific filetypes. Some folders unavilable

Im trying to backup a computer with Windows 7 installed.
In older systems I created a backup that found and copyied specific images and office files.
Now when trying in Windows 7, I face some problems regarding some folders that arent available for me like they used to be in older systems.
How can I tweek this problem. I really like this way of backing the system up prior to upgrading etc.
Thanks in advance.
Feel free to ask and comment.
using System;
using System.Collections.Generic;
using System.IO;
//using System.IO.Directory.CreateDirectory;
static class Program
{
static void Main(string[] args)
{
ShowAllFoldersUnder(#"c:\",0);
}
private static void ShowAllFoldersUnder(string path,int indent)
{
int idx = 0;
string sourcePath = #"c:\";
string destinPath = #"h:\20160714\";
string fldr = #"C:\";
string[] fileTypes = new string[2];
fileTypes[idx] = ".docx"; idx++;
fileTypes[idx] = ".xlsx"; idx++;
try
{
if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
{
foreach (string folder in Directory.GetDirectories( path ) )
{
//Console.WriteLine(folder);
//if (#folder.IndexOf(fldr) != -1) // COMMENT
//{
Console.WriteLine( folder );
foreach ( string file in Directory.GetFiles( folder ) )
{
string e = Path.GetExtension( file );
//Console.WriteLine(e);
for (int i =0;i<=fileTypes.GetUpperBound(0);i++)
{
string[] filesToCopy = Directory.GetFiles(folder, "*" + Convert.ToString(fileTypes[i]));
foreach (string name in filesToCopy)
{
if (Convert.ToString(fileTypes[i]).ToLower() == Path.GetExtension(file).ToLower())
{
Console.WriteLine("From: {0}",name);
Console.WriteLine("To: {0}", name.Replace(sourcePath, destinPath) );
try
{
DirectoryInfo di = Directory.CreateDirectory( Path.GetDirectoryName( name.Replace(sourcePath, destinPath) ) );
Console.WriteLine("Copying.");
File.Copy(name, name.Replace(sourcePath, destinPath), true);
}
catch (Exception ex)
{
Console.WriteLine("The process failed: {0}", ex.ToString());
}
finally {}
}
}
}
}
// break;
//}
ShowAllFoldersUnder(folder, indent);
}
}
}
catch (UnauthorizedAccessException)
{ }
}
}

Categories

Resources