I am trying to create a list using the FileStream/StreamReader method. Everything works fine except the price calculation is reset every time a new line is added.
I believe the issue is with the save method. I am sure it is not caused from functions in my classes, since the price is showing properly. There seems to be an issue when saving the string.
This is my read method:
public static List<Customer> ReadCustomers()
{
// create an empty customer list
List<Customer> customerList = new List<Customer>();
// new Filestream
FileStream fs = null;
// new StreamReader
StreamReader sr = null;
Customer c; // for reading
string line;
string[] fields;
try
{
fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read);
sr = new StreamReader(fs);
while (!sr.EndOfStream)// while there is data
{
line = sr.ReadLine();
fields = line.Split(','); // split sections by commas
c = new Customer(); // initializes customer object
c.AccountNo = Convert.ToInt32(fields[0].Trim());
c.CustomerName = Convert.ToString(fields[1].Trim());
c.CustomerType = Convert.ToChar(fields[2].Trim());
c.CustomerCharge = Convert.ToDecimal(fields[3].Trim());
customerList.Add(c);
}
}
catch (Exception ex)
{
throw ex;
}
finally // always execute
{
if (fs != null) fs.Close(); // close file
}
return customerList;
}
This is where I try to save the string...
public static void SaveCustomers(List<Customer> list)
{
FileStream fs = null;
StreamWriter sw = null;
string line;
try
{
fs = new FileStream(path, FileMode.Create, FileAccess.Write);
sw = new StreamWriter(fs);
foreach (Customer c in list) // for each customer in the list
{
line = c.AccountNo.ToString() + ", " + c.CustomerName.ToString() + ", " +
c.CustomerType.ToString() + ", " + c.CustomerCharge.ToString(); // make a line with data
sw.WriteLine(line); // and write it to the file
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
if (sw != null) sw.Close(); // stream writer close
if (fs != null) fs.Close();
}
}
Calculation:
public override decimal CalculateCharge()
{
decimal peak;
decimal offpeak;
if (Kwh1 <= INDUST_BASE_HOURS)
{
peak = KWH_PEAK_BASE_PRICE;
}
else
{
peak = ((Kwh1 - INDUST_BASE_HOURS) * KWH_INDUST_PEAK) + KWH_PEAK_BASE_PRICE;
}
if (Kwh2 <= INDUST_BASE_HOURS)
{
offpeak = KWH_OFF_PEAK_BASE_PRICE;
}
else
{
offpeak = ((Kwh2 - INDUST_BASE_HOURS) * KWH_INDUST_OFFPEAK) + KWH_OFF_PEAK_BASE_PRICE;
}
return peak + offpeak;
}
In SaveCustomers(), are you sure you want to open the file:
fs = new FileStream(path, FileMode.Create, FileAccess.Write);
You may want:
fs = new FileStream(path, FileMode.Append, FileAccess.Write);
FileMode.Create will destroy the file if it exists.
FileMode.Append will append to an existing file it exists.
Maybe for the purposes of clarity around testing, you output to another file rather than the one you read in.
Try using this by using the append parameter:
new StreamWriter("c:\\file.txt", true);
http://msdn.microsoft.com/en-us/library/36b035cb.aspx
Or you can see related answers here, which had similar problems
C# add text to text file without rewriting it?
Related
I need to create a StreamWriter from a FileStream object and append some text to
the file. It is assumed that the FileStream object that is being used has been created with FileMode.OpenOrCreate and FileAccess.ReadWrite. I have:
using (FileStream fs = GetCurrentFileStream())
{
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("StringToAppend");
sw.Flush();
}
However this just overwrites the file from the beginning. How do I move to the end of the file? Is there perhaps a way to change the FileMode to Append and FileAccess to Write after the FileStream has been created?
Edit: As mentioned above I need to do this using a FileStream object. The answers from Open existing file, append a single line assume that I can create a new StreamWriter from the file path which I don't have.
Edit 2: Added truncated version of GetCurrentFileStream().
public static FileStream GetCurrentFileStream()
{
String fileName = getFileName();
FileStream fs = OpenFileWhenAvailable(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
}
public static FileStream OpenFileWhenAvailable(String fileName, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
{
int tries = 0;
int timeout = 10 * 1000;
while (true)
{
tries++;
try
{
return new FileStream(fileName, fileMode, fileAccess, fileShare);
}
catch (IOException ex)
{
if (tries * 100 > timeout)
{
return null;
}
else
{
System.Threading.Thread.Sleep(100);
}
}
}
}
GetCurrentFileStream is used in several different contexts, so changing the FileMode and FileAccess directly is not an option. I do not wish to make a separate version of GetCurrentFileStream just for this one case, which is why I'm asking if there is a way to jump to the end of the stream and append a string when the FileStream object has already been created.
If I understood correctly, you want to append your line to a created file:
using (FileStream fs = GetCurrentFileStream())
{
StreamWriter sw = new StreamWriter(fs, true);
sw.WriteLine("StringToAppend");
sw.Flush();
}
With this overload of the StreamWriter constructor you choose if you append the file, or overwrite it.
It will be really cool if you show your implementation of method GetCurrentStream():
using (FileStream fileStream = new FileStream(fileName,FileMode.Append, FileAccess.Write))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(something);
}
Update:
using (FileStream fs = GetCurrentFileStream())
{
StreamWriter sw = new StreamWriter(fs);
long endPoint=fs.Length;
// Set the stream position to the end of the file.
fs.Seek(endPoint, SeekOrigin.Begin);
sw.WriteLine("StringToAppend");
sw.Flush();
}
If you really really wanted to, you could pretty this up....
static int iMaxLogLength = 15000;
static int iTrimmedLogLength = -2000;
static public void writeToFile2(string strMessage, string strLogFileDirectory, int iLogLevel)
{
string strFile = strLogFileDirectory + "log.log";
try
{
FileInfo fi = new FileInfo(strFile);
Byte[] bytesRead = null;
if (fi.Length > iMaxLogLength)
{
using (BinaryReader br = new BinaryReader(File.Open(strFile, FileMode.Open)))
{
// Go to the end of the file and backup some
br.BaseStream.Seek(iTrimmedLogLength, SeekOrigin.End);
// Read that.
bytesRead = br.ReadBytes((-1 * iTrimmedLogLength));
}
}
byte[] newLine = System.Text.ASCIIEncoding.ASCII.GetBytes(Environment.NewLine);
FileStream fs = null;
if (fi.Length < iMaxLogLength)
fs = new FileStream(strFile, FileMode.Append, FileAccess.Write, FileShare.Read);
else
fs = new FileStream(strFile, FileMode.Create, FileAccess.Write, FileShare.Read);
using (fs)
{
if (bytesRead != null)
{
fs.Write(bytesRead, 0, bytesRead.Length);
fs.Write(newLine, 0, newLine.Length);
Byte[] lineBreak = Encoding.ASCII.GetBytes("### " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " *** *** *** New Log Start Position *** *** *** *** ###");
fs.Write(lineBreak, 0, lineBreak.Length);
fs.Write(newLine, 0, newLine.Length);
}
Byte[] sendBytes = Encoding.ASCII.GetBytes(strMessage);
fs.Write(sendBytes, 0, sendBytes.Length);
fs.Write(newLine, 0, newLine.Length);
}
}
catch (Exception ex)
{
; // Write to event or something
}
}
I'm trying to use the streamwriter to write into a file that is created temporarily i.e. _logFileName and at the same time write the data written into the file to a string using stream reader. The current code shows no errors but at runtime says that it can not read from _logFileName as it is in use already.
how to do i do this ?
using (StreamWriter _logFile = File.CreateText(_logFileName))
{
//string s = "";
//using (StreamReader fill_log = new StreamReader(s))
using (StreamReader fill_log = new StreamReader(_logFileName))
{
_logFile.WriteLine("Logfile name is: " + _logFileName);
content += fill_log.ReadLine();
_logFile.WriteLine("LOG FILE STARTED AT: " + _startDateTime.ToString());
content += fill_log.ReadLine();
_logFile.WriteLine("============================================");
content += fill_log.ReadLine();
_logFile.Write(_message);
content += fill_log.ReadLine();
_logFile.WriteLine();
content += fill_log.ReadLine();
}
_logFile.Close();
}
So based on the suggestion i changed the code to this:
using (var fsWrite = new FileStream(_logFileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
using (var _logFile = new StreamWriter(fsWrite))
using (var fsRead = new FileStream(_logFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var fill_log = new StreamReader(fsRead))
{
_logFile.WriteLine();
content += fill_log.ReadLine();
_logFile.WriteLine("TIME OF LOG ENTRY: " + DateTime.Now);
content += fill_log.ReadLine();
// Arbitrary objects can also be written to the file.
_logFile.WriteLine(_message);
content += fill_log.ReadLine();
_logFile.Flush();
_logFile.Close();
On doing so, i am able to red and write simultaneously! that gave no problem. Thanks. But the content string variable seems to end after everyright. and ideas why this would happen ?
In order to be able to simultaneously read and write from the same file you have to create the FileStream object manually using one of the constructors that take a FileShare parameter, for example this one.
using (var fsWrite = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
using (var _logFile = new StreamWriter(fsWrite))
using (var fsRead = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var fill_log = new StreamReader(fsRead))
{
...
}
Another way to achieve what you want is using a specialized TextWriter that writes the StreamWriter and a StringBuilder:
using (StreamWriter _logFile = File.CreateText(_logFileName))
{
using (var builder = new StringBuildingStreamWriter(_logFile))
{
builder.WriteLine("Logfile name is: " + _logFileName);
builder.WriteLine("LOG FILE STARTED AT: " + _startDateTime.ToString());
builder.WriteLine("============================================");
builder.Write(_message);
builder.WriteLine();
content += builder.ToString();
}
_logFile.Close();
}
public class StringBuildingStreamWriter:TextWriter
{
StringBuilder sb = new StringBuilder();
private StreamWriter sw;
public StringBuildingStreamWriter(StreamWriter sw)
{
this.sw = sw;
}
public override void WriteLine(string value)
{
sb.AppendLine(value);
sw.WriteLine(value);
}
public override void WriteLine()
{
sw.WriteLine();
sb.AppendLine();
}
public override void Write(string value)
{
sb.Append(value);
sw.Write(value);
}
public override string ToString()
{
return sb.ToString();
}
public override Encoding Encoding
{
get { return UTF8Encoding.UTF8; }
}
}
I'm overwriting a file using C# in Windows Phone 7. When I do this a seemingly random character is added to the start of each line.
Why is this happening?
Code:
public static bool overwriteFile(string filename, string[] inputArray)
{
try
{
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
FileStream stream = store.OpenFile(filename, FileMode.Create);
BinaryWriter writer = new BinaryWriter(stream);
foreach (string input in inputArray)
{
writer.Write(input + "\n");
}
writer.Close();
return true;
}
catch (IOException ex)
{
return false;
}
}
Lodaing Code:
public static Idea[] getFile(string filename)
{
try
{
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
string fileContents = null;
if (store.FileExists(filename)) // Check if file exists
{
IsolatedStorageFileStream save = new IsolatedStorageFileStream(filename, FileMode.Open, store);
StreamReader streamReader = new StreamReader(save);
fileContents = streamReader.ReadToEnd();
save.Close();
}
string[] lines = null;
if (fileContents != null)
{
lines = fileContents.Split('\n');
}
Idea[] ideaList = null;
if (lines != null)
{
ideaList = new Idea[lines.Length];
for (int i = 0; i < lines.Length; i++)
{
ideaList[i] = new Idea(lines[i].TrimEnd('\r'));
}
}
return ideaList;
}
catch (IOException ex)
{
return null;
}
}
The random character is a length prefix; see http://msdn.microsoft.com/en-us/library/yzxa6408.aspx.
You should be using some type of TextWriter to write strings to the file; NOT a BinaryWriter.
A StreamWriter might be the best and then you could use the WriteLine method.
Instead of using '\n', try using Environment.NewLine
You are using a BinaryWriter to write, and a TextReader to read. Change your write code to use a StreamWriter (which is a TextWriter) instead of a BinaryWriter. This will also get you the WriteLine method that Naveed recommends.
try changing this
writer.Write(input + "\n");
to
writer.WriteLine(input);
I have a windows service writes its log in a text file in a simple format.
Now, I'm going to create a small application to read the service's log and shows both the existing log and the added one as live view.
The problem is that the service locks the text file for adding the new lines and at the same time the viewer application locks the file for reading.
The Service Code:
void WriteInLog(string logFilePath, data)
{
File.AppendAllText(logFilePath,
string.Format("{0} : {1}\r\n", DateTime.Now, data));
}
The viewer Code:
int index = 0;
private void Form1_Load(object sender, EventArgs e)
{
try
{
using (StreamReader sr = new StreamReader(logFilePath))
{
while (sr.Peek() >= 0) // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
sr.Close();
}
timer1.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader(logFilePath))
{
// skipping the old data, it has read in the Form1_Load event handler
for (int i = 0; i < index ; i++)
sr.ReadLine();
while (sr.Peek() >= 0) // reading the live data if exists
{
string str = sr.ReadLine();
if (str != null)
{
AddLineToGrid(str);
index++;
}
}
sr.Close();
}
}
Is there any problem in my code in reading and writing way?
How to solve the problem?
You need to make sure that both the service and the reader open the log file non-exclusively. Try this:
For the service - the writer in your example - use a FileStream instance created as follows:
var outStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Write, FileShare.ReadWrite);
For the reader use the same but change the file access:
var inStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);
Also, since FileStream implements IDisposable make sure that in both cases you consider using a using statement, for example for the writer:
using(var outStream = ...)
{
// using outStream here
...
}
Good luck!
Explicit set up the sharing mode while reading the text file.
using (FileStream fs = new FileStream(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (sr.Peek() >= 0) // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
}
}
new StreamReader(File.Open(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
-> this doesn't lock the file.
The problem is when you are writing to the log you are exclusively locking the file down so your StreamReader won't be allowed to open it at all.
You need to try open the file in readonly mode.
using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (!fs.EndOfStream)
{
string line = fs.ReadLine();
// Your code here
}
}
}
I remember doing the same thing a couple of years ago. After some google queries i found this:
FileStream fs = new FileStream(#”c:\test.txt”,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite);
i.e. use the FileShare.ReadWrite attribute on FileStream().
(found on Balaji Ramesh's blog)
Have you tried copying the file, then reading it?
Just update the copy whenever big changes are made.
This method will help you to fastest read a text file and without locking it.
private string ReadFileAndFetchStringInSingleLine(string file)
{
StringBuilder sb;
try
{
sb = new StringBuilder();
using (FileStream fs = File.Open(file, FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (StreamReader sr = new StreamReader(bs))
{
string str;
while ((str = sr.ReadLine()) != null)
{
sb.Append(str);
}
}
}
}
return sb.ToString();
}
catch (Exception ex)
{
return "";
}
}
Hope this method will help you.
I've downloaded ICSharpCode.SharpZipLib and DotNetZip. I'm zipping over 100 files at a time varying a meg to 4 megs. When I use ICSharpCode I get a 'ContextSwitchDeadlock' error. DotNetZip fails on the finalizing of the file every time.
Also, I'm working on sharepoint folders (mapped to my local drive)
private bool zipall()
//ICSharpCode
{
int i = 0;
progressBarzipping.Minimum = 0;
progressBarzipping.Maximum = listBoxfiles.Items.Count;
ZipOutputStream zipOut = new ZipOutputStream(File.Create(textBoxDropPath.Text + "\\" + textBoxZipFileName.Text + ".zip"));
foreach (string fName in listBoxfiles.Items)
{
try
{
FileInfo fi = new FileInfo(fName);
ZipEntry entry = new ZipEntry(fi.Name);
FileStream sReader = File.OpenRead(fName);
byte[] buff = new byte[Convert.ToInt32(sReader.Length)];
sReader.Read(buff, 0, (int)sReader.Length);
entry.DateTime = fi.LastWriteTime;
entry.Size = sReader.Length;
sReader.Close();
zipOut.PutNextEntry(entry);
zipOut.Write(buff, 0, buff.Length);
}
catch
{
MessageBox.Show("Zip Failed");
zipOut.Finish();
zipOut.Close();
progressBarzipping.Value = 0;
return false;
}
i++;
progressBarzipping.Value = i;
}
zipOut.Finish();
zipOut.Close();
MessageBox.Show("Zip Complete");
progressBarzipping.Value = 0;
return true;
}
//Not sure but I think this was my DotNetZip approach
//using (ZipFile zip = new ZipFile())
// {
// foreach(string file in listboxFiles.Items)
// {
// zip.AddFile(file);
// }
// zip.Save(PathToNewZip);
// }
You didn't provide the exception. When using DotNetZip, I guess the problem might be with the sharepoint mapped drive. DotNetZip normally will save the zip as a temp file, then rename it. Maybe this isn't working because of sharepoint. If that's the case, try opening a filestream and saving it to that stream. This avoids the rename operation.
progressBarzipping.Minimum = 0;
progressBarzipping.Maximum = listBoxfiles.Items.Count;
using (Stream fs = new FileStream(PathToNewZip, FileMode.Create, FileAccess.Write))
{
using (ZipFile zip = new ZipFile())
{
zip.AddFiles(listboxFiles.Items);
// do the progress bar:
zip.SaveProgress += (sender, e) => {
if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) {
progressBarzipping.PerformStep();
}
};
zip.Save(fs);
}
}