I am trying to get the text of a file in C# (config) and to put it into fields. The code itself works, but I need to close the file stream to open a new one futher in the code, but don't know where to put the Close() tag. Can someone help me?
string documentspath = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string rpath = documentspath + #"\Luminous\remember.ini";
if (File.Exists(rpath))
{
try
{
string text = File.ReadAllText(rpath);
string path = text.Split('|')[0];
string process = text.Split('|')[1];
string loadLib = text.Split('|')[2];
pathBox.Text = path;
processBox.Text = process;
if (loadLib == "True")
{
loadLibrary.Checked = true;
}
else
{
manualMap.Checked = true;
}
} catch
{
MessageBox.Show("Config file corrupted. Remembered data has been lost and deleted.");
File.Delete(rpath);
}
} else
{
MessageBox.Show("No config file loaded. Welcome, " + Environment.UserName + ".");
}
EDIT: Here's the code from where I'm opening another file stream.
string documentspath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (!Directory.Exists(documentspath + #"\Luminous")) {
Directory.CreateDirectory(documentspath + #"\Luminous");
} else {
string rpath = documentspath + #"\Luminous\remember.ini";
if (!File.Exists(rpath)) {
File.Create(rpath);
File.WriteAllText(rpath, pathBox.Text + "|" + processBox.Text + "|" + loadlibcheck + "|" + manualmapcheck);
} else {
File.WriteAllText(rpath, string.Empty);
File.WriteAllText(rpath, pathBox.Text + "|" + processBox.Text + "|" + loadlibcheck + "|" + manualmapcheck);
}
}
You don't need to close File when using File.ReadAllText().
From MSDN:
File.ReadAllText Method Opens a text file, reads all lines of the file, and then closes the file.
Error appears because of this line:
File.Create(rpath);
Try:
using(File.Create(rpath)) {}
File.Create method actually return FileStream, which have to be disposed. Some info about it can be found on the documentation.
In section "Return Value":
Type: System.IO.FileStream A FileStream that provides read/write
access to the file specified in path.
In section "Remarks":
The FileStream object created by this method has a default FileShare value of None; no other process or code can access the created file until the original file handle is closed.
However, as Chris Dunaway mentioned, there is no need to use File.Create at all, as according to documentation WriteAllText :
Creates a new file, writes the specified string to the file, and then closes the file. If the target file already exists, it is overwritten.
You have two good options:
On the finally clause of your try/catch block.
Change your code to use using statement for your file stream.
You don't have to close anything. File.ReadAllText reads and closes a stream internally. So you can safely invoke another File.ReadAllText if you need to.
Related
I've started to encounter a problem with File.Copy. This works fine for my data creation script, managing to duplicate thousands of files with no issues. My problem occurs when trying to create temp files later in my code.
I have added the code sample below that isn't working correctly. I've tried numerous different ways to try to resolve this to no avail. What I am doing is copying some user data files created in a directory on the C drive into a temp folder inside that user data folder.
Code
foreach (string originalFile in OriginalDataFileNames)
{
string tempFile = originalFile;
TempDataFiles.Add(tempFile);
Console.WriteLine("GlobalDataCtrl: Original Data File: " + XWSDataDirectory + "\\" + tempFile);
Console.WriteLine("GlobalDataCtrl: Saved Temp Data File: " + tempPath + "\\" + tempFile);
File.Copy(XWSDataDirectory + "\\" + originalFile, tempPath + "\\" + tempFile);
}
Exit Error
The program '[6256] XtremeWrestlingSim.vshost.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.
Any help is appreciated, thanks in advance!
SOLUTION:
FileStream outputFS = null;
FileStream inputFS = null;
outputFS = new FileStream(tempPath + "\\" + tempFile, FileMode.CreateNew, FileAccess.ReadWrite);
using (inputFS = new FileStream(XWSDataDirectory + "\\" + originalFile, FileMode.Open))
{
inputFS.CopyTo(outputFS);
}
outputFS.Close();
inputFS.Close();
Not sure how nicely formatted this is, but it works. Replace File.Copy with the above code.
You are using File.Create just before you call File.Copy, I think that is the issue, it is leaving an open stream.
Maybe removing the File.Create call will solve the issue. If not you could get the returned value (which is a stream) and close it before trying to copy.
The file is opened with read/write access and must be closed before it can be opened by another application.
See remarks https://msdn.microsoft.com/en-us/library/ms143361(v=vs.110).aspx
I'm trying to detect if a file exists at runtime, if not, create it. However I'm getting this error when I try to write to it:
The process cannot access the file 'myfile.ext' because it is being used by another process.
string filePath = string.Format(#"{0}\M{1}.dat", ConfigurationManager.AppSettings["DirectoryPath"], costCentre);
if (!File.Exists(filePath))
{
File.Create(filePath);
}
using (StreamWriter sw = File.AppendText(filePath))
{
//write my text
}
Any ideas on how to fix it?
File.Create(FilePath).Close();
File.WriteAllText(FileText);
I want to update this answer to say that this is not really the most efficient way to write all text. You should only use this code if you need something quick and dirty.
I was a young programmer when I answered this question, and back then I thought I was some kind of genius for coming up with this answer.
The File.Create method creates the file and opens a FileStream on the file. So your file is already open. You don't really need the file.Create method at all:
string filePath = #"c:\somefilename.txt";
using (StreamWriter sw = new StreamWriter(filePath, true))
{
//write to the file
}
The boolean in the StreamWriter constructor will cause the contents to be appended if the file exists.
When creating a text file you can use the following code:
System.IO.File.WriteAllText("c:\test.txt", "all of your content here");
Using the code from your comment. The file(stream) you created must be closed. File.Create return the filestream to the just created file.:
string filePath = "filepath here";
if (!System.IO.File.Exists(filePath))
{
System.IO.FileStream f = System.IO.File.Create(filePath);
f.Close();
}
using (System.IO.StreamWriter sw = System.IO.File.AppendText(filePath))
{
//write my text
}
FileStream fs= File.Create(ConfigurationManager.AppSettings["file"]);
fs.Close();
File.Create returns a FileStream. You need to close that when you have written to the file:
using (FileStream fs = File.Create(path, 1024))
{
Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
You can use using for automatically closing the file.
I updated your question with the code snippet. After proper indenting, it is immediately clear what the problem is: you use File.Create() but don't close the FileStream that it returns.
Doing it that way is unnecessary, StreamWriter already allows appending to an existing file and creating a new file if it doesn't yet exist. Like this:
string filePath = string.Format(#"{0}\M{1}.dat", ConfigurationManager.AppSettings["DirectoryPath"], costCentre);
using (StreamWriter sw = new StreamWriter(filePath, true)) {
//write my text
}
Which uses this StreamWriter constructor.
I know this is an old question, but I just want to throw this out there that you can still use File.Create("filename")", just add .Dispose() to it.
File.Create("filename").Dispose();
This way it creates and closes the file for the next process to use it.
This question has already been answered, but here is a real world solution that
checks if the directory exists and adds a number to the end if the text file
exists. I use this for creating daily log files on a Windows service I wrote. I
hope this helps someone.
// How to create a log file with a sortable date and add numbering to it if it already exists.
public void CreateLogFile()
{
// filePath usually comes from the App.config file. I've written the value explicitly here for demo purposes.
var filePath = "C:\\Logs";
// Append a backslash if one is not present at the end of the file path.
if (!filePath.EndsWith("\\"))
{
filePath += "\\";
}
// Create the path if it doesn't exist.
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
// Create the file name with a calendar sortable date on the end.
var now = DateTime.Now;
filePath += string.Format("Daily Log [{0}-{1}-{2}].txt", now.Year, now.Month, now.Day);
// Check if the file that is about to be created already exists. If so, append a number to the end.
if (File.Exists(filePath))
{
var counter = 1;
filePath = filePath.Replace(".txt", " (" + counter + ").txt");
while (File.Exists(filePath))
{
filePath = filePath.Replace("(" + counter + ").txt", "(" + (counter + 1) + ").txt");
counter++;
}
}
// Note that after the file is created, the file stream is still open. It needs to be closed
// once it is created if other methods need to access it.
using (var file = File.Create(filePath))
{
file.Close();
}
}
I think I know the reason for this exception. You might be running this code snippet in multiple threads.
you can just use using keyword around File.Create(path) to finalize the process
using(File.Create(path));
Try this: It works in any case, if the file doesn't exists, it will create it and then write to it. And if already exists, no problem it will open and write to it :
using (FileStream fs= new FileStream(#"File.txt",FileMode.Create,FileAccess.ReadWrite))
{
fs.close();
}
using (StreamWriter sw = new StreamWriter(#"File.txt"))
{
sw.WriteLine("bla bla bla");
sw.Close();
}
As the title suggests, I'm attempting to read and write to a file at the same time. I have researched this topic but the answers I have found don't seem to work for me because of the circumstances in my program. I am using multiple FileSystemWatchers to track a large amount of files that are constantly passing through a flow in my network. As the files pass through each part of my flow, a text file is updated(one text file per spot in the flow) that marks the name of the file and the time it was created within the folder. It is unpredictable when files might be passing through, and when they might be writing to the tracker text files. My goal is to be able to read and write to the file simultaneously, in case a user attempts to read to from a text file that is being written to at the exact same time. How would I accomplish this?
//Write to File
private void WriteToFile(string info,string path,string tr)
{
if (!File.Exists(path+#"\"+#tr))
{
var myFile =
File.Create(path + #"\" + #tr);
myFile.Close();
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info,true);
tw.Close();
}
else if (File.Exists(path + #"\" + #tr))
{
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info);
tw.Close();
}
}
The circumstances you are alluding to seem to say that while multiple attempts can be made to read/write the file at a given time, you still want to ensure that the operations are performed one after another in the correct order that the read or writes got called.
One simple method of ensuring that the read and write operations are synchronized would be to just put a lock or Monitor around the methods. Try the following code for your write method:
private readonly object _locker = new object();
// write the file
private void WriteToFile(string info, string path, string tr)
{
Monitor.Enter(this._locker);
try
{
if (!File.Exists(path + #"\" + #tr))
{
var myFile =
File.Create(path + #"\" + #tr);
myFile.Close();
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info, true);
tw.Close();
}
else if (File.Exists(path + #"\" + #tr))
{
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info);
tw.Close();
}
}
finally
{
Monitor.Exit(this._locker);
}
}
Then, I would use a very similar construct for reading the file.
// read the file
private string ReadFile(string path)
{
Monitor.Enter(this._locker);
try
{
// read the file here...
}
finally
{
Monitor.Exit(this._locker);
}
}
What the Monitor will do is ensure that the file will not be read until an on-going write operation is complete (and vice-versa). This will ensure that you will not get the old data when you read it, and you will also not over-write the new data (which has not yet been read). This method verifies the integrity of your files at all times.
I'm writing a function which is going to serialize class and save it to file, some classes must be saved in a different folder. I'm using Unity and C#. Here's my code:
public void save<T>(T data, string fileName) where T : class{
if (fileName == "")
Debug.Log ("Empty file path");
FileStream file = null;
try{
if(fileName.IndexOf("/") > 0){
string[] strDirName = fileName.Split(new char[] {'/'});
string dirName = strDirName[0];
if(!Directory.Exists(Application.persistentDataPath + dirName)){
Directory.CreateDirectory(Application.persistentDataPath + "/" + dirName);
}
}
file = File.Create(constructFilePath(fileName));
string a = constructFilePath(fileName);
binFormatter.Serialize(file, data);
Debug.Log ("File saved succesfully" + fileName);
}catch(IOException e){
Debug.Log(e.ToString());
}finally{
if(file != null)
file.Close();
}
}
string constructFilePath(string fileName){
return Path.Combine(Application.persistentDataPath, fileName);
}
I have no idea why it's saving files as folder, this happens since I added this line to construct constructFilePath
if(fileName[0] != "/")
fileName = "/" + fileName;
But without this file it's creating different folder. It's concatenating the Application.persistentDataPath with the folder name and creates the file there
so if my persistentDataPath = C:/Users/User/AppData/LocalLow/DefaultCompany/TestGame and I want to store the file inside this folder in folder a and store file b in it
C:/Users/User/AppData/LocalLow/DefaultCompany/TestGame/a/b
it creates folder with name TestGamea and stores b inside it
C:/Users/User/AppData/LocalLow/DefaultCompany/TestGamea/b
You are evaluating one thing and performing something different here:
if(!Directory.Exists(Application.persistentDataPath + dirName)){
Directory.CreateDirectory(Application.persistentDataPath + "/" + dirName);
}
Change this to:
if(!Directory.Exists(Path.Combine(Application.persistentDataPath, dirName))){
Directory.CreateDirectory(Path.Combine(Application.persistentDataPath, dirName));
}
Like Eric said, use Path.Combine. it will reliably combine path parts and ensure you get the same result every time so you don't have to worry about string manipulation.
I have a template excel file to generate excel files from it.
My code is as follows (This part is to create a new excel file from the template):
string currentFN = PropertyFinalResult[0].Fecha;
string fixCurrentFN = currentFN.Replace('/', '_');
string currentTime = DateTime.Now.ToLongTimeString();
string fixCurrentTime = currentTime.Replace(':', '_');
string addToFileName = fixCurrentTime.Replace(' ', '_');
string newFN = fixCurrentFN + "-" + addToFileName;
string SourceFile = Request.PhysicalApplicationPath + "Template\\ExcelTemplate.xlsx";
string DestFile = Request.PhysicalApplicationPath + "Template\\" + newFN + ".xlsx";
//To keep FileName for posterior deletion
Session["sDestFile"] = DestFile;
try
{
File.Copy(SourceFile, DestFile);
}
catch (Exception ex)
{
lblErrorSavingToDB.Text = "Error: " + ex.Message;
lblErrorSavingToDB.Visible = true;
}
after that I open the new excel file, insert the records in it and then, stream the file to the user by doing this:
//Streaming file to client
string fileName = newFN + ".xlsx";
Response.Redirect("../Template/" + fileName);
Now, my question is, whether the user save or not the file, when should I delete the generated file? I would prefer once the user closes the popup window regarding Open or Save the file. But how to know when the user closes that window?
You can use TransmitFile and then close once the transmission is over. Example:
try
{
Response.ContentType = "application/octet-stream";
Response.AddHeader("content-disposition", "attachment;filename=\"" + Path.GetFileName(path.FullName) + "\"");
Response.AddHeader("content-length", path.Length.ToString());
Response.TransmitFile(path.FullName);
Response.Flush();
}
finally
{
File.Delete(Server.MapPath("~/"+tpacode+".zip"));
}
When to delete the files (or maybe it's better to say "how long to keep the files") is a question that is best answered by your application's business rules.
In the past, in low-traffic applications, I've used a "clean-up" routine to delete files older than a certain threshold. That clean-up gets performed when a new file is created, and at that time any file in the designated folder that was older than the threshold would be deleted.