Move binary data until specific values from one file to another - vb.net

I writing a Visual Basic app and stuck at one point:
I need that app read the file, select everything before DDS string, cut it from file and paste to new file.
Then after edit a DDS insert that header.
Problem is, this header before DDS have not fixed length: every file of this type have different header. I tried to mess with System.IO.FileStream but got no result.
Is this even possible to do?

The header length is not that much, a simple search pattern is probably enough.
Pass the sequence of Bytes to find inside the File and the File path to the FindHeader method.
It returns a byte array containing all the bytes collected before the specified sequence is found.
This is a simple patter matching that seeks forward until it finds the first byte that can match the specified sequence.
It then reads a buffer and compares the buffer with the sequence:
- if it's a match, returns the bytes accumulated until that point;
- if it's not, it backtracks from the current position of a [Sequence Length] - 1 positions (inside the current Stream buffer) and continues.
You can call it like this:
Dim closeSequence = New Byte() { &H44, &H44, &H53 }
Dim headerBytes = FindHeader([Source File 1 Path], closeSequence)
Now we have the Header of the first source file.
The data section of the second source file is then:
Dim sourceFile2DataStart = FindHeader([Source File 2 Path], closeSequence).Length + closeSequence.Length
Dim dataLength = New FileInfo([Source File 2 Path]).Length - sourceFile2DataStart
We need to create a third file which will contain the Header of the fist file and the data read from the second file.
' Create a read buffer. The buffer length is less than or equal to the data length
Dim bufferLength As Integer = CInt(If(dataLength >= 1024, 1024, dataLength))
Dim buffer As Byte() = New Byte(bufferLength - 1) {}
Dim read As Integer = 0
Using two FileStream objects, we create a new Destination File, write the header of the first Source File, the closeSequence that identifies the start of the data section, then we read a buffer from the second Source File and write the buffer to the Destination File:
Dim patchworkFilePath as string = [Path of the Destination File]
Using sWriter As FileStream = New FileStream(patchworkFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None),
sReader As FileStream = New FileStream([Source File 2 Path], FileMode.Open, FileAccess.Read, FileShare.None)
sReader.Seek(sourceFile2DataStart, SeekOrigin.Begin)
sWriter.Write(header1Bytes, 0, header1Bytes.Length)
sWriter.Write(closeSequence, 0, closeSequence.Length)
While True
read = sReader.Read(buffer, 0, buffer.Length)
If read = 0 Then Exit While
sWriter.Write(buffer, 0, read)
End While
End Using
The Header reader method:
Public Function FindHeader(filePath As String, headerClosure As Byte()) As Byte()
Dim byteToFind = headerClosure(0)
Dim buffer = New Byte(headerClosure.Length - 1) {}
Dim header = New List(Of Byte)(2048)
Dim read As Integer = 0
Using fs As FileStream = New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)
While fs.Position <= (fs.Length - headerClosure.Length)
read = fs.ReadByte()
If read = byteToFind Then
fs.Read(buffer, 1, buffer.Length - 1)
buffer(0) = CByte(read)
If buffer.SequenceEqual(headerClosure) Then Exit While
fs.Seek(-(buffer.Length - 1), SeekOrigin.Current)
End If
header.Add(CByte(read))
End While
End Using
Return header.ToArray()
End Function

Related

No working append byte array to existing file using visual Basic

