I need to append data to a file, but if the file does not exist I need to add a header before appending.
If I open the file with FileMode.Append, I cannot see a way to work out if the file is new or not.
If I open the file with
FileStream file;
boolean isNew;
try
{
file = File.Open(path, FileMode.CreateNew);
isNew = true;
}
catch (IOException ex)
{
file = File.Open(path, FileMode.Append);
isNew = false;
}
I run into the risk of another process deleting the file between the the 2 open calls and not detecting the creation of the new file.
What is the recommended way of opening for appending and detecing if create or append?
Does this do what you need?
try
{
var file = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
if (file.Length == 0)
{
// do header stuff
}
// do the rest
}
catch (IOException ex)
{
// handle io ex.
}
Try something like this:
if (!File.Exists(path))
{
file = File.Open(path, FileMode.CreateNew);
isNew = true;
return;
}
// otherwise append to existing file
file = File.Open(path, FileMode.Append);
isNew = false;
Related
I have a certain requirement. When current line of code throwing exception, I want to move to next line
FileStream fs = new FileStream("D:/temp/product.xml", FileMode.Open, FileAccess.Read);
sometimes D:/ drive don't have xml file, it throwing FileNotFoundException and jumping control out of scope. but then in next line I want to check another location
FileStream fs = new FileStream("//letp.rf.servername.com/products/product.xml", FileMode.Open, FileAccess.Read);
How can I fix this issue?
Use defensive check and check whether the file exists first using File.Exists(String) method before actually accessing it. Again, wherever possible we should use Defensive Check rather Exception Handling since exception handling is expensive operation. How expensive are exceptions in C#?
Finally, you can wrap this entirely in a try .. catch block to make sure catching any other exception down the line and logging them.
try
{
if (File.Exists("D:/temp/product.xml"))
{
FileStream fs = new FileStream("D:/temp/product.xml", FileMode.Open, FileAccess.Read);
}
else
{
// check another location
}
}
catch (Exception ex)
{
// perform logging
}
All you need to do is wrap your code in a try-catch block, for example:
FileStream fs = null;
try
{
fs = new FileStream("D:/temp/product.xml", FileMode.Open, FileAccess.Read);
}
catch (FileNotFoundException e)
{
// Retry another file,
}
If the retry can also fail, you'll have to wrap it also.
(Btw, Rahul's answer is better and easier)
To use this in a loop:
FileSystem fs = null;
foreach (var file in files) // files contains the file paths
{
// Solution #1
try
{
fs = new FileStream(file, FileMode.Open, FileAccess.Read);
break;
}
catch (FileNotFoundException e) { }
// Or you can use File.Exists as per Rahul's answer
// Solution #2
if (File.Exists(file))
{
fs = new FileStream(file, FileMode.Open, FileAccess.Read);
break;
}
}
Don't use exceptions to check whether a file exists, but check whether the file exists via File.Exists:
string defaultPath = "D:/temp/product.xml";
string alternativePath = "//letp.rf.servername.com/products/product.xml";
string path = File.Exists(defaultPath) ? defaultPath : alternativePath;
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
If you want to check for another path if the second one is not found, you might want to use the following approach with an array of paths. With that, you are totally flexible how many paths you want to check.
string[] paths = new string[] { #"C:\first\path\product.xml", #"C:\second\path\product.xml", #"C:\third\path\product.xml"};
string path = paths.FirstOrDefault(p => File.Exists(p));
if(path == null)
{
Console.WriteLine("None of the files exists!");
}
else
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
}
Just use try and catch and loop:
foreach (var file in files)
{
try
{
FileStream fs = new FileStream(file , FileMode.Open, FileAccess.Read);
}
catch(Exception ex)
{}
}
Pretty new to C#. Trying to iteratively write to a .txt file and I tried to use this to implement the solution:
Create a .txt file if doesn't exist, and if it does append a new line
I have it written as such:
var path = #"C:\Test\test.txt";
try
{
if (!File.Exists(path))
{
File.Create(path);
TextWriter tw = new StreamWriter(path);
tw.WriteLine(message);
tw.Close();
}
else if (File.Exists(path))
{
using (var tw = new StreamWriter(path, true))
{
tw.WriteLine(message);
tw.Close();
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Whether or not the file exists, it generates the same error:
"System.IO.IOException: The process cannot access the file 'C:\Test\test.txt' because it is being used by another process"
What am I doing wrong this time?
File.Create(path); opens the file and leaves it opened. When you do TextWriter tw = new StreamWriter(path); you are trying to access the file which is being used by the process which created the file (the code line above).
You should do something like this:
if (!File.Exists(path))
{
using (var stream = File.Create(path))
{
using (TextWriter tw = new StreamWriter(stream))
{
tw.WriteLine("abc");
}
}
}
I am trying to read from a folder, and delete a specified file from inside.
I am able to do this one time without any issues.
However after doing it the first time, I am no longer able to Create the new file. The old one is still deleted, but the new file is no longer being created as it should. My question is; From the code provided why would the task work once, but not after that? It's being deleted after the first time but won't re-create.
EDIT:
The issue was in permissions.
I changed the folder security settings to allow reading/writing and I am now able to do it as I wanted.
However, I need it to automatically set the security settings if possible as other users may not know how to do so.
if (Directory.Exists(path1))
{
if (File.Exists(path1 + "\\launchinfo.txt"))
{
File.Delete(path1 + "\\launchinfo.txt");
using (FileStream fs = File.Create(path1 + "\\launchinfo.txt"))
{
Byte[] info = new UTF8Encoding(true).GetBytes("[Connection]\n" + Form1.ipaddress + "\nport=0000\nclient_port=0\n[Details]\n" + Form1.playername);
fs.Write(info, 0, info.Length);
}
}
else
{
using (FileStream fs = File.Create(path1 + "\\launchinfo.txt"))
{
Byte[] info = new UTF8Encoding(true).GetBytes("[Connection]\n" + Form1.ipaddress + "\nport=0000\nclient_port=0\n[Details]\n" + Form1.playername);
fs.Write(info, 0, info.Length);
}
}
}
You've not posted any possible exception you may be running into - if you do have one, please post it.
That being said, it's possible that you're encountering File in use by another process when trying to delete the file - especially if you're calling your function moments after creating a file.
A method to get around this is to check if a process is using the file before you try to delete it.
string fullPath = Path.Combine(path1, "launchinfo.txt");
if (Directory.Exists(path1))
{
if (File.Exists(fullPath))
{
// Call a method to check if the file is in use.
if (IsFileLocked(new FileInfo(fullPath)){
// do something else because you can't delete the file
} else {
File.Delete(fullPath);
}
}
using (FileStream fs = File.Create(fullPath))
{
Byte[] info = new UTF8Encoding(true).GetBytes("[Connection]\n" + Form1.ipaddress + "\nport=0000\nclient_port=0\n[Details]\n" + Form1.playername);
fs.Write(info, 0, info.Length);
}
}
A method to check if the file is in use by another process
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
I'm using a filestream to access a file (making an md5 ComputeHash). If I attempt to rename the file during this time (which fails as the file is being accessed). So far so good, but when I then try to open the file anew after the original filestream is closed I get the info that the file is open in another process.
Code:
using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
MD5 md5 = MD5.Create();
byte[] mymd5computed = md5.ComputeHash(fileStream);
......
}
Thread.Sleep(50);
Thread a = new Thread (()=>{(FileStream sourceStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){....} });
Like I said if while during the computation of the MD5 I try to rename the file I get the info that the file is still locked.
The lock on a file sometimes isn't released right away when you close your stream, so there are some other solutions you can use to wait until you can access the file again. One of them is explained here: http://www.codeproject.com/Tips/164428/C-FileStream-Lock-How-to-wait-for-a-file-to-get-re.
Recap:
public static void Lock(string path, Action<FileStream> action) {
var autoResetEvent = new AutoResetEvent(false);
while(true)
{
try
{
using (var file = File.Open(path,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.Write))
{
action(file);
break;
}
}
catch (IOException)
{
var fileSystemWatcher =
new FileSystemWatcher(Path.GetDirectoryName(path))
{
EnableRaisingEvents = true
};
fileSystemWatcher.Changed +=
(o, e) =>
{
if(Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
{
autoResetEvent.Set();
}
};
autoResetEvent.WaitOne();
}
}
}
Sample use:
Lock(#"c:\file",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch(IOException ioe)
{
// handle IOException
}
});
Hope it helps! :)
I'm working with a file stream in C#. It's a storage cache, so if something goes bad writing the file (corrupted data, ...), I need to delete the file and rethrow the exception to report the problem. I'm thinking on how to implement it in the best way. My first attempt was:
Stream fileStream = null;
try
{
fileStream = new FileStream(GetStorageFile(),
FileMode.Create, FileAccess.Write, FileShare.Write);
//write the file ...
}
catch (Exception ex)
{
//Close the stream first
if (fileStream != null)
{
fileStream.Close();
}
//Delete the file
File.Delete(GetStorageFile());
//Re-throw exception
throw;
}
finally
{
//Close stream for the normal case
if (fileStream != null)
{
fileStream.Close();
}
}
As you will see, if something goes bad writing the file, the fileStream will be closed twice. I know that it works, but I don't think that is the best implementation.
I think that I could remove the finally block, and close the stream in the try block, but I have posted this here because you guys are experts and I want to hear the voice of an expert.
If you put the fileStream in a using block you don't need to worry about closing it, and then just leave the cleaning up (deleting of the file in the catch block.
try
{
using (FileStream fileStream = new FileStream(GetStorageFile(),
FileMode.Create, FileAccess.Write, FileShare.Write))
{
//write the file ...
}
}
catch (Exception ex)
{
File.Delete(GetStorageFile());
//Re-throw exception
throw;
}
I believe what you want is this:
var fs = new FileStream(result.FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
I've used it with ASP.Net to have the web server return a result to a temp file that's on disk, but to make sure it's cleaned up after the web server finishes serving it to the client.
public static IActionResult TempFile(string tempPath, string mimeType, string fileDownloadName)
{
var fs = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
var actionResult = new FileStreamResult(fileStream: fs, contentType: mimeType)
{
FileDownloadName = fileDownloadName
};
return actionResult;
}