I need to create a .txt file in C# .
Is there a way (and how to do?) to create a file and open it in Notepad, but without saving in somewhere first? The user would save it after he checks it.
No not really, i've seen some programs that do this like so, but its not ideal:
Create a temporary file, most programs use the temp directory
you get there by using %temp% or C:\Users\{username}\AppData\Local\Temp so e.g. File.Create(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt")
Open the file with notepad. (File.Open(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt"))
The user makes the change and saves
Your program checks the file to see if any edits were made.
if any edits have been made, you can prompt the user to save the file to the actual location.
e.g. !string.IsNullOrWhiteSpace(File.ReadAllText(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt"))
If the user wants to save the file, the file gets copied to the real location
File.Copy(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt", #"c:\myRealPath\MyRealFileName.txt"
I created a way (I don't know if it already exists), using System.Diagnostics and System.Reflection libraries. My code is:
File.WriteAllText($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt", "information inside file");
while (!File.Exists($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt")) { }
Process.Start($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt");
while (Process.GetProcesses().Where(prc => { try { return prc.MainWindowTitle.Contains("exampleDoc.txt"); } catch { return false; } }).Count() == 0) { }
File.Delete($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt");
Related
I am using C# to create a GUI which has a logging feature. When I create the log file, I provide it a filename. But I have the following issue. For instance, if the file is already open in the background on my desktop and I want to name my filename as the same, I get the exception message as following:
The process cannot access the file 'C:\blah\blah\mytest.csv' because it is being used by another process.
I am using the following piece of code to check if the file exists and using the streamwriter to create the new file.
if (FileUtils.Exists(fileName))
{
if (!FileUtils.Delete(fileName))
{
cout<< Error replacing log file, it might be used by another process";
}
}
//Exception handling
public static bool Delete(string myfiletowrite)
{
try
{
File.Delete(myfiletowrite);
return true;
}
catch (IOException)
{
return false;
}
}
myfile= new StreamWriter(myfiletowrite, true); //exception occurs here when I try to write to myfiletowrite which is currently open
I am unsure on how to close this file which is open in the background so I could write to this file. I would appreciate it someone could help me with this.
If the other application did not explicitely allow it (via Share mode), it is not possible to open the file for writing.
If the other application is under your control, you have some options (open the file with FileShare.Write, implement some communication protocol between the two applications, use a common service for accessing the file, ...).
Best option would be to choose a different file name.
I have a function that checks every file in a directory and writes a list to the console. The problem is, I don't want it to include files that are currently being copied to the directory, I only want it to show the files that are complete. How do I do that? Here is my code:
foreach (string file in Directory.EnumerateFiles("C:\folder"))
{
Console.WriteLine(file);
}
There's really no way to tell "being copied" vs "locked for writing by something". Relevant: How to check for file lock? and Can I simply 'read' a file that is in use?
If you want to simply display a list of files that are not open for writing, you can do that by attempting to open them:
foreach (string file in Directory.EnumerateFiles("C:\folder"))
{
try {
using (var file = file.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) {
Console.WriteLine(file);
}
} catch {
// file is in use
continue;
}
}
However -- lots of caveats.
Immediately after displaying the filename (end of the using block) the file could be opened by something else
The process writing the file may have used FileShare.Read which means the call will succeed, despite it being written to.
I'm not sure what exactly you're up to here, but it sounds like two processes sharing a queue directory: one writing, one reading/processing. The biggest challenge is that writing a file takes time, and so your "reading" process ends up picking it up and trying to read it before the whole file is there, which will fail in some way depending on the sharing mode, how your apps are written, etc.
A common pattern to deal with this situation is to use an atomic file operation like Move:
Do the (slow) write/copy operation to a temporary directory that's on the same file system (very important) as the queue directory
Once complete, do a Move from the temporary directory to the queue directory.
Since move is atomic, the file will either not be there, or it will be 100% there -- there is no opportunity for the "reading" process to ever see the file while it's partially there.
Note that if you do the move across file systems, it will act the same as a copy.
There's no "current files being copied" list stored anywhere in Windows/.NET/whatever. Probably the most you could do is attempt to open each file for append and see if you get an exception. Depending on the size and location of your directory, and on the security setup, that may not be an option.
There isn't a clean way to do this, but this... works...
foreach (var file in new DirectoryInfo(#"C:\Folder").GetFiles())
{
try
{
file.OpenRead();
}
catch
{
continue;
}
Console.WriteLine(file.Name);
}
I have an application where I generate Report at the end of all the materials, by Hitting generate Report button. The report is generated in Excel format. The problem is that whenever I create one report, I can create another report with the same name on the same location. It basically overrides the first report.
I want to give the user a box saying that you can generate a report with the same name or the name already exists and choose a different name.
Thanks for the help!
Just before you save the file you should know what the Filename you are going to save it as. If so then just test if the File already exists. If it does then prompt the user for a new name and save it as the new name e.g.
string filename = #"C:\File.txt";
if(File.Exists(filename)){
// Prompt for new one.
// save the report to the new name instead.
}else
{
// save to filename
}
How about before saving a file, check if the file with this name already exists and if it does, offer to rename the file. Something like this:
if(File.Exists(proposedFileName)){
showDialog("file exists, please choose other name");
}
I always do what DarkXphenomenon suggested, I append a mildate timestamp to the filename of the form:
<filename>_YYMMDD_HHMMSS.ext
While this is't rught for every situation, it has a lot of advantages:
Its simple, and it works
It saves me from having to write in all kinds of gyrations for going back and forth with the user over the name, overwriting, renaming, canceling, etc. Usually deep in code that was never intended to have a user interface.
It makes automation much easier.
It makes testing easier.
It makes diagnosing user problems easier: there's no question over when a file was created or in what order they were created.
Before creating the report you can iterate through the existing files and check whether the name already exists and give proper error message.
string newFileName = "new file";
string[] fileNames = Directory.GetFiles("path");
foreach (string file in fileNames)
{
if (file == newFileName)
{
MessageBox.Show("Error");
break;
}
}
I use Word.Interop to work with Word Document and let user to open a file from hard disk.
Sometimes I get error saying that the file that user has chosen is readonly.
How can I check if a file is readonly or not?
Are you sure you are actually talking about the File attribute (that can be set via the Windows file properties dialog)? If so, you can use FileInfo.IsReadOnly:
FileInfo fileInfo = new FileInfo(#"path\to\file");
if (fileInfo.IsReadOnly)
{
// do something
}
otherwise, refer to this answer if another process is using the file.
i have written some pdf files to a temp directory and these get displayed as a thumbnail that the user can view. when i close my form i clean up all of the files in the temp directory.
If however the user has one of the thumbnails open and then closes my application - it deletes the files and then throws an exception because the pdf is open in another process and cant be cleaned up.
I guess this is a shocking programming decision by me, but i am still a novice! How should i account for this in my code?
Thanks
You can detect if the file is in use by using code similar to below, then use that to warn the user that a file can't be deleted.
Unfortunately you can't delete a file that is in use.
public static bool IsFileInUse(string pathToFile)
{
if (!System.IO.File.Exists(pathToFile))
{
// File doesn't exist, so we know it's not in use.
return false;
}
bool inUse = false;
System.IO.FileStream fs;
try
{
fs = System.IO.File.Open(pathToFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Read, System.IO.FileShare.None);
fs.Close();
}
catch (System.IO.IOException ex)
{
string exMess = ex.Message;
inUse = true;
}
return inUse;
}
You should catch that exception (in catch block you can inform user to close that file or it will not be deleted), and if the temp directory is yours you can try to delete it when application starts (or when it ends again), if its windows temp directory, then it does not matter that much
Tools like File Unlocker can release a file. However I think this could make programs depending on the file crash...
Maybe you can look up how they unlock files or manage to execute the unlocker via Process.Start to unlock your file and delete it.
However if it's you blocking the file you should try and fix this in your programm. Maybe you should dispose all loaded files (filestreams etc) before trying to clean it up.