I have two strings, each string is a PDF etiquette, I must to write this two etiquette into a PDF file. To do this I convert a each string to a byte array (I don't know if this is the best way) and each I Write into a PDF file. When I write one etiquette into PDF file all is good, I see the etiquette, but then I try to appending the second, the result is the same, into the file is only the first etiquette. For example this code write first etiquette and all working good:
Dim fs As FileStream = New FileStream(fullFileName, FileMode.CreateNew)
fs.Close()
fs = New FileStream(fullFileName, FileMode.Append)
Dim str As String = GetPDFString(27)
Dim binaryData As Byte() = ConvertStringToByte(str)
fs.Write(binaryData, 0, binaryData.Length)
fs.Close()
but if I want to append the second etiquette in the same PDF file using this code ... this not appending.
Dim fs As FileStream = New FileStream(fullFileName, FileMode.CreateNew)
fs.Close()
fs = New FileStream(fullFileName, FileMode.Append)
Dim str As String = GetPDFString(25)
Dim str1 As String = GetPDFString(27)
Dim binaryData As Byte() = ConvertStringToByte(str)
Dim binaryData1 As Byte() = ConvertStringToByte(str1)
fs.Write(binaryData, 0, binaryData.Length)
fs.Write(binaryData1, 0, binaryData1.Length)
fs.Close()
both have the same result, and I don't understand why the second etiquette isn't appending? Thank you a lot.
Your question title suggests that you are asking about how to append a byte to a FileStream, not about PDF, and not about Base64 string conversion (which you are using in your code).
Before asking a question on StackOverflow, you need to ensure you are conveying only one problem at a time. Remove everything that is not relevant, and prepare a code sample we can use in a brand new VS project, in order to reproduce your problem and help you solve it.
Now, if your question is really about appending a byte (or a byte array) to a file, it's as simple as one line of code (or two, if you keep FileStream approach). See below link:
C# Append byte array to existing file
Also copy-pasted for your convenience here (and converted from C# to VB.NET):
Dim appendMe As Byte() = New Byte(999) {}
File.AppendAllBytes("C:\test.exe", appendMe)
Or, to avoid memory overflow, if your byte array is expected to be large enough:
Public Shared Sub AppendAllBytes(path As String, bytes As Byte())
'argument-checking here.
Using stream = New FileStream(path, FileMode.Append)
stream.Write(bytes, 0, bytes.Length)
End Using
End Sub
With this line:
fs.Write(binaryData1, binaryData.Length + 1, binaryData1.Length)
Specifically the second argument (binaryData.Length + 1), you're telling it to start appending from the wrong position of binaryData1. If it's 3 bytes long, for example, and so is binaryData, it won't append anything. It should be similar to the first .Write line:
fs.Write(binaryData1, 0, binaryData1.Length)
So it appends all of binaryData1. It will still append it after binaryData - you don't need to specify the length of the preceeding binaryData in this line.
Alternatively, bypassing the above entirely, concatenate your two strings before encoding/writing them to the file:
Dim fs As FileStream = New FileStream(fullFileName, FileMode.CreateNew)
fs.Close()
fs = New FileStream(fullFileName, FileMode.Append)
Dim str As String = GetPDFString(id, token, depot, 25)
Dim str1 As String = GetPDFString(id, token, depot, 27)
Dim binaryData As Byte() = Convert.FromBase64String(str & str1) 'concatenate strings
fs.Write(binaryData, 0, binaryData.Length)
fs.Close()

Reading a filestream issue

I am trying to read a file from my computer and output its contents into a literal control. It gives the error : Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. This is my first time using FileStream and I'm not 100% about all of the syntax for VB, or if there's even a community-preferred way of reading from a file, but could somebody help me out with this error?
This is the code:
Using fs As New FileStream(_path, FileMode.Open, FileAccess.Read)
Try
Dim fileLength As Integer = CInt(fs.Length)
Dim buffer() As Byte = New Byte() {fileLength}
Dim count As Integer
Dim sum As Integer = 0
While ((count = fs.Read(buffer, sum, fileLength - sum)) > 0)
sum = sum + count
End While
litOutput.Text = buffer.ToString()
Catch ex As Exception
'TODO: log error
End Try
End Using
This line is wrong
Dim buffer() As Byte = New Byte() {fileLength}
It declares an array of 1 byte in which you try to store the length of your file. Probably you have Option Strict set to Off and thus you could go away without noticing immediately the problem.
Of course, if your file is of a reasonable length and it is a simple textfile then there is no need for this loop. Just use File.ReadAllText or File.ReadLines or File.ReadAllLines, and by the way, your code read all your data in a single call because the last parameter of FileStream.Read is the quantity of bytes to read from file and the expression fileLength - sum produces a request to read all the bytes in a single call
Instead if you want to read your file in chunks of certain sizes then
probably you need
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Try
Dim chunkSize = 2000
Dim fileLength As Integer = CInt(fs.Length)
Dim buffer(fileLength) as Byte
Dim blockSize(chunkSize) as Byte
Dim count As Integer = -1
Dim pos As Integer = 0
While count <> 0
count = fs.Read(blockSize, 0, chunkSize-1)
Array.Copy(blockSize, 0, buffer, pos, count)
pos += count
End While
litOutput.Text = Encoding.UTF8.GetString(buffer)
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Using
Notice that this code assumes that your file is a Text file with UTF8 encoding.
It this is not the case then you could try with Encoding.ASCII.GetString or Encoding.Unicode.GetString

Can we read dbisam .dat files through vb.net

I am using a 3rd party account software which uses a dbisam database and have tables with .dat extension.
is there any way to read dbisam tables in vb.net?
I am getting quite difficult to read dbisam in visual basic, is there any guide of tip available, please provide your input.
Here is the code I tried but nothing is working
Dim contents As New StringBuilder()
Dim enc As Encoding = New ASCIIEncoding()
'flDatFile is the source of .dat file
Using fStream As FileStream = New FileStream(flDatFile, FileMode.Open, FileAccess.Read)
' The maximum bytes to read.
Dim toRead As Int32 = 1024000 ' 1Kb
' The buffer for read bytes.
Dim buffer(toRead - 1) As Byte
' The number of bytes that have been read.
Dim read As Int32 = fStream.Read(buffer, 0, toRead)
' While there is any data that has been read
Do While read > 0
' Get the string from the byte array.
MsgBox(enc.GetString(buffer, 0, read))
' Read next batch of data into the buffer.
read = fStream.Read(buffer, 0, toRead)
Loop
fStream.Close()
End Using

MongoDB C# How to Update GridFS File and metadata?

Need a solution to to see if the grid file exist and then update the file with metadata.
I am using the solution below. but want a better one.
Don't mind having separate Update and Delete methods.
Thanks
Public Class storedXYZ
Property Data As Stream
Property MetaData As storedXYZMetaData
End Class
Public Sub SaveStoredXYZ(storedXYZ As StoredXYZ)
Dim MongoGridFSCreateOptions As New MongoDB.Driver.GridFS.MongoGridFSCreateOptions
Dim qry As IMongoQuery
qry = Query.EQ("metadata.StoredXYZId", BsonValue.Create(storedXYZ.MetaData.StoredXYZ.ToString()))
Dim gridFile As MongoGridFSFileInfo = mdbGridFS.FindOne(qry)
If gridFile IsNot Nothing Then
Dim mongoStream As MongoGridFSStream
MongoGridFSCreateOptions.Metadata = storedXYZ.MetaData.ToBsonDocument
mongoStream = gridFile.OpenWrite()
''Convert MongoStream to MemoryStream
Dim fs As Stream = New MemoryStream()
Dim buffer As Byte() = New Byte(9999) {}
Dim bytesRead As Integer = 0
Do
bytesRead = storedXYZ.Data.Read(buffer, 0, buffer.Length)
mongoStream.Write(buffer, 0, bytesRead)
Loop While bytesRead > 0
mongoStream.Seek(0, SeekOrigin.Begin)
mongoStream.Position = 0
mdbGridFS.SetMetadata(gridFile, storedAXYZ.MetaData.ToBsonDocument)
Else
MongoGridFSCreateOptions.Metadata = storedXYZ.MetaData.ToBsonDocument
Dim fileinfo As MongoGridFSFileInfo
fileinfo = mdbGridFS.Upload(storedXYZ.Data, storedXYZ.MetaData.Name, MongoGridFSCreateOptions)
End If
End Sub
Rather than trying to overwrite the current file why not just fire off a delete command and then re-upload the file and update the document to the old ones Id?
MongoGridFS Upload method gets a new version of the file when you upload a file using an existing file name.
Using OpenWrite with an existing file name updates the file in place. The C# driver is the only driver that allows to update a GridFS file in place.
More information here
You can use fs.files and fs.chnuks collections as any other collection but you have to be careful to keep important for GridFS data untouched.

Reading a part of a txt file in VB.NET

I need to read a txt file part by part...
For example, in a txt file: (age,5char_name)
17susan23wilma25fredy
I need to read firstly 17susan. In other words, the first seven characters and after 23wilma and 25fredy, but I'm not reading the whole file and substring the file record. Is there a way to do this via streamreader?
Records are always seven bytes... 2 bytes for age, 5 bytes for name and all records in a line. There is no jump into the next line.
I think there is the solution:
Dim filestream As New FileStream("\records.txt", FileMode.Open)
Dim streamreader As New StreamReader(fs)
Dim buffer(7) As Char
bw.ReadBlock(buffer, 0, 7)
Console.WriteLine(buffer)
this is read first 7.. you can read other via loop or for..
If you ALWAYS want to use the first 7 characters, you can simply use Visual Basic line of code like:
Dim Result as String = Microsoft.VisualBasic.Left(string, no)
String is the StreamReader line from which you want to read only first seven characters.
No is any integer value and it is equal to the number of characters you want to read, in this case 7.
Also, in the same way, you can use Right and Mid to select a string from the right or somewhere in the middle.
Assuming a static number of characters per record (seven in your description), you could use a FileStream reader instead, and use the Read method to retrieve seven chars at a time.
For example:
Const chunkSize As Integer = 7
Using inputFile = File.OpenRead("namefile.txt")
Dim bytesRead As Integer
Dim buffer = New Byte(chunkSize - 1) {}
bytesRead = inputFile.Read(buffer, 0, buffer.Length)
while bytesRead = 7
'Process the buffer here
bytesRead = inputFile.Read(buffer, 0, buffer.Length)
End While
End Using
(code isn't tested, but should be close)