Checking is a specific byte in a file is set to a specific value in vb - vb.net

I want to be able to make is so that when my program loads it checks to see if the bytes in the file are set to something specific. If they are set to a certain byte then carry out the code.
So I want to be able to make it go to a specific byte, check if it's a certain byte and if it is that certain byte then carry out the code else if it is something else then carry out the other code.
I tried this:
Dim bytes As Byte() = New Byte(writeStream.Length) {}
Dim ByteResult As Integer = writeStream.Read(bytes, 30, 1)
MsgBox(ByteResult)
But it didn't work because for some reason it always returned 1.
I also tried this:
Dim dataArray(60) As Byte
If dataArray(30) <> writeStream.ReadByte() - 0 Then
MsgBox("The bytes have been checked.")
End If
But that didn't seem to work either because it never opened the message box for me.
For example, I want it to seek to offset 30 and then check if the byte is 00 then I want it to carry out code 1 and else if it is 01 I want it to carry out code2.
Thanks.

I found that the following code works:
fLocation = ("file.txt")
Dim writeStream As New FileStream(fLocation, FileMode.Open)
Dim writeBinary As New BinaryWriter(writeStream)
writeStream.Seek(30, SeekOrigin.Begin)
Dim ByteResult = writeStream.ReadByte()
MsgBox(ByteResult)

You can also do this
Dim FileStream1 As New IO.FileStream("File.txt", IO.FileMode.Open)
FileStream1.Position = 30
MsgBox(FileStream1.ReadByte)
FileStream1.Close()
FileStream1.Dispose()

Related

VB - BinaryWriter inserting junk characters

I'm trying to create an MP3 ID3v1 Tag editor in Visual Basic (2010)
I have no problem reading tags, however, I can't seem to update the tags correctly.
I use FileStream to open the file, and then I use BinaryWriter. I seek to right after the "TAG" header, which is 125 bytes from the end of file.
The first field is the Title field, which is 30 characters long.
So before writing the new tag, I would clear it by writing 30 spaces.
Then I seek back to the beginning, and try to write the new data. But it ends up overwriting data in the next field.
Dim file As New System.IO.FileStream(songpath, IO.FileMode.Open)
Dim bw As New System.IO.StreamWriter(file)
file.Seek(-125, IO.SeekOrigin.End)
bw.Write(" ")
file.Seek(-125, IO.SeekOrigin.End)
bw.Write(data(0))
bw.Close()
file.Close()
Here is a screen cap of the result. I attempted to write "Test" in the title field, I write the data and then reopen the file and this is what I get.
Rather than using file.Seek, I would set the .Position property, like this:
Imports System.IO
Imports System.Text
Module Module1
Sub Main()
Dim f = "C:\temp\sample.MP3"
Dim newTitle = "This is a test."
Dim dataLen = 30
Dim titleData(dataLen - 1) As Byte
Dim newTitleBytes = Encoding.ASCII.GetBytes(newTitle)
Array.Copy(newTitleBytes, titleData, Math.Min(dataLen, newTitleBytes.Length))
Using str As New FileStream(f, FileMode.Open, FileAccess.Write, FileShare.None)
Dim titlePosition = str.Length - 125
str.Position = titlePosition
str.Write(titleData, 0, dataLen)
End Using
End Sub
End Module
The unused portion of the title should be bytes with a value of zero - when you create an array its values are set to zero* for you. Then you can fill the start of the title bytes with the bytes which represent the string in ASCII. I suspect you could get away with using ISO-8859-1 if you need accented characters, but don't rely on that.
The Using construction makes sure that the file is closed afterwards even if something goes wrong.
* If it's an array of a numeric type, like Byte or Integer and so on.

Displaying the ASCII Table Number for each item in a byte array

I am writing a Message builder and in it I have to send a byte array to a remote machine requesting data.
I have an 8 bit number that counts how many items are being requested (count) and am trying to get the number inserted into a byte array.
The Byte array locations are in positions 70 & 71 of the array and in little endian order.
I am trying to just convert the byte and then insert the converted bytes with the following code.
Dim count As Byte = 3
Dim countbyteArray As Byte() = BitConverter.GetBytes(count)
sendBytes(70) = (countbyteArray(0))
sendBytes(71) = (countbyteArray(1))
when I do this for anything greater than 1 it does not get accepted by the device I am sending the byte array to.
Am I in the right ball Park or completely wrong as I am not completely up to speed with Bytes and Bits. Also any example or explanation would be greatly appreciated.
Little endian is the natural order in .NET so it is easy to work with.
As for a message builder, wouldn't it be easier to say
Dim message = New Message With { .Command = Command.Request, .Device = &hF, .Count = 8, .Filter = &h1234 }
Dim bytes = message.GetBytes()
' Hex for debugging
Dim hex = BitConverter.ToString(bytes)
You just have to layout the structure of the message. One way is with LayoutKind.Explicit. I'd probably choose the LayoutKind that most closely aligns with the device documentation.
Public Enum Command As Byte
Reset = 0
Request = 1
End Enum
<StructLayout(LayoutKind.Explicit)>
Public Structure Message
<FieldOffset(0)> Public Command As Command
<FieldOffset(1)> Public Device As Byte
' unused bytes default to 0
<FieldOffset(10)> Public Count As UInt16
<FieldOffset(12)> Public Filter As Int16
Public Function GetBytes() As Byte()
Dim rawData(0 To Marshal.SizeOf(Me) - 1) As Byte
Dim handle = GCHandle.Alloc(rawData, GCHandleType.Pinned)
Try
Dim rawDataPtr = handle.AddrOfPinnedObject()
Marshal.StructureToPtr(Me, rawDataPtr, False)
Return rawData
Finally
handle.Free()
End Try
End Function
End Structure
'TODO define enums, etc to make it easier for caller.
'TODO update struct per device documentation

