I'm trying to read from a binary file with BinaryReader.
This is how I call my reading method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (File.Exists(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt"))
{
string[] myArray = operationManager.BinaryReading(film.MovieName);
if (myArray != null)
{
this.textStarring.Text = myArray[1];
this.textProduced.Text = myArray[2];
this.textMusic.Text = myArray[3];
this.textYear.Text = myArray[4];
this.textTime.Text = myArray[5];
}
else
{
MessageBox.Show("An error occured");
}
}
This is my reading method :
public string[] BinaryReading(string name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + name + ".txt", FileMode.Open);
BinaryReader reader = new BinaryReader(myStream);
string loadString = reader.ReadString();
string[] loadArray = loadString.Split(',');
reader.Close();
myStream.Close();
return loadArray;
}
Now something within these lines is not working. My file is not empty because since it's only a string I can read whats in the file.
My problem is I'm trying to find whats wrong with a break point but as soon as I get past this line :
string loadString = reader.ReadString();
My program starts to run again. How is that possible ? This prevents me from checking what's inside my String[] and what are my values after the method call.
Any idea why ? Thanks in advance.
Update :
I tried to move my breakpoint here
string[] loadArray = loadString.Split(',');
But my program never stops so it never gets past the previous line.
Also this is my Writting method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (film.MovieName == name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt", FileMode.Create);
BinaryWriter writer = new BinaryWriter(myStream);
writer.Write(film.MovieName + "," + starring + "," + produced + "," + music + "," + year + "," + lenght);
writer.Close();
myStream.Close();
}
}
Your string will be prefixed with a length field. That makes the .txt extension misleading.
Since it 'suddenly started working again' : is it possible you opened (and saved) one of the files with a Text editor?
Also, your current Read and Write methods are not thread-safe, you should enclose the Stream and Reader/Writer objects in using() {} statements.
Related
I am working on a website ATM school project, and I need to be able to rewrite the account balance in the original .txt file based on session transactions. The .txt file contains 3 lines, each with (username),(password),(balance). The issue I'm having is that the program cannot write to file while it is still reading it. The loop works fine if I write to a different file, but I have to edit the original (so the updated balance is retained the next time the program is run). Below is the code from the Logout page load event.
//Stream variable
StreamReader readFile;
StreamWriter writeFile;
//Counter variable
int index = 0;
//Open file
readFile = File.OpenText(#"C:\C#\Project4_TSullivan\loginFile.txt");
//Array rows
const int ROWS = 3;
while (index < ROWS && !readFile.EndOfStream)
{
string str = readFile.ReadLine();
string[] tokens = str.Split(',');
//Check if username matches session username
if (tokens[0] == Convert.ToString(Session["sessionUserName"]))
{
//Update balance
tokens[2] = Convert.ToString(Session["sessionBalance"]);
}
if (index == 0)
{
writeFile = File.CreateText(#"C:\C#\Project4_TSullivan\loginFile.txt");
writeFile.WriteLine(tokens[0] + "," + tokens[1] + "," + tokens[2]);
writeFile.Close();
}
else
{
writeFile = File.AppendText(#"C:\C#\Project4_TSullivan\loginFile.txt");
writeFile.WriteLine(tokens[0] + "," + tokens[1] + "," + tokens[2]);
writeFile.Close();
}
index++;
}
//Close file
readFile.Close();
Please let me know if any additional info would be helpful. I may be going about this in entirely the wrong way, and any advice would be much appreciated. Thanks!
Edited
Here is the solution in case the mods want to save it. Using File.ReadAllLines I was able to store the contents of the file in an array. Then I created 3 more arrays (1 for each line in the file) to tokenize each line.
string path = #"C:\C#\Project4_TSullivan\loginFile.txt";
string[] readFile = File.ReadAllLines(path);
string[] token0 = readFile[0].Split(',');
string[] token1 = readFile[1].Split(',');
string[] token2 = readFile[2].Split(',');
if (token0[0] == Convert.ToString(Session["sessionUsername"]))
{
token0[2] = Convert.ToString(Session["sessionBalance"]);
}
else if (token1[0] == Convert.ToString(Session["sessionUsername"]))
{
token1[2] = Convert.ToString(Session["sessionBalance"]);
}
else
{
token2[2] = Convert.ToString(Session["sessionBalance"]);
}
using (StreamWriter writeFile = File.CreateText(path))
{
writeFile.WriteLine(token0[0] + "," + token0[1] + "," + token0[2]);
writeFile.WriteLine(token1[0] + "," + token1[1] + "," + token1[2]);
writeFile.WriteLine(token2[0] + "," + token2[1] + "," + token2[2]);
}
I'm doing a c# wcf service in which I receive a bunch of images and the service merge them in a multiimage Tiff file. At the end of the service I want to delete the original files but I'm receiving an error that some other process is locking the file.
This is the code that receives the images (as a byte[] list) and write them to disk
public static List<string> SaveByteImagesToFile(List<byte[]> bytesToCopyIntoFiles, string imageReferenceType, string imageReferenceValue)
{
_applicationLogger.Debug(MethodBase.GetCurrentMethod().DeclaringType.Name, MethodBase.GetCurrentMethod().Name);
string imageFinalPath = string.Empty;
string joinImagesFilePath = string.Empty;
List<string> imagesFilePath = new List<string>();
int count = 1;
try
{
if (bytesToCopyIntoFiles.Count == 0)
{
throw new ArgumentNullException("bytesToCopyIntoFiles");
}
else
{
joinImagesFilePath = SettingsManager.GetServiceSetting(AppSettingsKeys.CopyImagesToFilePath, "NO_VALID_FILEPATH");
if (joinImagesFilePath.IsValidFilePath(out string errorMessage, true, true))
{
foreach (byte[] image in bytesToCopyIntoFiles)
{
var imageFileName = imageReferenceType + "_" + imageReferenceValue + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + count.ToString();
imageFinalPath = joinImagesFilePath + Path.DirectorySeparatorChar + imageFileName + ".tiff";
using (FileStream stream = new FileStream(imageFinalPath, FileMode.Create, FileAccess.ReadWrite))
{
stream.Write(image, 0, image.Length);
stream.Flush();
}
imagesFilePath.Add(imageFinalPath);
count++;
}
}
else
{
exceptionMessageType = MainRepository.GetExceptionMessage("E171");
throw new IOException(exceptionMessageType.ExceptionMessage + " " + errorMessage);
}
}
return imagesFilePath;
}
catch
{
throw;
}
}
How or what can I use to prevent the service or any process to lock the file. As you can see I'm using the using scope for filestream without any luck.
Any ideas? Thanks
Resolved! By organizing the files in a certain order, when creating the multipage tiff, by the time the logic ends the worker already unlock the resources and I'm able now to delete them without any issue.
I've honestly been researching about this for hours, and I still haven't found anything close to what I am looking for.
Basically I created a folder in my project and called it "Files". Then I added a lot of actual files to that folder, and now I want to access them via a void, but I can't get the names of them.
I've tried to display the files in a message box (just for testing purposes), so I used this:
public static string[] GetResourceNames()
{
var asm = Assembly.GetEntryAssembly();
string resName = asm.GetName().Name + ".Files";
using (var stream = asm.GetManifestResourceStream(resName))
using (var reader = new System.Resources.ResourceReader(stream))
{
return reader.Cast<DictionaryEntry>().Select(entry => (string)entry.Key).ToArray();
}
}
But all it does is return an error saying the reader can't be null.
I'm trying to show it in a foreach loop like this:
foreach (string resourceName in GetResourceNames())
{
MessageBox.Show(resourceName);
}
but it shows nothing.
What I'm trying to do is this:
Assembly assembly = Assembly.GetExecutingAssembly();
int totalFiles = 17;
int currentFiles = 0;
foreach (var file in assembly.GetManifestResourceNames())
{
string extractPath = functions.pathToExtract + #"\" + file;
using (Stream s = assembly.GetManifestResourceStream(file))
using (BinaryReader r = new BinaryReader(s))
using (FileStream fs = new FileStream(extractPath, FileMode.OpenOrCreate))
using (BinaryWriter w = new BinaryWriter(fs))
w.Write(r.ReadBytes((int)s.Length));
currentFile.Invoke((MethodInvoker)delegate { currentFile.Text = "Installing : " + file + " ( " + currentFiles + " out of "+ totalFiles + " installed )"; });
currentFiles += 1;
}
This is what I'm trying to do, and this is code is successful, but it writes the file names as: SolutionName.Files.FileName.Extension and I only want it to write as FileName.Extension
What am I doing wrong here?
Well, a resource file is stored with the format you've specified: [Solution].[Folder].[File].[Extension].
Assuming all you really want to do is remove the initial [Solution].[Folder] from file names you can just use String.Replace.
Something like:
var fileName = file.Replace("[Solution].[Folder]", "");
Then use fileName for the currentFile.Text or for extractPath. Be mindful that I don't know what functions.pathToExtract + #"\" + file in your code produces at the moment, so it's a bit of a guess on my part, but I think this would produce a sensible path which could be used for extracting embedded resources.
I have a file that is being created based on the items in a Repeater control if the radioButton for each item is "Yes". My issue that if the file is empty, it is still being created. I have tried FileName.Length > 0 and other possible solutions but I get errors that the file can not be found. I am sure the issue is within my logic but I cant see where. Any ideas?
protected void btnContinue_Click(object sender, EventArgs e)
{
string JobName;
string FileName;
StreamWriter sw;
string Name, Company, Date;
JobName = TYest + "_" + System.DateTime.Now;
JobName = JobName.Replace(":", "").Replace("/", "").Replace(" ", "");
FileName = JobName + ".txt";
sw = new StreamWriter(C: +"/" + FileName, false, Encoding.GetEncoding(1250));
foreach ( RepeaterItem rpItems in rpGetData.Items )
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if ( rbYesNo.SelectedItem.Text == "Yes" )
{
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
sw.Flush();
sw.Dispose();
if ( File.Exists("C:/" + FileName) )
{
try
{
File.Copy(+"C:/" + FileName, LoftwareDropPath + FileName, true);
}
catch ( Exception ex )
{
string msgE = "Error";
msgE += ex.Message;
throw new Exception(msgE);
}
}
else
{
//Do something if temp file not created properly
lblMessage.Text = "An error has occurred. Plese see your host to get a printed name badge.";
}
MessageBox messageBox = new MessageBox();
messageBox.MessageTitle = "Printed?";
messageBox.MessageText = "If not, please see host.";
Literal1.Text = messageBox.Show(this);
}
}
sounds like you want to detect if a file is empty. Use:
long length = new System.IO.FileInfo(path).Length;
if(length == 0)....
FileName.Length just tells you how long the file name is - not usefule
Why not check if the file exists first? That should solve your exception problems! If you want to know if the file is empty I would recommend checking what you're writing to the file and making sure it's not all empty and THEN write to the file if you actually have content?
if(File.Exists(File))
{
if(new FileInfo(File).Length > 0)
{
//Do Stuff.
}
}
How about this:
StreamWriter sw = null;
string Name, Company, Date;
JobName = TYest + "_" + System.DateTime.Now;
JobName = JobName.Replace(":", "").Replace("/", "").Replace(" ", "");
FileName = #"C:\" + JobName + ".txt";
try
{
foreach (RepeaterItem rpItems in rpGetData.Items)
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if (rbYesNo.SelectedItem.Text == "Yes")
{
if (null == sw)
sw = new StreamWriter(FileName, false, Encoding.GetEncoding(1250));
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
}
finally
{
if (null != sw)
{
sw.Flush();
sw.Dispose();
}
}
Build your FileName completely once so that you know it is always the same. Then only create your StreamWriter if something is going to be written. Also, use a try..finally to make sure your code to free your resources is always hit.
You should change it to only write and create the file when you have some data to write.
A simple way of doing this is to store everything memory with something like a StringBuilder, then afterwards write the contents of the string builder to the file if there is something to write:
var sb = new StringBuilder();
foreach (RepeaterItem rpItems in rpGetData.Items)
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if (rbYesNo.SelectedItem.Text == "Yes")
{
// ..omitted..
sb.AppendLine("Name," + Name);
sb.AppendLine("Company," + Company);
sb.AppendLine("Date," + Date);
sb.AppendLine("*PRINTLABEL");
}
}
if (sb.Length > 0)
{
File.WriteAllText(FileName, sb.ToString(), Encoding.GetEncoding(1250));
}
You can check whether any items are eligible for saving before opening the stream writer like this:
var itemsToBeSaved = rpGetData.Items
Where(ri => ((RadioButtonList)ri.FindControl("rbBadge")).SelectedItem.Text == "Yes");
if (itemsToBeSaved.Any()) {
string path = #"C:\" + FileName;
using (var sw = new StreamWriter(path, false, Encoding.GetEncoding(1250))) {
foreach (RepeaterItem rpItems in itemsToBeSaved) {
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
} // Flushes, Closes und Disposes the stream automatically.
}
The first statement prepares a filtered enumeration of repeater items containing only the ones to be saved. itemsToBeSaved.Any() tests if this enumeration contains at least one item. This enumeration is then reused in the foreach statement. Therefore it is not necessary to check the conditions again.
The using statement takes care of closing the stream in all situations, even if an exception should occur while writing to the file. I also declared the stream writer in the using statement. Therefore you can delete your declaration StreamWriter sw = null;.
Also note the expression #"C:\" + FileName. The # makes the string constant a verbatim string. This means that the usual escape character '\' loses its meaning and is used as is. Path.Combine(...) does not work here, since it does not add the path separator after a drive letter.
I have a program that employs a simple logging process. The idea is that every day a new file gets created that corresponds with the date unless the file already exists, in which case it's just appended to. The problem is, File.Create is throwing an error every time it runs. I found a solution to the problem that says File.Create is opening a FileStream and you just need to call it with a .close(); but that solution didn't work for me, I'm still getting the IO exception saying that the file is in use by another process, which is impossible since it doesn't exist until File.Create creates it, and nothing else uses these files.
Here's the code:
public static void logResults(System.Reflection.MethodBase method, Results result, string message)
{
string date = DateTime.Now.ToString();
int index = date.IndexOf(" ");
string subString = date.Substring(0, index);
string nwDate = Regex.Replace(subString, "/", "");
logFileName = "WebsiteRegressionProduction_TestCycle." + nwDate;
string currentLogFile = logFileLocation + #"\" + logFileName;
StringBuilder sb = new StringBuilder();
if (!File.Exists(currentLogFile))
{
File.Create(currentLogFile).Close();
sb.Append("DATE-TIME\tACTION\tTEST CLASS\tTEST NAME\tTEST STATUS\tERROR MESSAGES");
sb.Append("\n");
}
else
{
string previousLogs = File.ReadAllText(currentLogFile);
sb.Append(previousLogs);
}
sb.Append(DateTime.Now.ToString());
sb.Append(" : ");
sb.Append("Text Executed: ");
sb.Append(method.ReflectedType.Name + " : ");
sb.Append(method + " : ");
sb.Append(result.ToString());
sb.Append(" : ");
sb.Append(message);
sb.Append("\n");
sb.Append("\n");
File.WriteAllText(currentLogFile, sb.ToString());
File.AppendText is probably a much better option for what you are trying to accomplish. It will create the file if it is missing and add the text to the end. If you want to add the header to the start of the file, you'll just have to do a quick manual check to see if the file exists first.
Using suggestions from the answers, I've changed my code. It doesn't throw an exception anymore when first creating the file, but I'll mark an answer as Accepted when someone can explain why File.Create was throwing an IOException saying that the file was already in use and could not be accessed.
public static void logResults(System.Reflection.MethodBase method, Results result, string message)
{
string date = DateTime.Now.ToString();
int index = date.IndexOf(" ");
string subString = date.Substring(0, index);
string nwDate = Regex.Replace(subString, "/", "");
logFileName = "WebsiteRegressionProduction_TestCycle." + nwDate;
string currentLogFile = logFileLocation + #"\" + logFileName;
if (!File.Exists(currentLogFile))
{
File.WriteAllText(currentLogFile,
"DATE-TIME\tACTION\tTEST CLASS\tTEST NAME\tTEST STATUS\tERROR MESSAGES\n\n", Encoding.ASCII);
}
var sb = new StringBuilder();
sb.Append(String.Format("{0} : Test Executed: {1} : {2} : {3}\n\n", DateTime.Now.ToString(),
method.ReflectedType.Name, method, message));
using (var stream = File.AppendText(currentLogFile))
{
stream.Write(sb.ToString());
}
}
1) Why do you read all previous content to append?
2) You can simply use log4net that do all that work for "free"
However, I suggest you to use a stream to have more control over the operation
FileStream fs = new FileStream(filePath, FileMode.Append);
byte[] data = Encoding.ASCII.GetBytes("The string you wanna append");
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
The FileMode.Append open the specified (filePath) in Append if exists or create it if not.
File.Create returns FileStream, so you should be using a FileStream object like so:
FileStream fs = File.Create(currentLogFile);
Then do all your read/writes with the fs object.