I will try to make this as straight forward as possible. This question does not simply involve reading and writing bytes. I am looking for an exact translation between this VB6 code and C# code. I know this is not always a posibility but I'm sure someone out there has some ideas!
VB6 Code & explanation:
The below code writes data into a specific part of the file.
[ Put [#]filenumber, [byte position], varname ].
It is the *byte position * that I am having trouble figuring out - and help with this would be very much appreciated!
Dim file, stringA as string
Open file for Binary As #1
lPos = 10,000
stringA = "ThisIsMyData"
Put #1, lPos, stringA
Close #1
So, I am looking for some help with the byte position, once again. In this example the byte position was represented by lPos.
EDIT FOR HENK -
I will be reading binary data. There are some characters in this binary data that I will need to replace. For this reason, I will be using VB6's instr function to get the poisition of this data (there lengths are previously known). I will then use Vb6's Put function to write this data at the newfound position. This will overwrite the old data with the new data. I hope this helped!
If it helps anyone, here is some further information regarding the Put function.
Thanks so much,
Evan
Can you not use a BinaryWriter?
For example:
FileStream fs = new FileStream(file, FileMode.Open);
BinaryWriter w = new BinaryWriter(fs);
w.Seek(10000, SeekOrigin.Origin);
w.Write(encoding.GetBytes("ThisIsMyData"));
w.Flush();
w.Close();
fs.Close();
You can do this using StreamReader and StreamWriter.
I would try something like this:
Read the first n bits and write them into a new stream using StreamWriter.
Using the same StreamWriter, write the new bits that you want to insert.
Finally, write the rest of the bits from your StreamReader.
This question is not a perfect fit, however it shows a similiar technique using text (not binary data): Insert data into text file
Take a look at the StreamWriter Class specially at this overload of the Write method, which allows you to start writing to a specific place within the stream.
Related
Is there a way to tell the BinaryReader to interpret as big-endian? Like just saying "interpret everything big endian" so I don't have to write extra code to manually read in bytes, reverse them, and then convert it to int or float or whatever I need.
UPDATE
looked around, seems like you can't.
Which is kind of strange; I figured it's something you'd naturally do when writing a class that will read binary data from arbitrary files.
Try creating a BinaryReader BinaryReader(stream,encoding) using the Encoding.BigEndianUnicode Property
Since it was pointed out that this is for text only, you will have to create your own code to manually convert it, or you can use Scott Chamberlain's example at the end of this MSDN Forum Posting .
I am trying to use StreamReader and StreamWriter to Open a text file (fixed width) and to modify a few specific columns of data. I have dates with the following format that are going to be converted to packed COMP-3 fields.
020100718F
020100716F
020100717F
020100718F
020100719F
I want to be able to read in the dates form a file using StreamReader, then convert them to packed fields (5 characters), and then output them using StreamWriter. However, I haven't found a way to use StreamWriter to right to a specific position, and beginning to wonder if is possible.
I have the following code snip-it.
System.IO.StreamWriter writer;
this.fileName = #"C:\Test9.txt";
reader = new System.IO.StreamReader(System.IO.File.OpenRead(this.fileName));
currentLine = reader.ReadLine();
currentLine = currentLine.Substring(30, 10); //Substring Containing the Date
reader.Close();
...
// Convert currentLine to Packed Field
...
writer = new System.IO.StreamWriter(System.IO.File.Open(this.fileName, System.IO.FileMode.Open));
writer.Write(currentLine);
Currently what I have does the following:
After:
!##$%0718F
020100716F
020100717F
020100718F
020100719F
!##$% = Ascii Characters SO can't display
Any ideas? Thanks!
UPDATE
Information on Packed Fields COMP-3
Packed Fields are used by COBOL systems to reduce the number of bytes a field requires in files. Please see the following SO post for more information: Here
Here is Picture of the following date "20120123" packed in COMP-3. This is my end result and I have included because I wasn't sure if it would effect possible answers.
My question is how do you get StreamWriter to dynamically replace data inside a file and change the lengths of rows?
I have always found it better to to read the input file, filter/process the data and write the output to a temporary file. After finished, delete the original file (or make a backup) and copy the temporary file over. This way you haven't lost half your input file in case something goes wrong in the middle of processing.
You should probably be using a Stream directly (probably a FileStream). This would allow you to change position.
However, you're not going to be able to change record sizes this way, at least, not in-line. You can have one Stream reading from the original file, and another writing to a new, converted copy of the file.
However, I haven't found a way to use StreamWriter to right to a specific position, and
beginning to wonder if is possible.
You can use StreamWriter.BaseStream.Seek method
using (StreamWriter wr = new StreamWriter(File.Create(#"c:\Temp\aaa.txt")))
{
wr.Write("ABC");
wr.Flush();
wr.BaseStream.Seek(0, SeekOrigin.Begin);
wr.Write("Z");
}
Hey there! I'm trying to read a 150mb file with a file stream but every time I do it all I get is: |zl instead of the whole stream. Note that it has some special characters in it.
Does anybody know what the problem could be? here is my code:
using (FileStream fs = File.OpenRead(path))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
extract = Encoding.Default.GetString(buffer);
}
Edit:
I tried to read all text but it still returned the same four characters. It works fine on any other file except for these few. When I use read all lines it only gets the first line.
fs.Read() does not read the whole smash of bytes all at once, it reads some number of bytes and returns the number of bytes read. MSDN has an excellent example of how to use it to get the whole file:
http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx
For what it's worth, reading the entire 150MB of data into memory is really going to put a drain on your client's system -- the preferred option would be to optimize it so that you don't need the whole file all at once.
If you want to read text this way File.ReadAllLine (or ReadAllText) - http://msdn.microsoft.com/en-us/library/s2tte0y1.aspx is better option.
My guess the file is not text file to start with and the way you display resulting string does stop at 0 characters.
As debracey pointed out Read returns number of bytes read - check that out. Also for file operations it is unlikely to stop at 4 characters...
I have a file that exists within a text and a binary image, I need to read from 0 to 30 position the text in question, and the position on 31 would be the image in binary format.
What are the steps that I have to follow to proceed with that problem?
Currently, I am trying to read it using FileStream, and then I move the FileStream var to one BinaryReader as shown below:
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)
BinaryReader br = new BinaryReader(fs)
From there forward, I'm lost.
UPDATE
Alright, so I Can read my file now.
Until the position 30 is my 30 string, from position 30 is the bit string Which is Actually an image.
I wonder how do I read the bytes from position 30 and then save the images!
Does anyone have any ideas?
Follow an example from my file to you have some ideia:
£ˆ‰¢#‰¢#¢–”…#•…¦#„£################################.-///%<<??#[K}#k{M÷]kðñôôô}ù~øòLKóôòÿg
Note that even the # # # is my string and from that the picture would be one byte.
Expanding on Roger's answer a bit, with some code.
A string is always encoded in some format, and to read it you need to know that encoding (especially when using binary reader). In many cases, it's plain ASCII and you can use Encoding.ASCII.GetString to parse it if you get unexpected results (weird characters etc.) then try another encoding.
To parse the image you need to use an image parser. .NET has several as part of their GUI namespaces. In the sample below I'm using the one from System.Drawing (windows forms) but similar ones exists in WPF and there are many third party libraries out there.
using (var reader = new BinaryReader(File.Open(someFile, FileMode.Open))
{
// assuming your string is in plain ASCII encoding:
var myString = System.Text.Encoding.ASCII.GetString(reader.ReadBytes(30));
// The rest of the bytes is image data, use an image library to process it
var myImage = System.Drawing.Image.FromStream(reader.BaseStream);
}
Now MSDN has a caution about using the BaseStream in conjunction with BinaryReader but I believe in the above case you should be safe since you're not using the stream after the image. But keep an eye out for problems. If it fails, you can always read the bytes into a new byte[] and create a new MemoryStream from those bytes.
EDIT:
You indicated in your comment your string is EBCDIC which unfortunately means you cannot use any of the built in Encodings to decode it. A quick google search revealed a post by Jon Skeet on a EBCDIC .NET Encoding class that may get you started. It will essentially give you ebcdicEncoding.GetString(...);
You can use FileStream to open and read from the file. If you read the first 30 bytes into a buffer you can then convert that to a string using "string Encoding.ASCII.GetString(byte[] buffer, int offset, int length)".
I'm using BinaryWriter to write records to a file. The records are comprised of a class with the following property datatypes.
Int32,
Int16,
Byte[],
Null Character
To write each record, I call BinaryWriter.Write four times--one for each datatype. This works fine but I'd like to know if there's any way to just call the BinaryWriter.Write() method a single time using all of these datatypes. The reasoning for this is that another program is reading my binary file and will occasionally only read part of a record because it starts reading between my write calls. Unfortunately, I don't have control over the code to the other program else I would modify the way it reads.
Add a .ToBinary() method to your class that returns byte[].
public byte[] ToBinary()
{
byte[] result= new byte[number_of_bytes_you_need];
// fill buf
return result;
}
In your calling code (approximate as I haven't compiled this)
stream.BinaryWrite(myObj.toBinary());
You're still writing each value independently, but it cleans up the code a little.
Also, as sindre suggested, consider using the serialization, as it makes it incredibly easy to recreate your objects from the file in question, and requires less effort than writing the file as you're attempting to.
Sync: you can't depend on any of these solutions to fix your file sync issue. Even if you manage to reduce your binaryWrite() call to a single statement, not using serialization or the .ToBinary() method I've outlined, bytes are still written sequentially by the framework. This is a limitation of the physical structure of the disk. If you have control over the file format, add a record length field written before any of the record data. In the app that's reading the file, make sure that you have record_length bytes before attempting to process the next record from the file. While you're at it, put this in a database. If you don't have control over the file format, you're kind of out of luck.
In keeping with you writing to a BinaryWriter, I would have the object create a binary record using a second BinaryWriter that is then written to the BinaryWriter. So on your class you could have a method like this:
public void WriteTo(BinaryWriter writer)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(value1);
bw.Write(value2);
bw.Write(value3);
bw.Write(value4);
writer.Write(ms.ToArray());
}
This would create a single record with the same format as you're already writing to the main BinaryWriter, just it would build it all at once then write it as a byte array.
Create a class of the record and use the binary formatter:
FileStream fs = new FileStream("file.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, <insert instance of a class here>);
fs.Close();
I haven't done this myself so I'm not absolutely sure it would work, the class cannot contain any other data, that's for sure. If you have no luck with a class you could try a struct.
Edit:
Just came up with another possible solution, create a struct of your data and use the Buffer.BlockCopy function:
byte[] writeBuffer = new byte[sizeof(structure)];
structure[] strucPtr = new structure[1]; // must be an array, 1 element is enough though
strucPtr[0].item1 = 0213; // initialize all the members
// Copy the structure array into the byte array.
Buffer.BlockCopy(strucPtr, 0, writeBuffer, 0, writeBuffer.Length);
Now you can write the writeBuffer to file in one go.
Second edit:
I don't agree with the sync problems not beeing possible to solve. First of all, the data is written to the file in entire sectors, not one byte at a time. And the file is really not updated until you flush it, thus writing data and updating the file length. The best and safest thing to do is to open the file exclusively, write a record (or several), and close the file. That requires the reading applications to use a similiar manner to read the file (open ex, read, close), as well as handling "access denied" errors gracefully.
Anyhow, I'm quite sure this will perform better no matter what when your'e writing an entire record at a time.