I have source code available for a legacy Delphi application that creates/reads a binary file. I have to read that binary file in a C# application.
The code in Delphi is something like this :
fs := TFileStream.Create(dst,fmOpenRead);
try
while fs.Position<fs.Size do begin
fs.Read(sSomeVar,sizeof(dDateTime));
fs.Read(sSomeVar1,sizeof(sIntValue));
fs.Read(sSomeVar2,sizeof(sCardinalValue1));
fs.Read(sSomeVar3,sizeof(sStringValue));
....
It appears that I have read the entire file into a byte[] and then interpret number of bytes to correct data type(for e.g. integer, string, uint1)?
I couldn't find a c# example anywhere.
Thanks,
Related
Alright, so I basically want to read any file with a specific extension. Going through all the bytes and reading the file is basically easy, but what about getting the type of the next byte? For example:
while ((int)reader.BaseStream.Position != RecordSize * RecordsCount)
{
// How do I check what type is the next byte gonna be?
// Example:
// In every file, the first byte is always a uint:
uint id = reader.GetUInt32();
// However, now I need to check for the next byte's type:
// How do I check the next byte's type?
}
Bytes don't have a type. When data in some language type, such as a char or string or Long is converted to bytes and written to a file, there is no strict way to tell what the type was : all bytes look alike, a number from 0-255.
In order to know, and to convert back from bytes to structured language types, you need to know the format that the file was written in.
For example, you might know that the file was written as an ascii text file, and hence every byte represents one ascii character.
Or you might know that your file was written with the format {uint}{50 byte string}{linefeed}, where the first 2 bytes represent a uint, the next 50 a string, followed by a linefeed.
Because all bytes look the same, if you don't know the file format you can't read the file in a semantically correct way. For example, I might send you a file I created by writing out some ascii text, but I might tell you that the file is full of 2-byte uints. You would write a program to read those bytes as 2-byte uints and it would work : any 2 bytes can be interpreted as a uint. I could tell someone else that the same file was composed of 4-byte longs, and they could read it as 4-byte longs : any 4 bytes can be interpreted as a long. I could tell someone else the file was a 2 byte uint followed by 6 ascii characters. And so on.
Many types of files will have a defined format : for example, a Windows executable, or a Linux ELF binary.
You might be able to guess the types of the bytes in the file if you know something about the reason the file exists. But somehow you have to know, and then you interpret those bytes according to the file format description.
You might think "I'll write the bytes with a token describing them, so the reading program can know what each byte means". For example, a byte with a '1' might mean the next 2 bytes represent a uint, a byte with a '2' might mean the following byte tells the length of a string, and the bytes after that are the string, and so on. Sure, you can do that. But (a) the reading program still needs to understand that convention, so everything I said above is true (it's turtles all the way down), (b) that approach uses a lot of space to describe the file, and (c) The reading program needs to know how to interpret a dynamically described file, which is only useful in certain circumstances and probably means there is a meta-meta format describing what the embedded meta-format means.
Long story short, all bytes look the same, and a reading program has to be told what those bytes represent before it can use them meaningfully.
I Know on VB we can read binary file using this code
Function GetMonData()
Dim Header(63) As Byte, Rows As Long, NoUse As Long
Dim i As Long, j As Long, TmpStr As String
Open "file.dat" For Binary As #1
Get #1, , Header
Get #1, , Rows
Get #1, , NoUse
Close #1
End Function
But how about method in c# ?
especially Get #1, , Header
I already try
string strFilePath = #"C:\file.dat";
FileStream stream = new FileStream(strFilePath, FileMode.Open);
BinaryReader b = new BinaryReader(File.Open(strFilePath, FileMode.Open));
I just confused to get data (63) byte for header , (4) byte for Rows, (4) byte for NoUse
in VB we can use Get #1, , Header, What about c# ? i need to Seek for the stream ?
Thanks in advanced
That is VB6/VBA code. The olden syntax is still supported in VB.NET, grudgingly, to permit porting programs. But surely you'll have to change the declarations from Long to Integer.
If you need to be able to read old files like this then the most obvious way to do it is to take advantage of .NET's excellent language interop and create a VB.NET class library that you reference in your C# project. By far the best way to ensure that the code is compatible and can deal with the weirdo semantics of Get().
Otherwise you'll have to use BinaryReader.GetBytes() to read Header, ReadInt32() to get the other ones.
I have a binary file written by VB6 application and now would like to use C# application to read the VB6 exported binary file. I have used the Microsoft.VisualBasic.dll into my C# project.
However there are some data inconsistency in C# application but I have check it in VB.net and it works nicely as well. (I convert from VB6 to VB.net, then VB.net to C#)
The screenshot represents the result from reading binary file by using C# and VB.Net application.
VB.Net is my expected result and now my C# application was showing inconsistency result
Both are double values in C# and VB.NET, and based on my observation, the int, string values looks fine.
In C# I was using statement shown as below, BinaryDetails is struct and inside have few double variables
ValueType DetailsValueType = (ValueType)BinaryDetails;
FileSystem.FileOpen(FileNumber, FileName, OpenMode.Binary, OpenAccess.Read);
FileSystem.FileGet(FileNumber, ref DetailsValueType);
I have change the data type in C# from double to float, still not my expected result:
You can reverse-engineer this kind of mishap with a little test program:
class Program {
static void Main(string[] args) {
var value1 = 3.49563395756763E-310;
var bytes1 = BitConverter.GetBytes(value1);
Console.WriteLine(BitConverter.ToString(bytes1));
var value2 = 101.325;
var bytes2 = BitConverter.GetBytes(value2);
Console.WriteLine(BitConverter.ToString(bytes2));
}
}
Output:
CC-CC-CC-54-59-40-00-00
CD-CC-CC-CC-CC-54-59-40
Note how you are definitely on the right track, you are reading correct byte values from the file. Those doubles have CC-54-59-40 in common. It is just that you read the data misaligned. You started reading too late, off by 2 bytes.
That's because your BinaryDetails is not an exact match with the data in the file. Do keep in mind that you have to assume the file contains VB6 data types. They are slightly different from C# types:
VB6 file data is tightly packed, you need [StructLayout(LayoutKind.Sequential, Pack = 1)]
A VB6 Integer is a C# short
A VB6 Long is a C# int
A VB6 Boolean is a C# short with -1 = True, 0 = False;
VB6 strings have a fixed width, you need to read them as byte[]
Ought to be enough to solve the problem. And of course keep in mind that it is very simple to use a VB.NET assembly from a C# program.
This question already has answers here:
C# - How do I read and write a binary file?
(4 answers)
Closed 9 years ago.
The application I'm attempting to create would read the binary code of any file and create a file with the exact same binary code, creating a copy.
While writing a program that reads a file and writes it somewhere else, I was running into encoding issues, so I hypothesize that reading as straight binary will overcome this.
The file being read into the application is important, as after I get this to work I will add additional functionality to search within or manipulate the file's data as it is read.
Update:
I'd like to thank everyone that took the time to answer, I now have a working solution. Wolfwyrd's answer was exactly what I needed.
BinaryReader will handle reading the file into a byte buffer. BinaryWriter will handle dumping those bytes back out to another file. Your code will be something like:
using (var binReader = new System.IO.BinaryReader(System.IO.File.OpenRead("PATHIN")))
using (var binWriter = new System.IO.BinaryWriter(System.IO.File.OpenWrite("PATHOUT")))
{
byte[] buffer = new byte[512];
while (binReader.Read(buffer, 0, 512) != 0)
{
binWriter.Write(buffer);
}
}
Here we cycle a buffer of 512 bytes and immediately write it out to the other file. You would need to choose sensible sizes for your own buffer (there's nothing stopping you reading the entire file if it's reasonably sized). As you mentioned doing pattern matching you will need to consider the case where a pattern overlaps a buffered read if you do not load the whole file into a single byte array.
This SO Question has more details on best practices on reading large files.
Look at MemoryStream and BinaryReader/BinaryWriter:
http://www.dotnetperls.com/memorystream
http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx
http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx
Have a look at using BinaryReader Class
Reads primitive data types as binary values in a specific encoding.
and maybe BinaryReader.ReadBytes Method
Reads the specified number of bytes from the current stream into a
byte array and advances the current position by that number of bytes.
also BinaryWriter Class
Writes primitive types in binary to a stream and supports writing
strings in a specific encoding.
Another good example C# - Copying Binary Files
for instance, one char at a time.
using (BinaryReader writer = new BinaryWrite(File.OpenWrite("target"))
{
using (BinaryReader reader = new BinaryReader(File.OpenRead("source"))
{
var nextChar = reader.Read();
while (nextChar != -1)
{
writer.Write(Convert.ToChar(nextChar));
nextChar = reader.Read();
}
}
}
The application I'm attempting to create would read the binary code of any file and create a file with the exact same binary code, creating a copy.
Is this for academic purposes? Or do you actually just want to copy a file?
If the latter, you'll want to just use the System.IO.File.Copy method.
I have a byte[] array and want to write it to stdout: Console.Out.Write(arr2str(arr)). How to convert byte[] to string, so that app.exe > arr.txt does the expected thing? I just want to save the array to a file using a pipe, but encodings mess things up.
I'd later want to read that byte array from stdin: app.exe < arr.txt and get the same thing.
How can I do these two things: write and read byte arrays to/from stdin/stdout?
EDIT:
I'm reading with string s = Console.In.ReadToEnd(), and then System.Text.Encoding.Default.GetBytes(s). I'm converting from array to string with System.Text.Encoding.Default.GetString(bytes), but this doesn't work when used with <,>. By "doesn't work" I mean that writing and reading over a pipe does not return the same thing.
To work with binary files you want Console.OpenStandardInput() to retrieve a Stream that you can read from. This has been covered in other threads here at SO, this one for example: Read binary data from Console.In
If you are writing to Console.WriteLine you need to encode the text in to a printable format. If you want to output to a file as a binary you can't use Console.WriteLine
If you still need to output to the console you either need to open the raw stream with Console.OpenStandardOutput() or call Convert.ToBase64String to turn the byte array to a string. There is also Convert.FromBase64String to come back from base64 to a byte array.