I am attempting to change the icon of a folder. The code below does all what I found online says to do but the icon never changes. Am I maybe not "Applying" the change?
string createdFile = Path.Combine(#"C:\Users\np\Desktop\PUTEST", "desktop.ini");
if (File.Exists(createdFile))
{
var di = new DirectoryInfo(createdFile);
di.Attributes &= ~FileAttributes.ReadOnly;
File.Delete(createdFile);
File.Create(createdFile).Dispose();
}
else
{
File.Create(createdFile).Dispose();
}
//string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconPath = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\SHELL32.dll");
string iconIndex = "-183";
using (TextWriter tw = new StreamWriter(createdFile))
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
File.SetAttributes(createdFile, System.IO.FileAttributes.ReadOnly);
File.SetAttributes(createdFile, System.IO.FileAttributes.System);
File.SetAttributes(createdFile, System.IO.FileAttributes.Hidden);
When crafting a file like this it's always good to do so using Explorer or Notepad first, then write/adjust your code to match whatever was produced. Otherwise, it's harder to figure out if the problem is with your file or your code.
I believe the minimum requirements to make this work is Desktop.ini must be marked System and the parent directory must be marked ReadOnly (System may work there as well, but I know ReadOnly definitely does). So, your code is working with the right attributes, but there are still a few problems.
Your if ... else ... block is saying "If a file exists at this path, create a directory at that path, then delete the file at that path, then create a file at that path." Of course, the directory should not and cannot have the same path as the file. I assume you are deleting and recreating the file to clear the contents when it already exists, however File.Create() overwrites (truncates) existing files, making the calls to both File.Delete() and File.Exists() unnecessary.
More importantly is this line...
di.Attributes &= ~FileAttributes.ReadOnly;
...with which there are two problems. First, you are ANDing the directory's attributes with the negation of ReadOnly, which has the effect of removing ReadOnly and keeping the other attributes the same. You want to ensure ReadOnly is set on the directory, so you want to do the opposite of the code you used: OR the directory's attributes with ReadOnly (not negated)...
di.Attributes |= FileAttributes.ReadOnly;
Also, you need that attribute set regardless of whether you created the directory or not, so that line should be moved outside of the if ... else ....
Another issue is the successive calls to File.SetAttributes(). After those three calls the file's attributes will be only Hidden, since that was the value of the last call. Instead, you need to combine (bitwise OR) those attributes in a single call.
A couple of other minor tweaks...
As you know since you are calling Dispose() on it, File.Create() returns a FileStream to that file. Instead of throwing it away, you could use it to create your StreamWriter, which will have to create one, anyways, under the covers. Better yet, call File.CreateText() instead and it will create the StreamWriter for you.
Environment variables are supported in Desktop.ini files, so you don't have to expand them yourself. This would make the file portable between systems if, say, you copied it from one system to another, or the directory is on a network share accessed by multiple systems with different %SystemRoot% values.
Incorporating all of the above changes your code becomes...
// Create a new directory, or get the existing one if it exists
DirectoryInfo directory = Directory.CreateDirectory(#"C:\Users\np\Desktop\PUTEST");
directory.Attributes |= FileAttributes.ReadOnly;
string filePath = Path.Combine(directory.FullName, "desktop.ini");
string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconIndex = "-183";
using (TextWriter tw = File.CreateText(filePath))
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
File.SetAttributes(filePath, FileAttributes.ReadOnly | FileAttributes.System | FileAttributes.Hidden);
One catch is that the above code throws an exception if you run it twice in succession. This is because the File.Create*() methods fail if the input file is Hidden or ReadOnly. We could use new FileStream() as an alternative, but that still throws an exception if the file is ReadOnly. Instead, we'll just have to remove those attributes from any existing input file before opening it...
// Create a new directory, or get the existing one if it exists
DirectoryInfo directory = Directory.CreateDirectory(#"C:\Users\np\Desktop\PUTEST");
directory.Attributes |= FileAttributes.ReadOnly;
string filePath = Path.Combine(directory.FullName, "desktop.ini");
FileInfo file = new FileInfo(filePath);
try
{
// Remove the Hidden and ReadOnly attributes so file.Create*() will succeed
file.Attributes = FileAttributes.Normal;
}
catch (FileNotFoundException)
{
// The file does not yet exist; no extra handling needed
}
string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconIndex = "-183";
using (TextWriter tw = file.CreateText())
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
file.Attributes = FileAttributes.ReadOnly | FileAttributes.System | FileAttributes.Hidden;
I changed from using File to FileInfo since that makes this a little easier.
Related
I'm having a problem with a file updating portion of an ASP.NET MVC program I'm working on. The basic premise is that the program will take an edited image from the user, and then update the old file with the new data, keeping the old name. But for some reason, when the file is moved from the temp folder to the folder it's supposed to go to, it's saved as a new file, while keeping the old one. (For example, "foo 1-1.jpg" and "foo 1-1.jpg" exist in the same folder). As far as I can tell, the two filenames are identical. Why is this happening, and how do I make it so that it will delete the old file first, as intended?
I'm getting the old filename before moving it, so there shouldn't be a problem there. There are also no path issues, either.
I'm unsure if there is a problem with the path I'm passing in, but I use the same methodology for getting the filepath to move to, so I don't know why it would fail for File.Delete() and not File.Move().
Here is the code in question:
/// <summary>
/// Move a number of files to a single directory, keeping their names
/// and overwriting if the switch is toggled.
/// Will ignore nonexistent files, and return false if the specified directory does not exist.
/// Returns true if it succeeded, false if it did not.
/// </summary>
/// <param name="filePaths">An array of filepath strings, </param>
/// <param name="saveDirectory">The path to the directory to use</param>
/// <param name="overWrite">Optional, defaults to false. Whether or not
/// to overwrite any existing files with the same name in the new directory.
/// If false, skips files that already exist in destination.</param>
/// <returns>bool</returns>
public static bool MoveSpecificFiles(string[] filePaths, string saveDirectory, bool overWrite = false)
{
//If the directory doesn't exist, error out.
if (!Directory.Exists(saveDirectory))
{
return false;
}
string fileName;
try
{
foreach (string filePath in filePaths)
{
//Check if the file to be moved exists. If it doesn't, skip it and go to the next one.
if (File.Exists(filePath))
{
fileName = Path.GetFileName(filePath);
//if the overwrite flag is set to true and the file exists in the new directory, delete it.
if (overWrite && File.Exists(saveDirectory + fileName))
{
//WHERE THE ERROR IS OCCURING
File.Delete(saveDirectory + fileName);
}
//If the file to be moved does not exist in the new location, move it there.
//This means that duplicate files will not be moved.
if (!File.Exists(saveDirectory + fileName))
{
File.Move(filePath, saveDirectory + fileName);
}
}
//throw new ArgumentException();
}
}
catch (Exception)
{
//check = saveDirectory + " " + Path.GetFileName(filePaths[0]);
return false;
}
return true;
}
Any help would be much appreciated.
The only improvement i can suggest is to use the Path.Combine method to generate the correct path. With this method, you do not need to worry about misssing / at the end etc.
var fullPath = Path.Combine(saveDirectory, fileName);
if (overWrite && File.Exists(fullPath))
{
File.Delete(fullPath);
}
Also since your if condition is checking overWrite variable, make sure that the value of overWrite is true. I suggest you put visual studio breakpoints and inspect the value of this boolean variable and the fullPath variable property.
Also i am not sure what is the value of saveDirectory variable. If it is not the full physical file path on the Web server, Consider using Server.MapPath to get that.
Are you sure you're not missing the slash in the filepath for your if-check?
if (overWrite && File.Exists(saveDirectory + fileName))
You might want to try changing your code to be more like:
if (overWrite && File.Exists(saveDirectory + "\\" + fileName))
I've found the problem. The File.Exists was looking for a .jpeg file, when the original was a .jpg file. Thus, File.Exists didn't find the file, even though the file format was really the same. Just goes to show, check your actual file extensions too!
I am moving files from source folder to destination folder. Before moving files, I am checking that directory exists or not which is working fine. The issue is with my second check where I want to make sure that folder is not empty before moving files but it is not giving me correct result.
public void MoveFilesFromTempToSourceTbl()
{
//Moving all files from temp folder to orig folder.
string sourceFolder = (twitterDO.Path + "\\" + msgDate.Year.ToString() + "\\" + msgDate.Month.ToString() + "\\" + msgDate.Day.ToString() + "_Temp").Replace("\\", #"\");
string destinationFolder = (twitterDO.Path + "\\" + msgDate.Year.ToString() + "\\" + msgDate.Month.ToString() + "\\" + msgDate.Day.ToString()).Replace("\\", #"\");
string pattern = "*.txt";
if (Directory.Exists(sourceFolder))
{
if (File.Exists(pattern))
{
foreach (var file in new DirectoryInfo(sourceFolder).GetFiles(pattern))
{
file.MoveTo(Path.Combine(destinationFolder, file.Name));
}
}
if (Directory.GetFiles(sourceFolder).Length == 0) //Before deleting make sure that Temp folder is empty.
Directory.Delete(sourceFolder, true); // Delete Temp folder after moving all the contents.
}
}
I know I am making some small mistake but not sure what it is. Following is the screenshot of the result which I got in immediate window.
http://imgur.com/FZvo9cj
There's a bit of redundancy in your current code. Starting with the if-checks, here's how I would approach this:
var sourceDirectory = new DirectoryInfo(sourceFolder); // remember this, it is reused
if (sourceDirectory.Exists)
{
// Look for the files in the directory, if none found, will be empty array
foreach (var file in sourceDirectory.GetFiles(pattern))
{
file.MoveTo(Path.Combine(destinationFolder, file.Name));
}
// Re-check the directory for any remaining files
if (sourceDirectory.GetFiles(pattern).Length == 0) //Before deleting make sure that Temp folder is empty.
sourceDirectory.Delete(); // Delete Temp folder after moving all the contents.
}
As a small performance improvement, you could replace sourceDirectory.GetFiles() with sourceDirectory.EnumerateFiles() in the for-loop. This will allow you to start moving them as the method finds them, not after they have all been found.
You are passing "*.txt" into the File.Exists() call when you need to be passing a path.
You can read the Documentation here
Alternatively you could use something like this:
Directory.GetFiles(destinationFolder).Contains(filename)
I agree with David here but also I think the flow of you logic should be adjusted a bit. The File.Exixts(filename); should occur inside the foreach.
That will allow you to iterate each file and if it exists do something.
Try adding the following to check if any files exist in the location:
bool exist = Directory.EnumerateFiles(sourceFolder, "*.txt").Any();
I am trying to create 2 XML files in the same folder.
For some reason it does create the first one, but does not create the second one.
Could it be that the first one is still being created when an attempt to create the second file is made, and therefore the latter fails?
I don't get any errors with the code:
if (File.Exists(FileNameTextBox.Text + ".AA.xml"))
{
MessageBox.Show("Already exists. renaming to *.old" + Environment.NewLine +
"if there is already an *.old file, this will be deleted.");
if (File.Exists(FileNameTextBox.Text + ".AA.xml.old"))
{
File.Delete(FileNameTextBox.Text + ".AA.xml.old");
}
File.Move(FileNameTextBox.Text + ".AA.xml", FileNameTextBox.Text + ".AA.xml.old");
}
if (!File.Exists(FileNameTextBox.Text + ".AA.xml"))
{
XmlTextWriter textWritter = new XmlTextWriter(FileNameTextBox.Text + ".AA.xml", null);
textWritter.WriteStartDocument();
textWritter.WriteStartElement("Data");
textWritter.WriteEndElement();
textWritter.Close();
}
if (File.Exists("BB.xml"))
{
if (File.Exists("BB.xml.old"))
{
File.Delete("BB.xml.old");
}
File.Move("BB.xml", "BB.xml.old");
}
if (!File.Exists("BB.xml"))
{
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
textWritterPC3.WriteStartDocument();
textWritterPC3.WriteStartElement("Data");
textWritterPC3.WriteEndElement();
textWritterPC3.Close();
}
Whats in FileNameTextBox.Text? Does it specify a directory path?
Your second file is created without saying which directory. So it will be created in the current directory - which is not necessarily the directory specified by FileNameTextBox.Text
You are not specifying an absolute path for your file names, so you are using whatever the current directory happens to be, which is not reliable. Also you may need to call DirectoryInfo.Refresh() or FileInfo.Refresh() to make sure you are seeing the latest directory information (whether the file exists or not).
The comment is only making the last if case execute the first row.. The last if should look like this. I don't know if it's only in your example.
Your example
if (!File.Exists("BB.xml")) // {
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
should be
if (!File.Exists("BB.xml")) //
{
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
textWritterPC3.WriteStartDocument();
textWritterPC3.WriteStartElement("Data");
textWritterPC3.WriteEndElement();
textWritterPC3.Close();
}
I'm having a little bit of trouble writing to a text file within a folder I tried to create. It said I didn't have access to the path 'C:\'
Could anyone tell me why and how to fix it? Thanks!
string file_name = Environment.CurrentDirectory;
file_name += #"\.";
file_name = (string)combobox1.SelectedValue;
file_name += #"\.";
file_name += (string)combobox2.SelectedValue;
TextWriter name = new StreamWriter(file_name);
EDIT: Here's the new code after revisions...
var location = Path.Combine(Environment.CurrentDirectory, (string)combobox1.SelectedItem);
Directory.CreateDirectory(location);
var path = Path.Combine(location, combobox2.SelectedItem);
TextWriter name = new StreamWriter(path, true);
My goal is to write a text file to \\.txt
Could anyone tell me how? Thanks!
have you checked the value of file_name to make sure is a valid Path?
you have missed a concatenation anyway at line number 3
string file_name = Environment.CurrentDirectory;
file_name += #"\.";
file_name += (string)combobox1.SelectedValue; // <--
file_name += #"\.";
file_name += (string)combobox2.SelectedValue;
TextWriter name = new StreamWriter(file_name);
The account that the application is running under does not have write permissions in the location you are trying to save the file to.
This article goes over how to resolve this issue:
http://www.phdcc.com/findinsite/instperm.htm
You should be using Path.Combine():
var fileName = Path.Combine(Environment.CurrentDirectory, (string)comboBox1.SelectedValue,
(string)comboBox2.SelectedValue);
If at that point it still doesn't work, at least you'll know it's actually a permissions/existence/etc. issue, rather than an issue with the way you've constructed the file name.
The solution here is a combination of what everyone else has said.
As has already been pointed out, this line:
file_name = (string)combobox1.SelectedValue;
is incorrectly doing an assignment (=) instead of a concatenation (+=). This means that if comboxbo1.SelectedValue is null, your path becomes \., which is the root directory of the drive.
You need to remember that it's legal for SelectedValue to be null, because a combo box can have an empty selection. You need to handle that case, perhaps by disabling your save functionality until the combo boxes have valid selections.
This isn't really a problem with permissions; it's unlikely that you actually need or intend to write to the root directory, which is why you aren't given that permission in the first place.
Wondering how to best deal with a problem I am having with xsltransform. Long story short, everything works in my test environment, but it crashes when I run it on the server due to the filenames it tries to deal with, which are output from another program, over which I have no control.
For example. "4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml" a simple # would solve this, but it's actually running on a service, and this service gets all files of that type in the directory and processes them one by one.
string[] filepaths = Directory.GetFiles(path, Filetype);
I keep the file name variable in:
FileInfo f = new FileInfo(filepaths[i]);
But the method I use for the transform:
myXslTransform = new XslCompiledTransform();
myXslTransform.Transform(filename,OutputFileName);
Only accepts (String, String) and thus when it sees "4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml" it has a heart attack and cuts it off.
I was thinking save the original name, rename, remove whitespace, transform, and rename back. But I think there is a smarter way to handle it out there, just not sure where to look. Is there a way of telling C# to handle a variable as a literal? Or a different transform method that accepts these weird filenames with very bad naming conventions?
Any insight that helps would be great!
The error & exception message I recieve from the Eventvwr is
Cannot Translate
\\9g031\Export\4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml
OutputName = \\9g031\Export\done\4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml
XSL LOC = C:\CXS.xsl
System.IO.IOException: The specified path is invalid.
private void PreformTranslation(FileInfo FileName, String OutputFileName , String result)
{
try
{
XslCompiledTransform myXslTransform;
myXslTransform = new XslCompiledTransform();
myXslTransform.Load(XSLname);
EventLog.WriteEntry(FileName.ToString(), OutputFileName);
myXslTransform.Transform(FileName.Name,OutputFileName);
EventLog.WriteEntry("TranslationComplete");
if (File.Exists(path + result))
{
MoveVideoFiles(path + result, outputPath + result);
}
// Rename(OutputFileName, FileName, Out);
}
catch (Exception e)
{
EventLog.WriteEntry("Cannot Translate " + FileName + " OutputName = " + OutputFileName + " \r\n"+
"XSL LOC = " + XSLname + "\r\n" + e);
}
}
The default directory when running a service is something like "windows/system32" and this isn't the directory of the executable.
This is probably the reason the XML file isn't found.