FileInfo.MoveTo() vs File.Move() - c#

Is there any difference between these two methods of moving a file?
System.IO.FileInfo f = new System.IO.FileInfo(#"c:\foo.txt");
f.MoveTo(#"c:\bar.txt");
//vs
System.IO.File.Move(#"c:\foo.txt", #"c:\bar.txt");

Take a look at "Remarks" section in this MSDN page http://msdn.microsoft.com/en-us/library/akth6b1k.aspx :
If you are going to reuse an object several times, consider using the instance method of FileInfo instead of the corresponding static methods of the File class, because a security check will not always be necessary.
I think this difference is most significant between File (Directory) and FileInfo (DirectoryInfo) classes.
Update: The same explanation in similar question: https://stackoverflow.com/a/1324808/380123

Via RedGate Reflector:
File.Move()
public static void Move(string sourceFileName, string destFileName)
{
if ((sourceFileName == null) || (destFileName == null))
{
throw new ArgumentNullException((sourceFileName == null) ? "sourceFileName" : "destFileName", Environment.GetResourceString("ArgumentNull_FileName"));
}
if ((sourceFileName.Length == 0) || (destFileName.Length == 0))
{
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), (sourceFileName.Length == 0) ? "sourceFileName" : "destFileName");
}
string fullPathInternal = Path.GetFullPathInternal(sourceFileName);
new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand();
string dst = Path.GetFullPathInternal(destFileName);
new FileIOPermission(FileIOPermissionAccess.Write, new string[] { dst }, false, false).Demand();
if (!InternalExists(fullPathInternal))
{
__Error.WinIOError(2, fullPathInternal);
}
if (!Win32Native.MoveFile(fullPathInternal, dst))
{
__Error.WinIOError();
}
}
and FileInfo.MoveTo()
public void MoveTo(string destFileName)
{
if (destFileName == null)
{
throw new ArgumentNullException("destFileName");
}
if (destFileName.Length == 0)
{
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "destFileName");
}
new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new string[] { base.FullPath }, false, false).Demand();
string fullPathInternal = Path.GetFullPathInternal(destFileName);
new FileIOPermission(FileIOPermissionAccess.Write, new string[] { fullPathInternal }, false, false).Demand();
if (!Win32Native.MoveFile(base.FullPath, fullPathInternal))
{
__Error.WinIOError();
}
base.FullPath = fullPathInternal;
base.OriginalPath = destFileName;
this._name = Path.GetFileName(fullPathInternal);
base._dataInitialised = -1;
}

An important difference is that FileInfo.MoveTo() will update the filepath of the FileInfo object to the destination path. This is obviously not the case of File.Move() since it only uses strings as input.

The only significant difference I can see is File.Move is static and FileInfo.MoveTo is not.Apart from that they run approximately the same code.

Related

How can I put the code block into a function in c#?

