How to generate a binary file? C# - c#

I need to make a method that generates a binary (4 bytes long), receives List of integers and writes this List one by one in the file. So, I have this:
public void FrameCodesBinaryWriter(List<int> frameCodes)
{
using (FileStream fileStream = new FileStream(binaryFilePath, FileMode.Create)) // destiny file directory.
{
using (BinaryWriter binaryWriter = new BinaryWriter(fileStream))
{
for (int i = 0; i < frameCodes.Count; i++)
{
binaryWriter.Write(frameCodes[i]);
}
binaryWriter.Close();
}
}
}
is this correct? or some other solution please

As it is it should work fine. Here is a refactored version, you can pick and choose which bits of the refactoring you like.
public void WriteFrameCodesAsBinary(IEnumerable<int> frameCodes)
{
using (FileStream fileStream = new FileStream(binaryFilePath, FileMode.Create))
using (BinaryWriter binaryWriter = new BinaryWriter(fileStream))
{
foreach (int frameCode in frameCodes) {
binaryWriter.Write(frameCode);
}
}
}
I would rename the function to describe the action it will do. FrameCodesBinaryWriter sounds more like a class name to me.
If you don't need the ordering of the List<T>, it might be an idea to accept an IEnumerable<T> instead. That way you can be more flexible about what you pass in.
Some people like to stack their using statements to remove a layer of nesting (code indentation). Personally I'm not a massive fan of this, but it's a matter of personal taste and style.
Using an IEnumerable<T> forces us to use foreach, but even with List<T> it can look cleaner/make it more obvious you are iterating through the list.
As previously mentioned, if you are using using you don't need to explicitly close the binary writer - that will be done automatically when the using block is exited.

You don't need to close binaryWriter because you have a using clause anyway. binaryFilePath needs to be a field of the class, apart from that it looks ok.

Related

IEnumerable emit as stream?

Is there a way to take an IEnumerable<T> and emit it as a readable stream kinda like this?
private void DoTheThing(IEnumerable<Foo> foos)
{
using (var myStream = foos.EmitAsStream(f =>
{
var line = JsonConvert.SerializeObject(f);
return line;
}))
using(var streamReader = new StreamReader(myStream))
{
while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();
Console.WriteLine(line);
}
}
}
Obviously, there are some problems with this, for example it seems to imply a StreamWriter with none specified, but the idea would be that the stream reader would just yield enumerate through the IEnumerable under the hood, apply the transform delegate, and pull the results without making any new, potentially large objects in memory.
I have some very large enumerable objects in memory, and I need to push them to external places (like Amazon S3) which accepts a stream. I really can't afford to build a MemoryStream with the collection and send that; I can spool to disk and read from disk, but I'd prefer not to if I have the option, since it seems like an extra step.
Is this possible? If it's possible, is it practical?
You can, achieve that by using TakeWhile, if I right understood your problem.
Something like :
while(..end ..)
{
var enumeration = foos.TakeWhile(..line bounds..);
var stream = StreamFromEnum(enumeration ); //custom implementation
// stream --> S3
}
I presume you have some custom definition of "line", which might be some sort of stride/slice of data from the stream.
A lazily-evaluated stream wrapper for IEnumerable is a one possible implementation of IEnumerable<T> -> Stream conversion.
The EnumerableToStream package will do exactly what you ask:
using EnumerableToStream;
using (var myStream = foos.Select(f =>
{
var line = JsonConvert.SerializeObject(f);
return line;
}).ToStream())
That ToStream() method is the one that does the magic. If you are interested in the implementation details, have a look at the source code.

How do I locate a particular word in a text file using .NET

