I am using this little function to get the byte data from a file but sometimes I get errors maybe bad file or bad code or file in use?
Dim fs As System.IO.FileStream = New System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)
Dim br As System.IO.BinaryReader = New System.IO.BinaryReader(fs)
Dim data() As Byte = br.ReadBytes(CType(fs.Length, Integer))
br.Close()
fs.Close()
Return data
If it's a small enough file that you want all the bytes in memory in an array, the easiest way to do it is:
Dim data() as Byte = File.ReadAllBytes(filePath)
Related
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
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()
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
I am trying to Serialize an object to XML however my object is a generic list containing many records and causes the serializer to consume lots of memory. So I tried to serialize directly to a GZipStream with the following code:
Dim formatter As XmlSerializer = XmlSerializerFactory.GetSerializerForType(_type)
Using _ms As New MemoryStream()
Using gzStream As New GZipStream(_ms, CompressionMode.Compress, True)
_ms.Position = 0
formatter.Serialize(gzStream, obj)
_ms.Position = 0
gzStream.Flush()
gzStream.Close()
End Using
_ms.Position = 0
Dim decompressData() As Byte
Using gzStream As New GZipStream(_ms, CompressionMode.Decompress)
ReDim decompressData(9000 - 1) 'this number doesn't matter, the data in my test sample is small
Dim Len As Integer = gzStream.Read(decompressData, 0, decompressData.Length)
End Using
End Using
However I run into an InvalidDataException The magic number in GZip header is not correct. Make sure you are passing in a GZip stream. when trying to read the data into the decompressData array.
When I Serialize to a separate memory stream first and then compress that stream such as:
Dim formatter As XmlSerializer = XmlSerializerFactory.GetSerializerForType(_type)
Using _ms As New MemoryStream()
Dim uc_fileBytes() As Byte
Dim uc_len As Integer
Using _ms101 As New MemoryStream()
formatter.Serialize(_ms101, obj)
uc_fileBytes = _ms101.GetBuffer()
uc_len = _ms101.Length
End Using
Using gzStream As New GZipStream(_ms, CompressionMode.Compress, True)
_ms.Position = 0
gzStream.Write(uc_fileBytes, 0, uc_len)
gzStream.Flush()
gzStream.Close()
End Using
Dim decompressData() As Byte
Using gzStream As New GZipStream(_ms, CompressionMode.Decompress)
ReDim decompressData(9000 - 1)
Dim Len As Integer = gzStream.Read(decompressData, 0, decompressData.Length)
End Using
End Using
It works fine without error. But why does it fail when I serialize directly to the GZipStream?
The cause of the problem is because the GZipStream behaves differently (obviously) to the MemoryStream when writing to it. It doesn't handle paged writes very well.
i get the error in following code
Function ReadFile(ByVal sPath As String) As Byte
Dim data As Byte
data = Nothing
Dim fInfo As FileInfo
fInfo = New FileInfo(sPath)
Dim numBytes As Long
numBytes = fInfo.Length
Dim fStream As FileStream
fStream = New FileStream(sPath, FileMode.Open, FileAccess.Read)
Dim br As BinaryReader
br = New BinaryReader(fStream)
data = Convert.ToByte(br.ReadBytes(numBytes)) `getting error on this line`
Return data
End Function
The ReadBytes function returns a byte array which you are passing to the Convert.ToByte function which throws an exception at runtime because you cannot convert an array of multiple bytes to a single byte. Depending on what you are trying to accomplish the actions to fix the problem will vary.
You have defined ReadFile to return a single byte, as in Byte.
ReadBytes returns a byte array, as in Byte().
You cannot convert a Byte() to a Byte.
Byte(0) = Byte
Byte <> Byte()
Convert.ToByte takes an Object.
Visual Basic .NET with Option Strict Off will try to convert Byte(), the Object you are passing to Convert.ToByte, into a Byte by calling the System.IConvertible interface on Byte() array, which will throw an exception because an Array does not implement this interface.
From your function implementation, it is obvious that you want to return all bytes. Therefore, change ReadFile to return Byte() and remove the ToByte method call.