I would want to use a function in the place of the if/else-clause.
public void CopyPasteFiles(string modelInfoFilePath, string definitionFilePath, string pedName)
{
string messageBoxText = "Looks like a ped with this name already Exists. Please try a new Name.";
if (this.IsMale)
{
modelInfoFilePath = Tokenizer.Detokenize(modelInfoFilePath);
this.NewModelInfoPath = modelInfoFilePath.Replace("Z_Z_ProxyPed_MR1_000_Dummy", pedName);
if (!File.Exists(this.NewModelInfoPath))
{
File.Copy(modelInfoFilePath, this.NewModelInfoPath, false);
FileInfo fileInfo = new FileInfo(this.NewModelInfoPath);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
definitionFilePath = Tokenizer.Detokenize(definitionFilePath);
this.NewDefinitionPath = definitionFilePath.Replace("Z_Z_ProxyPed_MR1_000_Dummy", pedName);
if (!File.Exists(this.NewDefinitionPath))
{
File.Copy(definitionFilePath, this.NewDefinitionPath, false);
FileInfo fileInfo = new FileInfo(this.NewDefinitionPath);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
}
else if (this.IsFemale)
{
modelInfoFilePath = Tokenizer.Detokenize(modelInfoFilePath);
this.NewModelInfoPath = modelInfoFilePath.Replace("Z_Z_ProxyPed_FR1_000_Dummy", pedName);
if (!File.Exists(this.NewModelInfoPath))
{
File.Copy(modelInfoFilePath, this.NewModelInfoPath, false);
FileInfo fileInfo = new FileInfo(this.NewModelInfoPath);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
definitionFilePath = Tokenizer.Detokenize(definitionFilePath);
this.NewDefinitionPath = definitionFilePath.Replace("Z_Z_ProxyPed_FR1_000_Dummy", pedName);
if (!File.Exists(this.NewDefinitionPath))
{
File.Copy(definitionFilePath, this.NewDefinitionPath, false);
FileInfo fileInfo = new FileInfo(this.NewDefinitionPath);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
}
}
Let's see: you have the following piece of code which comes back constantly:
if (!File.Exists(New_Information))
{
File.Copy(Existing_Information, New_Information, false);
FileInfo fileInfo = new FileInfo(New_Information);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
This means that you need to write a function, using the two parameters Existing_Information and New_Information, something like:
void Do_Something(var Existing_Information, var New_Information)
{
if (!File.Exists(New_Information))
{
File.Copy(Existing_Information, New_Information, false);
FileInfo fileInfo = new FileInfo(New_Information);
fileInfo.IsReadOnly = false;
}
else
{
RsMessageBox.Show(messageBoxText);
}
}
Inside your code, you just replace your if-loop by that function, using the correct parameters:
Do_Something(modelInfoFilePath, this.NewmodelInfoFilePath);
...
Do_Something(definitionFilePath, this.DefinitionFilePath);
...
First you should analyze what parts of your code are the same, and which variables can be substituted for parameters.
Looking at your code, I see 4 parts that are somewhat similar.
2 of them are for this.IsMale, and two of them are this.IsFemale (which could also be !this.IsMale considering a binary biological standpoint). We can use this to change the string itself, instead of using two if statements.
2 of them use modelInfoFilePath, while the other 2 use definitionFilePath.
If we declare these first, we can use them as parameters for a CopyFile method.
Take a look at this code below, you might see what I mean.
public void CopyPasteFiles(string modelInfoFilePath, string definitionFilePath, string pedName)
{
modelInfoFilePath = Tokenizer.Detokenize(modelInfoFilePath);
definitionFilePath = Tokenizer.Detokenize(definitionFilePath);
string pedReplaceName = this.IsMale : "Z_Z_ProxyPed_MR1_000_Dummy" ? "Z_Z_ProxyPed_FR1_000_Dummy";
// replace names
this.NewModelInfoPath =
modelInfoFilePath.Replace(pedReplaceName, pedName);
this.NewDefinitionPath =
definitionFilePath.Replace(pedReplaceName, pedName);
// copy files
CopyFile(modelInfoFilePath, this.NewModelInfoPath);
CopyFile(definitionFilePath, this.NewDefinitionPath);
}
public void CopyFile(filePath, newFilePath) {
if (!File.Exists(newFilePath))
{
File.Copy(filePath, newFilePath, false);
FileInfo fileInfo = new FileInfo(newFilePath);
fileInfo.IsReadOnly = false;
}
else {
RsMessageBox.Show("Looks like a ped with this name already exists. Please try a new Name.");
}
}

ConfigurationErrorsException- The process cannot access the file 'c:\eventlog.config' because it is being used by another process

Team,
I have this piece of code which invariably ties up itself in a sort of race condition especially when two or more resources are trying to write to eventlog.config file simultaneously. I have googling out several channels but not able to solve this error out. Can anyone help me to modify this code so that i can remove the race condition.
private void UpdateLastEventId(IList<EventLogEntry> entries)
{
if (entries.Count > 0)
{
EventLogEntry lastEntry = entries[entries.Count - 1];
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var configSettings = config.AppSettings.Settings;
string key = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", _eventLogFilter.EventLog, _eventLogFilter.MD5Hash);
if (configSettings[key] == null)
{
configSettings.Add(key, lastEntry.Index.ToString(CultureInfo.InvariantCulture));
}
else
{
configSettings[key].Value = lastEntry.Index.ToString(CultureInfo.InvariantCulture);
}
config.Save(ConfigurationSaveMode.Modified);//Error seems to happen here
}
}
private static readonly object _configLogLock = new object();
private void UpdateLastEventId(IList<EventLogEntry> entries)
{
if (entries.Count > 0)
{
EventLogEntry lastEntry = entries[entries.Count - 1];
lock (_configLogLock)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var configSettings = config.AppSettings.Settings;
string key = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", _eventLogFilter.EventLog, _eventLogFilter.MD5Hash);
if (configSettings[key] == null)
{
configSettings.Add(key, lastEntry.Index.ToString(CultureInfo.InvariantCulture));
}
else
{
configSettings[key].Value = lastEntry.Index.ToString(CultureInfo.InvariantCulture);
}
config.Save(ConfigurationSaveMode.Modified);//Error seems to happen here
}
}
}

c# nullreference for save on load streamreader/writer

I've made a program and I want to save the data. Saving is working, but "Loading" doesn't work.
public void Save(StreamWriter sw)
{
for (int i = 0; i < buecher.Count; i++)
{
Buch b = (Buch)buecher[i];
if (i == 0)
sw.WriteLine("ISDN ; Autor ; Titel");
sw.WriteLine(b.ISDN + ";" + b.Autor + ";" + b.Titel);
}
}
public void Load(StreamReader sr)
{
int isd;
string aut;
string tit;
while (sr.ReadLine() != "")
{
string[] teile = sr.ReadLine().Split(';');
try
{
isd = Convert.ToInt32(teile[0]);
aut = teile[1];
tit = teile[2];
}
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
Buch b = new Buch(isd, aut, tit);
buecher.Add(b);
}
}
If I'm doing that with an break after buecher.Add(b); than its everything fine but it obviously shows me only 1 book... if I'm not using the break he gives me an error "nullreference.."
Would be awesome if someone could help me
best regards
Ramon
The problem is that you are reading two lines for each iteration in the loop (and throwing away the first one). If there are an odd number of lines in the file, the second call to Read will return null.
Read the line into a variable in the condition, and use that variable in the loop:
public void Load(StreamReader sr) {
int isd;
string aut;
string tit;
// skip header
sr.ReadLine();
string line;
while ((line = sr.ReadLine()) != null) {
if (line.Length > 0) {
string[] teile = line.Split(';');
try {
isd = Convert.ToInt32(teile[0]);
aut = teile[1];
tit = teile[2];
} catch {
throw new Exception("umwandlung fehlgeschlagen");
}
Buch b = new Buch(isd, aut, tit);
buecher.Add(b);
}
}
}
You are calling sr.ReadLine() twice for every line, once in the while() and once right after. You are hitting the end of the file, which returns a null.
Different approach to this but I suggest it because it's simpler;
Load(string filepath)
{
try
{
List<Buch> buches = File.ReadAllLines(filepath)
.Select(x => new Buch(int.Parse(x.Split(';')[0]), x.Split(';')[1], x.Split(';')[2]));
{
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
}
You could do it in more lines if you find it to be more readable but I've come to prefer File.ReadAllText and File.ReadAllLines to StreamReader approach of reading files.
Instead of using the LINQ statement you could also do;
Load(string filepath)
{
try
{
string[] lines = File.ReadAllLines(filepath);
foreach (string line in lines)
{
string[] tokens = line.Split(';');
if (tokens.Length != 3)
// error
int isd;
if (!int.TryParse(tokens[0], out isd))
//error, wasn't an int
buetcher.Add(new Buch(isd, tokens[1], tokens[2]);
}
{
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
}

Get to an Exchange folder by path using EWS

I need to retrieve items from the 'Inbox\test\final' Exchange folder using EWS. The folder is provided by a literal path as written above. I know I can split this string into folder names and recursively search for the necessary folder, but is there a more optimal way that can translate a string path into a folder instance or folder ID?
I'm using the latest EWS 2.0 assemblies. Do these assemblies provide any help, or am I stuck with manual recursion?
You could use an extended property as in this example
private string GetFolderPath(ExchangeService service, FolderId folderId)
{
var folderPathExtendedProp = new ExtendedPropertyDefinition(26293, MapiPropertyType.String);
var folderPropSet = new PropertySet(BasePropertySet.FirstClassProperties) { folderPathExtendedProp };
var folder = Folder.Bind(service, folderId, folderPropSet);
string path = null;
folder.TryGetProperty(folderPathExtendedProp, out path);
return path?.Replace("\ufffe", "\\");
}
Source: https://social.msdn.microsoft.com/Forums/en-US/e5d07492-f8a3-4db5-b137-46e920ab3dde/exchange-ews-managed-getting-full-path-for-a-folder?forum=exchangesvrdevelopment
Since Exchange Server likes to map everything together with Folder.Id, the only way to find the path you're looking for is by looking at folder names.
You'll need to create a recursive function to go through all folders in a folder collection, and track the path as it moves through the tree of email folders.
Another parameter is needed to track the path that you're looking for.
public static Folder GetPathFolder(ExchangeService service, FindFoldersResults results,
string lookupPath, string currentPath)
{
foreach (Folder folder in results)
{
string path = currentPath + #"\" + folder.DisplayName;
if (folder.DisplayName == "Calendar")
{
continue;
}
Console.WriteLine(path);
FolderView view = new FolderView(50);
SearchFilter filter = new SearchFilter.IsEqualTo(FolderSchema.Id, folder.Id);
FindFoldersResults folderResults = service.FindFolders(folder.Id, view);
Folder result = GetPathFolder(service, folderResults, lookupPath, path);
if (result != null)
{
return result;
}
string[] pathSplitForward = path.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
string[] pathSplitBack = path.Split(new[] { #"\" }, StringSplitOptions.RemoveEmptyEntries);
string[] lookupPathSplitForward = lookupPath.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
string[] lookupPathSplitBack = lookupPath.Split(new[] { #"\" }, StringSplitOptions.RemoveEmptyEntries);
if (ArraysEqual(pathSplitForward, lookupPathSplitForward) ||
ArraysEqual(pathSplitBack, lookupPathSplitBack) ||
ArraysEqual(pathSplitForward, lookupPathSplitBack) ||
ArraysEqual(pathSplitBack, lookupPathSplitForward))
{
return folder;
}
}
return null;
}
"ArraysEqual":
public static bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (ReferenceEquals(a1, a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
I do all the extra array checking since sometimes my clients enter paths with forward slashes, back slashes, starting with a slash, etc. They're not tech savvy so let's make sure the program works every time!
As you go through each directory, compare the desired path to the iterated path. Once it's found, bubble up the Folder object that it's currently on. You'll need to create a search filter for that folder's id:
FindItemsResults<item> results = service.FindItems(foundFolder.Id, searchFilter, view);
Loop through the emails in results!
foreach (Item item in results)
{
// do something with item (email)
}
Here's my recursive descent implementation, which attempts to fetch as little information as possible on the way to the target folder:
private readonly FolderView _folderTraversalView = new FolderView(1) { PropertySet = PropertySet.IdOnly };
private Folder TraceFolderPathRec(string[] pathTokens, FolderId rootId)
{
var token = pathTokens.FirstOrDefault();
var matchingSubFolder = _exchangeService.FindFolders(
rootId,
new SearchFilter.IsEqualTo(FolderSchema.DisplayName, token),
_folderTraversalView)
.FirstOrDefault();
if (matchingSubFolder != null && pathTokens.Length == 1) return matchingSubFolder;
return matchingSubFolder == null ? null : TraceFolderPathRec(pathTokens.Skip(1).ToArray(), matchingSubFolder.Id);
}
For a '/'-delimited path, it can be called as follows:
public Folder TraceFolderPath(string folderPath)
{ // Handle folder names with '/' in them
var tokens = folderPath
.Replace("\\/", "<slash>")
.Split('/')
.Select(t => t.Replace("<slash>", "/"))
.ToArray();
return TraceFolderPathRec(tokens, WellKnownFolderName.MsgFolderRoot);
}
No, you don't need recursion and you efficiently go straight to the folder. This uses the same extended property as Tom, and uses it to apply a search filter:
using Microsoft.Exchange.WebServices.Data; // from nuget package "Microsoft.Exchange.WebServices"
...
private static Folder GetOneFolder(ExchangeService service, string folderPath)
{
var propertySet = new PropertySet(BasePropertySet.IdOnly);
propertySet.AddRange(new List<PropertyDefinitionBase> {
FolderSchema.DisplayName,
FolderSchema.TotalCount
});
var pageSize = 100;
var folderView = new FolderView(pageSize)
{
Offset = 0,
OffsetBasePoint = OffsetBasePoint.Beginning,
PropertySet = propertySet
};
folderView.Traversal = FolderTraversal.Deep;
var searchFilter = new SearchFilter.IsEqualTo(ExchangeExtendedProperty.FolderPathname, folderPath);
FindFoldersResults findFoldersResults;
var baseFolder = new FolderId(WellKnownFolderName.MsgFolderRoot);
var localFolderList = new List<Folder>();
do
{
findFoldersResults = service.FindFolders(baseFolder, searchFilter, folderView);
localFolderList.AddRange(findFoldersResults.Folders);
folderView.Offset += pageSize;
} while (findFoldersResults.MoreAvailable);
return localFolderList.SingleOrDefault();
}
...
public static class ExchangeExtendedProperty
{
/// <summary>PR_FOLDER_PATHNAME String</summary>
public static ExtendedPropertyDefinition FolderPathname { get => new ExtendedPropertyDefinition(0x66B5, MapiPropertyType.String); }
}
The path will need to be prefixed with a backslash, ie. \Inbox\test\final.

Paths from a directory tree array

I am using Directory.GetFiles to find files that will be copied. I need to find the paths of the files so I can use copy, but I have no idea how to find the path.
It iterates through the files fine, but I can't copy or move them because I need the file's source path.
This is what I have:
string[] files = Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories);
System.Console.WriteLine("Files Found");
// Display all the files.
foreach (string file in files)
{
string extension = Path.GetExtension(file);
string thenameofdoom = Path.GetFileNameWithoutExtension(file);
string filename = Path.GetFileName(file);
bool b = false;
string newlocation = (#"\\TEST12CVG\Public\Posts\Temporaryjunk\");
if (extension == ".pst" ||
extension == ".tec" ||
extension == ".pas" ||
extension == ".snc" ||
extension == ".cst")
{
b = true;
}
if (thenameofdoom == "Plasma" ||
thenameofdoom == "Oxygas" ||
thenameofdoom == "plasma" ||
thenameofdoom == "oxygas" ||
thenameofdoom == "Oxyfuel" ||
thenameofdoom == "oxyfuel")
{
b = false;
}
if (b == true)
{
File.Copy(file, newlocation + thenameofdoom);
System.Console.WriteLine("Success: " + filename);
b = false;
}
}
Path.GetFullPath works, but also consider using FileInfo as it comes with many file helper methods.
I would use a method similar to this (could use a lot more error handling (try catches...) but it's a good start
EDIT I noticed that you are filtering out the extensions, but requiring them, update to code allows for that
class BackupOptions
{
public IEnumerable<string> ExtensionsToAllow { get; set; }
public IEnumerable<string> ExtensionsToIgnore { get; set; }
public IEnumerable<string> NamesToIgnore { get; set; }
public bool CaseInsensitive { get; set; }
public BackupOptions()
{
ExtensionsToAllow = new string[] { };
ExtensionsToIgnore = new string[] { };
NamesToIgnore = new string[] { };
}
}
static void Backup(string sourcePath, string destinationPath, BackupOptions options = null)
{
if (options == null)
optionns = new BackupOptions();
string[] files = Directory.GetFiles(sourcePath, ".", SearchOption.AllDirectories);
StringComparison comp = options.CaseInsensitive ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
foreach (var file in files)
{
FileInfo info = new FileInfo(file);
if (options.ExtensionsToAllow.Count() > 0 &&
!options.ExtensionsToAllow.Any(allow => info.Extension.Equals(allow, comp)))
continue;
if (options.ExtensionsToIgnore.Any(ignore => info.Extension.Equals(ignore, comp)))
continue;
if (options.NamesToIgnore.Any(ignore => info.Name.Equals(ignore, comp)))
continue;
try
{
File.Copy(info.FullName, destinationPath + "\\" + info.Name);
}
catch (Exception ex)
{
// report/handle error
}
}
}
With a call like:
var options = new BackupOptions
{
ExtensionsToAllow = new string[] { ".pst", ".tec", ".pas", ".snc", ".cst" },
NamesToIgnore = new string[] { "Plasma", "Oxygas", "Oxyfuel" },
CaseInsensitive = true
};
Backup("D:\\temp", "D:\\backup", options);

Categories