Shortest way to get String from part of Bytes

I have read bytes from file and I have to get a String from known location.
Dim b() As Byte = File.ReadAllBytes("MYFILE.BIN")
Dim myYear As String = Encoding.ASCII.GetString(b)
That gives whole file in myYear String so I can extract a year from there.
Is there some handy and shortest way to get bytes from 50 to 54 and convert only that part to string?
Maybe something like the following. Its not shorter but you don't need to read the complete file into memory.
Using stream = File.OpenRead("c:\MYFILE.BIN")
stream.Seek(50, SeekOrigin.Begin)
Dim b = New Byte(4) {}
stream.Read(b, 0, 5)
Dim str = Encoding.ASCII.GetString(b)
End Using

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)

linq submitchanges runs out of memory

I have a database with about 180,000 records. I'm trying to attach a pdf file to each of those records. Each pdf is about 250 kb in size. However, after about a minute my program starts taking about about a GB of memory and I have to stop it. I tried doing it so the reference to each linq object is removed once it's updated but that doesn't seem to help. How can I make it clear the reference?
Thanks for your help
Private Sub uploadPDFs(ByVal args() As String)
Dim indexFiles = (From indexFile In dataContext.IndexFiles
Where indexFile.PDFContent = Nothing
Order By indexFile.PDFFolder).ToList
Dim currentDirectory As IO.DirectoryInfo
Dim currentFile As IO.FileInfo
Dim tempIndexFile As IndexFile
While indexFiles.Count > 0
tempIndexFile = indexFiles(0)
indexFiles = indexFiles.Skip(1).ToList
currentDirectory = 'I set the directory that I need
currentFile = 'I get the file that I need
writePDF(currentDirectory, currentFile, tempIndexFile)
End While
End Sub
Private Sub writePDF(ByVal directory As IO.DirectoryInfo, ByVal file As IO.FileInfo, ByVal indexFile As IndexFile)
Dim bytes() As Byte
bytes = getFileStream(file)
indexFile.PDFContent = bytes
dataContext.SubmitChanges()
counter += 1
If counter Mod 10 = 0 Then Console.WriteLine(" saved file " & file.Name & " at " & directory.Name)
End Sub
Private Function getFileStream(ByVal fileInfo As IO.FileInfo) As Byte()
Dim fileStream = fileInfo.OpenRead()
Dim bytesLength As Long = fileStream.Length
Dim bytes(bytesLength) As Byte
fileStream.Read(bytes, 0, bytesLength)
fileStream.Close()
Return bytes
End Function
I suggest you perform this in batches, using Take (before the call to ToList) to process a particular number of items at a time. Read (say) 10, set the PDFContent on all of them, call SubmitChanges, and then start again. (I'm not sure offhand whether you should start with a new DataContext at that point, but it might be cleanest to do so.)
As an aside, your code to read the contents of a file is broken in at least a couple of ways - but it would be simpler just to use File.ReadAllBytes in the first place.
Also, your way of handling the list gradually shrinking is really inefficient - after fetching 180,000 records, you're then building a new list with 179,999 records, then another with 179,998 records etc.
Does the DataContext have ObjectTrackingEnabled set to true (the default value)? If so, then it will try to keep a record of essentially all the data it touches, thus preventing the garbage collector from being able to collect any of it.
If so, you should be able to fix the situation by periodically disposing the DataContext and creating a new one, or turning object tracking off.
OK. To use the smallest amount of memory we have to update the datacontext in blocks. I've put a sample code below. Might have sytax errors since I'm using notepad to type it in.
Dim DB as YourDataContext = new YourDataContext
Dim BlockSize as integer = 25
Dim AllItems = DB.Items.Where(function(i) i.PDFfile.HasValue=False)
Dim count = 0
Dim tmpDB as YourDataContext = new YourDataContext
While (count < AllITems.Count)
Dim _item = tmpDB.Items.Single(function(i) i.recordID=AllItems.Item(count).recordID)
_item.PDF = GetPDF()
Count +=1
if count mod BlockSize = 0 or count = AllItems.Count then
tmpDB.SubmitChanges()
tmpDB = new YourDataContext
GC.Collect()
end if
End While
To Further optimise the speed you can get the recordID's into an array from allitems as an anonymous type, and set DelayLoading on for that PDF field.