I have a Windows forms application, that is supposed to store its config data on a file called config.txt. I have this code, which runs when the form is initialized. Here is the function:
string folderPath = #‘C:\Users\Public\Periodic_Clock\’;
string filePath = #‘C:\Users\Public\Periodic_Clock\config.txt’;
public Form1()
{
InitializeComponent();
once = 0;
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
if (!File.Exists(filePath))
{
new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
File.WriteAllText(filePath, "Alarm" + Environment.NewLine + "Alarm Ringing!" + Environment.NewLine + 1);
}
else
{
}
notificationTitle = File.ReadLines(filePath).Skip(0).Take(1).First();
notificationText = File.ReadLines(filePath).Skip(1).Take(1).First();
}
Pretty much, I have an app that sends a notification when a timer goes off. I want to use this config file to store a custom title, text and notification type for the notification. (so that the user can customize what the notification looks like) My intention with this was to have the first line as the notification title, second line as the text, and the third line as a number from 0 - 3, to store the type of notification (info, error, etc.)
I can not manage to get the program to write anything to the text file. It creates it, but it seems to completely skip the part where I use File.WriteAllText(). I used other methods like StreamWriter, but nothing was written to the text document. The code right now skips the WriteAllText part and creates an error at File.ReadLines, which just tells me that the sequence contains no elements. What's the problem here? How do I fix it?
In the end, I ended up with this code:
public Form1()
{
InitializeComponent();
once = 0;
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
try
{
FileStream config = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
config.Close();
StreamWriter writetext = new StreamWriter(filePath);
writetext.Write("Alarm");
writetext.WriteLine();
writetext.Write("Alarm Ringing!");
writetext.WriteLine();
writetext.Write("1");
writetext.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error!");
}
notificationTitle = File.ReadLines(filePath).Skip(0).Take(1).First();
notificationText = File.ReadLines(filePath).Skip(1).Take(1).First();
}
Related
I've got a windows service that I have to modify. Current code is this:
public IRecord2 GetRecord(string name)
{
string path = Path.Combine(this.DirectoryPath, name);
if (!File.Exists(path))
return null;
byte[] contents;
lock (locker) {
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize:4096, useAsync:true)) //WHERE THE PROBLEM IS OCCURRING
{
using (BinaryReader br = new BinaryReader(fs))
{
contents = br.ReadBytes((int)fs.Length);
br.Close(); //unnecessary but threw it in just to be sure
fs.Close(); //unnecessary but threw it in just to be sure
}
}
}
return new Record2()
{
Name = name,
Contents = contents
};
}
Code that calls the function:
public void Process(string pickupFileName)
{
string uniqueId = DateTime.Now.ToString("(yyyy-MM-dd_HH-mm-ss)");
string exportFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + ".csv";
string archiveFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + Path.GetExtension(pickupFileName);
string unprocessedFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + Path.GetExtension(pickupFileName);
try
{
_logger.LogInfo(String.Format("Processing lockbox file '{0}'", pickupFileName));
IRecord2 record = _pickup.GetRecord(pickupFileName);
if (record == null)
return;
_archive.AddOrUpdate(new Record2() { Name = archiveFileName, Contents = record.Contents });
string pickupFileContents = UTF8Encoding.UTF8.GetString(record.Contents);
IBai2Document document = Bai2Document.CreateFromString(pickupFileContents);
StringBuilder sb = Export(document);
_export.AddOrUpdate(new Record2() { Name = exportFileName, Contents = Encoding.ASCII.GetBytes(sb.ToString()) });
_pickup.Delete(pickupFileName);
}
catch(Exception ex)
{
throw ex;
}
}
Function that calls Process:
public void Process()
{
foreach (ConfigFolderPath configFolderPath in _configSettings.ConfigFolderPaths)
{
IRecordRepository pickup = new FileRepository(configFolderPath.PickupFolderPath);
IRecordRepository export = new FileRepository(configFolderPath.ExportFolderPath);
IRecordRepository archive = new FileRepository(configFolderPath.ArchiveFolderPath);
IRecordRepository unprocessed = new FileRepository(configFolderPath.UnprocessedFolderPath);
Converter converter = new Converter(Logger,pickup, export, archive, unprocessed);
foreach (string fileName in pickup.GetNames())
{
if (_configSettings.SupportedFileExtensions.Count > 0 && !_configSettings.SupportedFileExtensions.Any(extension => extension.ToLower() == Path.GetExtension(fileName).ToLower()))
continue;
Action action = () => converter.Process(fileName);
_queue.TryEnqueue(action, new WorkTicket() { Description = String.Format("Processing '{0}'", fileName), SequentialExecutionGroup = fileName });
}
}
}
When 1 file is sent to the service, it processes and reads the file correctly. However, if two files are sent (difference of 3 minutes), the first file will process correctly, but the second will give me "System.IO.IOException: The process cannot access the file "filename" because it is being used by another process.
Is the solution to use a mutex as per https://stackoverflow.com/a/29941548/4263285 or is there a better solution to solve this?
Edit: More context:
Service is constantly running - as soon as files are dropped into a folder, it begins the process.
get the file data (function up above)
take the data, transform it, and put it into a different file
Delete the original file from the one up above
rinse and repeat if more files
if one file is placed in the folder, it works correctly.
if two files are placed in the folder, it breaks on the second file
if service is stopped and restarted, it works again
In your code add ".Close()" here, at the end of the line :
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize:4096, useAsync:true).Close())
I want to write a code in C# that reads a text file in Android and if it doesn't exist, create it. I want my application to read the same file everytime I run my App and create that file the first time I open my app.I wrote this code but it doesn't work.It only creates a directory if it doesn't exist but it doesn't create my text file.Thank you for your answer in advance.
network=Network.Main;
//string _fileName = Path.Combine(, "bitcoinwallets.phoenixbtcwallet");
string rootPath = Android.App.Application.Context.GetExternalFilesDir(null).ToString();
var filePathDir = Path.Combine(rootPath, "PhoenixWallet/");
if (!File.Exists(filePathDir))
{
Directory.CreateDirectory(filePathDir);
}
bitcoinPrivateKeysFile= filePathDir+"bitcoinwallets.phoenixbtcwallet";
string bitcoinprivateKeyItem;
if(File.Exists( bitcoinPrivateKeysFile))
{
StreamReader sr = File.OpenText(bitcoinPrivateKeysFile);
while (!sr.EndOfStream ){
bitcoinprivateKeyItem=sr.ReadLine();
bitcoinprivKeys.Add(bitcoinprivateKeyItem);
}
Console.WriteLine("File Exists");
sr.Close();
} else {
Key bitcoinKey = new Key();
BitcoinSecret bitcoinsecret = new BitcoinSecret(bitcoinKey,network);
StreamWriter sw;
sw= File.CreateText(bitcoinPrivateKeysFile);
sw.WriteLine(bitcoinsecret.PrivateKey);
Console.WriteLine("File Does not Exist");
sw.Close();
}
btn.Text = "New Wallet";
bitcoinWalletAddressTextView.Text=bitcoinprivKeys[0];
You are checking File.Exists(...) != null which is a bit nonsensical, since File.Exists returns a bool value which is never null.
So just do if (File.Exists(...)) {...}
if (File.Exists(...))
{
// read file
}
else
{
// create file
}
I have two methods: saveFile and saveAsToFile. The first one is supposed to overwrite the contents of the current, existing file. While the second is supposed to save as a new file (if the current is non-existing or the user just wants to make a copy.)
When I use the saveAsToFile method it works every time. When I use the saveFile method it doesn't write anything. (I DO see the "Saved!" MessageBox, though.)
Here are my methods:
public void saveFile(string[] inData, string inDataTitle)
{
//This method saves the file
SaveFileDialog savefile;
string trueFileName;
if (isStrArrayNotEmpty(inData)) {
//Only attempt to save the file if there is anything written in the textArea
if (f.getDocumentSavedStatus()) {
if (f.getDocumentChangedStatus()) {
savefile = new SaveFileDialog();
if (inDataTitle.EndsWith("*")) {
//Remove the asterisk from the document name
savefile.FileName = inDataTitle.Substring(0, inDataTitle.Length - 1);
}
else {
savefile.FileName = inDataTitle;
}
StreamWriter sw = new StreamWriter(savefile.FileName, false);
foreach (string line in inData) {
sw.WriteLine(line);
}
sw.Flush();
if (sw.BaseStream != null)
sw.BaseStream.Flush();
sw.Close();
/*
using (StreamWriter sw = new StreamWriter(savefile.FileName, false))
foreach (string line in inData) {
sw.WriteLine(line);
}
*/
f.setDocumentName(string.Empty);
trueFileName = Path.GetFileName(savefile.FileName);
f.setDocumentName(trueFileName);
f.setDocumentSavedStatus(true);
f.setDocumentChangedStatus(false); //Changes saved, status updated
MessageBox.Show("Saved!");
}
}
else {
//If the document hasn't been saved before, send the values to the 'Save As' method
saveAsToFile(inData, inDataTitle);
}
}
}
public void saveAsToFile(string[] inData, string inDataTitle)
{
//This method checks if there is anything written in the texArea,
//if so it prompts the user to save the file to disk (Save As)
SaveFileDialog savefile;
string trueFileName;
if (isStrArrayNotEmpty(inData)) {
//Only attempt to save the file if there is anything written in the textArea
savefile = new SaveFileDialog();
if (inDataTitle.EndsWith("*")) {
//Remove the asterisk from the document name
savefile.FileName = inDataTitle.Substring(0, inDataTitle.Length - 1);
}
else {
savefile.FileName = inDataTitle;
}
savefile.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
if (savefile.ShowDialog() == DialogResult.OK) {
StreamWriter sw = new StreamWriter(savefile.FileName, false);
foreach (string line in inData) {
sw.WriteLine(line);
}
sw.Flush();
if (sw.BaseStream != null)
sw.BaseStream.Flush();
sw.Close();
/*
using (StreamWriter sw = new StreamWriter(savefile.FileName))
foreach (string line in inData) {
sw.WriteLine(line);
}
*/
f.setDocumentName(string.Empty);
trueFileName = Path.GetFileName(savefile.FileName);
f.setDocumentName(trueFileName);
f.setDocumentSavedStatus(true);
f.setDocumentChangedStatus(false); //Changes saved, status updated
}
}
}
As you can see by the comments in the code; I tried using using, and then I tried to "manually flush" the streamwriter, but nothing works.
Using saveAsToFile works every time. It overwrites the text file as expected, no problems. While saveFile doesn't write anything to the file. (Leaving it unchanged.)
I tried looking for errors in saveFile by using MessageBox.Show to print the values of savefile.Filename and line in the appropriate places - they all worked as expected, yet nothing is written to the actual text file.
isStrArrayNotEmpty returns true if the string array does not contain any white spaces.
getDocumentSavedStatus returns the value of a boolean which tells if the file has been saved before or not (existent / non-existent)
getDocumentChangedStatus returns the value of a boolean which tells if the file has been modified or not (asterisk by the end of the file name, indicating that work will be lost if the user shuts down the application.)
Does the inDataTitle parameter include the path of the filename you're trying to save? If not, it's likely saving to a file of the same name but in a different folder.
After your line:-
StreamWriter sw = new StreamWriter(savefile.FileName, false);
add the line:-
MessageBox.Show(((FileStream)(sw.BaseStream)).Name);
and it'll tell you where the file is being saved.
Try replacing
StreamWriter sw = new StreamWriter(savefile.FileName, false);
foreach (string line in inData) {
sw.WriteLine(line);
}
sw.Flush();
if (sw.BaseStream != null)
sw.BaseStream.Flush();
sw.Close();
with
File.WriteAllLines(saveFile.Filename, inData);
I am trying to Write to a text file after this code block checks for the last time the PC was restarted. The code below reads from a text file, the last time the PC was resarted, and from there it determines whether to show a splash-screen. However, After this method runs, i need to write to the text file what the current "System Up-Time" is. But i keep getting an error that says the text file is in use. This has driven me insane. I have made sure all StreamWriters and StreamReaders are closed. I have tried Using Statements. I have tried GC.Collect. I feel like i have tried everything.
Any help would be appreciated.
private void checkLastResart()
{
StreamReader sr = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
if (sr.ReadLine() == null)
{
sr.Close();
MessageBox.Show("There was an error loading 'System UpTime'. All settings have been restored to default.");
StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt", false);
sw.WriteLine("Conversion Complete Checkbox: 0");
sw.WriteLine("Default Tool: 0");
sw.WriteLine("TimeSinceResart: 0");
sw.Flush();
sw.Close();
}
else
{
try
{
StreamReader sr2 = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
while (!sr2.EndOfStream)
{
string strSetting = sr2.ReadLine();
if (strSetting.Contains("TimeSinceResart:"))
{
double lastTimeRecorded = double.Parse(strSetting.Substring(17));
//If the lastTimeRecorded is greater than timeSinceResart (computer has been resarted) OR 2 hours have passed since LVT was last run
if (lastTimeRecorded > timeSinceRestart || lastTimeRecorded + 7200 < timeSinceRestart)
{
runSplashScreen = true;
}
else
{
runSplashScreen = false;
}
}
}
sr2.Close();
sr2.Dispose();
}
catch (Exception e) { MessageBox.Show("An error has occured loading 'System UpTime'.\r\n\r\n" + e); }
}
}
Below is a sample of writing to the Text file, after the above code has been run. It doesnt matter if i open a StreamWriter, or use File.WriteAllLines, an error is thrown immediately.
StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
string[] lines = File.ReadAllLines(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
lines[2] = "TimeSinceResart: " + timeSinceRestart;
foreach (string s in lines)
sw.WriteLine(s);
Your writing code should be changed in this way
string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");
// First read the two lines in memory
string[] lines = File.ReadAllLines(file);
// then use the StreamWriter that locks the file
using(StreamWriter sw = new StreamWriter(file))
{
lines[2] = "TimeSinceResart: " + timeSinceRestart;
foreach (string s in lines)
sw.WriteLine(s);
}
In this way the lock on the StreamWriter doesn't block the reading with FileReadAllLines.
Said that, please note a couple of things. Do not create path strings with string concatenation, use the static methods of the Path class. But most important, when you create a disposable object like a stream be sure to use the using statement to close correctly the file
To complete the answer in response to your comment. Using statement also for the first part of your code
private void checkLastResart()
{
string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");
using(StreamReader sr = new StreamReader(file))
{
if (sr.ReadLine() == null)
{
sr.Close();
MessageBox.Show(...)
using(StreamWriter sw = new StreamWriter(file, false))
{
sw.WriteLine("Conversion Complete Checkbox: 0");
sw.WriteLine("Default Tool: 0");
sw.WriteLine("TimeSinceResart: 0");
sw.Flush();
}
}
else
{
....
}
} // exit using block closes and disposes the stream
}
Where you create sr2, sr still has settings.txt open.
I'm writing text to files using StreamWriter using the following code:
path == #"Desktop\";
filepath1 = path + "1.txt";
StreamWriter _sw = new StreamWriter(filepath1, true);
_sw.WriteLine("some Text");
_sw.Close();
if size of textfile exceeds 500kb I want to create text files dynamically. I'm tryng following code:
var size = (path.Length)/1024;
if(size>=500)
{
int i = (size/500)+1;
var filepath2 = path + i + ".txt";
if (File.Exists(filepath2))
{
StreamWriter _sw = new StreamWriter(filepath2, true);
_sw.WriteLine("Some message");
_sw.Close();
}
}
else
{
FileStream fs = File.Create(filepath2);
StreamWriter _sw = new StreamWriter(filepath2, true);
_sw.WriteLine(ex);
_sw.Close();
}
My question is if file 2.txt also exceeds 500kb I want to create 3.txt,4.txt..... and so on..
I want to create all these dynamically - how to solve this problem?
First thing you need to do the SIZE comparison for the data length of File not the File Path.
Here is Function which dose what you want to achieve, Please make appropriate changes for your path.
//Public variable to manage file names
int FileCounter = 1;
string FileName;
// Call this function to Add text to file
private void WriteToFile(string writeText)
{
FileName = "MyFile_"+FileCounter +".txt";
if (File.Exists(FileName))
{
string str = File.ReadAllText(FileName);
if ((str.Length + writeText.Length) / 1024 > 500) // check for limit
{
// Create new File
FileCounter++;
FileName = "MyFile_" + FileCounter + ".txt";
StreamWriter _sw = new StreamWriter(FileName, true);
_sw.WriteLine(writeText);
_sw.Close();
}
else // use exixting file
{
StreamWriter _sw = new StreamWriter(FileName, true);
_sw.WriteLine(writeText);
_sw.Close();
}
}
}
Where to start..
You are writing it as one big long procedural script. You need to break it down into chunks that can be reused using functions. As it is, it will get out of control way too quickly.
path == #"Desktop\"; is not valid. 1 too many =
Use Path.Combine() to combine your folder and filenames.
I'm sure this is all just test/rough/scratch code but just in case it's not, also check out Try/Except to wrap your file handling. You should also look up using() to dispose of your streams/writers.
My last comment would be that I see a lot of this sort of code a lot and it's often replaceable with something like Nlog for a whole lot less friction.
I would have commented but this login has no rep.