I am sending mails (in asp.net ,c#), having a template in text file (.txt) like below
User Name :<User Name>
Address : <Address>.
I used to replace the words within the angle brackets in the text file using the below code
StreamReader sr;
sr = File.OpenText(HttpContext.Current.Server.MapPath(txt));
copy = sr.ReadToEnd();
sr.Close(); //close the reader
copy = copy.Replace(word.ToUpper(),"#" + word.ToUpper()); //remove the word specified UC
//save new copy into existing text file
FileInfo newText = new FileInfo(HttpContext.Current.Server.MapPath(txt));
StreamWriter newCopy = newText.CreateText();
newCopy.WriteLine(copy);
newCopy.Write(newCopy.NewLine);
newCopy.Close();
Now I have a new problem,
the user will be adding new words within an angle, say for eg, they will be adding <Salary>.
In that case i have to read out and find the word <Salary>.
In other words, I have to find all the words, that are located with the angle brackets (<>).
How do I do that?
Having a stream for your file, you can build something similar to a typical tokenizer.
In general terms, this works as a finite state machine: you need an enumeration for the states (in this case could be simplified down to a boolean, but I'll give you the general approach so you can reuse it on similar tasks); and a function implementing the logic. C#'s iterators are quite a fit for this problem, so I'll be using them on the snippet below. Your function will take the stream as an argument, will use an enumerated value and a char buffer internally, and will yield the strings one by one. You'll need this near the start of your code file:
using System.Collections.Generic;
using System.IO;
using System.Text;
And then, inside your class, something like this:
enum States {
OUT,
IN,
}
IEnumerable<string> GetStrings(TextReader reader) {
States state=States.OUT;
StringBuilder buffer;
int ch;
while((ch=reader.Read())>=0) {
switch(state) {
case States.OUT:
if(ch=='<') {
state=States.IN;
buffer=new StringBuilder();
}
break;
case States.IN:
if(ch=='>') {
state=States.OUT;
yield return buffer.ToString();
} else {
buffer.Append(Char.ConvertFromUtf32(ch));
}
break;
}
}
}
The finite-state machine model always has the same layout: while(READ_INPUT) { switch(STATE) {...}}: inside each case of the switch, you may be producing output and/or altering the state. Beyond that, the algorithm is defined in terms of states and state changes: for any given state and input combination, there is an exact new state and output combination (the output can be "nothing" on those states that trigger no output; and the state may be the same old state if no state change is triggered).
Hope this helps.
EDIT: forgot to mention a couple of things:
1) You get a TextReader to pass to the function by creating a StreamReader for a file, or a StringReader if you already have the file on a string.
2) The memory and time costs of this approach are O(n), with n being the length of the file. They seem quite reasonable for this kind of task.
Using regex.
var matches = Regex.Matches(text, "<(.*?)>");
List<string> words = new List<string>();
for (int i = 0; i < matches.Count; i++)
{
words.Add(matches[i].Groups[1].Value);
}
Of course, this assumes you already have the file's text in a variable. Since you have to read the entire file to achieve that, you could look for the words as you are reading the stream, but I don't know what the performance trade off would be.
This is not an answer, but comments can't do this:
You should place some of your objects into using blocks. Something like this:
using(StreamReader sr = File.OpenText(HttpContext.Current.Server.MapPath(txt)))
{
copy = sr.ReadToEnd();
} // reader is closed by the end of the using block
//remove the word specified UC
copy = copy.Replace(word.ToUpper(), "#" + word.ToUpper());
//save new copy into existing text file
FileInfo newText = new FileInfo(HttpContext.Current.Server.MapPath(txt));
using(var newCopy = newText.CreateText())
{
newCopy.WriteLine(copy);
newCopy.Write(newCopy.NewLine);
}
The using block ensures that resources are cleaned up even if an exception is thrown.

How to append data to a binary file?

I have a binary file to which I want to append a chunk of data at the end of the file, how can I achieve this using C# and .net? Also is there anything to consider when writing to the end of a binary file? Thanks a lot for your help.
private static void AppendData(string filename, int intData, string stringData, byte[] lotsOfData)
{
using (var fileStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.None))
using (var bw = new BinaryWriter(fileStream))
{
bw.Write(intData);
bw.Write(stringData);
bw.Write(lotsOfData);
}
}
You should be able to do this via the Stream:
using (FileStream data = new FileStream(path, FileMode.Append))
{
data.Write(...);
}
As for considerations - the main one would be: does the underlying data format support append? Many don't, unless it is your own raw data, or text etc. A well-formed xml document doesn't support append (without considering the final end-element), for example. Nor will something like a Word document. Some do, however. So; is your data OK with this...
Using StreamWriter and referencing DotNetPerls, make sure to add the True boolean to the StreamWriter constructor, if otherwise left blank, it'll overwrite as usual:
using System.IO;
class Program
{
static void Main()
{
// 1: Write single line to new file
using (StreamWriter writer = new StreamWriter("C:\\log.txt", true))
{
writer.WriteLine("Important data line 1");
}
// 2: Append line to the file
using (StreamWriter writer = new StreamWriter("C:\\log.txt", true))
{
writer.WriteLine("Line 2");
}
}
}
Output
(File "log.txt" contains these lines.)
Important data line 1
Line 2
This is the solution that I was actually looking for when I got here from Google, although it wasn't a binary file though, hope it helps someone else.

How to save a human readable file

Currently i have an application that reads and writes several properties from one or two basic classes to a .txt file using the Binary Serializer.
I've opened up the .txt file in NotePad and as it's formatted for the application it's not very readable to the human eye, not for me anyway =D
I've heard of using XML but pretty much most of my searches seem to overcomplicate things.
The kind of data im trying to save is simply a collection of "Person.cs" classes,nothing more than a name and address, all private strings but with properties and marked as Serializable.
What would be the best way to actually save my data in a way that can be easily read by a person? It would also make it easier to make small changes to the application's data directly in the file instead of having to load it, change it and save it.
Edit:
I have added the current way i am saving and loading my data, my _userCollection is as it suggests and the nUser/nMember are an integer.
#region I/O Operations
public bool SaveData()
{
try
{
//Open the stream using the Data.txt file
using (Stream stream = File.Open("Data.txt", FileMode.Create))
{
//Create a new formatter
BinaryFormatter bin = new BinaryFormatter();
//Copy data in collection to the file specified earlier
bin.Serialize(stream, _userCollection);
bin.Serialize(stream, nMember);
bin.Serialize(stream, nUser);
//Close stream to release any resources used
stream.Close();
}
return true;
}
catch (IOException ex)
{
throw new ArgumentException(ex.ToString());
}
}
public bool LoadData()
{
//Check if file exsists, otherwise skip
if (File.Exists("Data.txt"))
{
try
{
using (Stream stream = File.Open("Data.txt", FileMode.Open))
{
BinaryFormatter bin = new BinaryFormatter();
//Copy data back into collection fields
_userCollection = (List<User>)bin.Deserialize(stream);
nMember = (int)bin.Deserialize(stream);
nUser = (int)bin.Deserialize(stream);
stream.Close();
//Sort data to ensure it is ordered correctly after being loaded
_userCollection.Sort();
return true;
}
}
catch (IOException ex)
{
throw new ArgumentException(ex.ToString());
}
}
else
{
//Console.WriteLine present for testing purposes
Console.WriteLine("\nLoad failed, Data.txt not found");
return false;
}
}
Replace your BinaryFormatter with XMLSerializer and run the same exact code.
The only change you need to make is the BinaryFormatter takes an empty constructor, while for the XMLSerializer you need to declare the type in the constructor:
XmlSerializer serializer = new XmlSerializer(typeof(Person));
Using XmlSerializer is not really complicated. Have a look at this MSDN page for an example: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
You could implement your own PersonsWriter, that takes a StreamWriter as constructor argument and has a Write method that takes an IList<Person> as input to parse out a nice text representation.
For example:
public class PersonsWriter : IDisposable
{
private StreamWriter _wr;
public PersonsWriter(IList<Person> persons, StreamWriter writer)
{
this._wr = writer;
}
public void Write(IList<Persons> people) {
foreach(Person dude in people)
{
_wr.Write(#"{0} {1}\n{2}\n{3} {4}\n\n",
dude.FirstName,
dude.LastName,
dude.StreetAddress,
dude.ZipCode,
dude.City);
}
}
public void Dispose()
{
_wr.Flush();
_wr.Dispose();
}
}
YAML is another option for human readable markup that is also easy to parse. there are libraries available for c# as well as almost all other popular languages. Here's a sample of what yaml looks like:
invoice: 34843
date : 2001-01-23
bill-to: &id001
given : Chris
family : Dumars
address:
lines: |
458 Walkman Dr.
Suite #292
city : Royal Oak
state : MI
postal : 48046
Frankly, as a human, I don't find XML to be all that readable. In fact, it's not really designed to be read by humans.
If you want a human readable format, then you have to build it.
Say, you have a Person class that has a First Name, a last Name and a SSN as properties. Create your file, and have it write out 3 lines, with a description of the field in the first fifty (random number from my head) and then with character 51 have the value start being written.
This will produce a file that looks like:
First Name-------Stephen
Last Name -------Wrighton
SSN -------------XXX-XX-XXXX
Then, reading it back in, your program would know where the data begins on each line, and what each line is for (the program would know that Line 3 is the SSN value).
But remember, to truly gain human readability, you sacrifice data portability.
Try the DataContractSerializer
It serializes objects to XML and is very easy to use
Write a CSV reader writer if you want a good compromise between human and machine readable in a Windows environment
Loads into Excel too.
There's a discussion about it here:
http://knab.ws/blog/index.php?/archives/3-CSV-file-parser-and-writer-in-C-Part-1.html
EDIT
That is a C# article... it just confusingly has "C" in the URL.
I really think you should go with XML (look into DataContractSerializer). Its not that complicated. You could probably even just replace BinarySerializer with XMLSerializer and go.
If you still don't want to do that, though, you can write a delimited text file. Then you'll have to write your own reader method (although, it could almost just use the split method).
//Inside the Person class:
public override string ToString()
{
List<String> propValues = new List<String>();
// Get the type.
Type t = this.GetType();
// Cycle through the properties.
foreach (PropertyInfo p in t.GetProperties())
{
propValues.add("{0}:={1}", p.Name, p.GetValue(o, null));
}
return String.Join(",". propValues.ToArray())
}
using (System.IO.TextWriter tw = new System.IO.StreamWriter("output.txt"))
{
tw.WriteLine(person.ToString());
}

Which way to save custom types to a file on a mobile device?

I have a list of custom types, they need to be saved/loaded to/from a file on a mobile device (Windows Mobile 6) what method would be the most suited, taking into account the limited resources of the device?
EDIT:
The data file will be around 2-5mb
How much data are we talking about?
I used an old device (HTC-s620, with a TI OMAP 850 200 MHz processor) to save a 2mb XML file using XML Serialization, in a matter of 3-5 seconds. Very simple programming model. Very easy to do. With a newer device I'm sure it would be much faster.
My usage scenario was, one full load, and one full save, per run.
[XmlRoot("notes")]
public class NoteList : List<Note>
{
// Set this to 'default' or 'preserve'.
[XmlAttribute("space", Namespace = "http://www.w3.org/XML/1998/namespace")]
public string space = "preserve";
public static void Save(NoteList noteList, string NotesFilePath)
{
if (noteList == null) return;
XmlSerializer serializer = new XmlSerializer(typeof(NoteList));
string tmpPath = NotesFilePath + ".tmp";
using (System.IO.FileStream fs = new FileStream(tmpPath, FileMode.Create, FileAccess.Write))
{
serializer.Serialize(fs, noteList);
fs.Close();
}
if (File.Exists(tmpPath))
{
if (File.Exists(NotesFilePath))
{
string oldFile = NotesFilePath + ".bak";
if (File.Exists(oldFile)) File.Delete(oldFile);
File.Move(NotesFilePath, oldFile);
}
File.Move(tmpPath, NotesFilePath);
}
}
public static NoteList Load(string NotesFilePath)
{
if (!System.IO.File.Exists(NotesFilePath))
return null;
NoteList noteList = new NoteList();
XmlSerializer serializer = new XmlSerializer(noteList.GetType());
using (FileStream fs = new FileStream(NotesFilePath, FileMode.Open, FileAccess.Read))
{
noteList = (NoteList)serializer.Deserialize(fs);
fs.Close();
}
return noteList;
}
}
Devices capable of running Win Mobile 6, seem to be able to handle themselves quite well using the "crippled" .NET framework.
But if you want something faster then what System.IO provides, I think you're out of luck (?).
With "custom types", I gather you're referring to classes, and by that I suspect some .NET compliant classes? Then I don't see how you're going to squeeze any more juice...at least no more than
this happy camper got.
I'd recommend looking at SqlLite if you want a proper db but without the bloat. SqlLite is also atomic and power resilient. Otherwise saving to a flat file isn't a problem. Just remember that the power can die on you at any point, including half-way through your write.

Categories