UPDATED - I added 2 screen shots with 0.00 in the data and one with 1234.56 in the data
I am using an old VB6 set of code as 95% works to read a text file that gets converted and stored in MS SQL. The strings are all good however there are numbers mixed into the text binary file that I haven't figured out how to read. The original application the numbers are all currency however the hex dump of the numbers looks to be 4 byte numbers.
Either way I am not sure how to read the numbers into a local variable. Maybe I am not starting at the correct place in the data. In the example below I am starting at the <160>.
Here is a dump of the part of the binary file with 0.00 in the data:
Here is a dump of the part of the binary file with 1234.56 in the data:
Note the arrow point to where the data changed.
This is my last try but that doesnt work either.
Function ReadFloat(f As Integer, Optional ShowDB As Boolean = False) As String
On Error GoTo 0
Dim c As Single
Dim S(4) As Byte
Dim x As Integer
Dim flt As Single
Get f, , S
For x = 1 To 4
Debug.Print x & " " & S(x) & " " & Hex(S(x)); "='" & Chr(S(x)) & "'"
Next x
CopyMemory flt, S, 4
My initial inspection suggests that the bytes starting:
40 E2 01
are what you're looking for. These are stored little endian, so 01E240 is hex for 123456 in decimal. So my guess would be 32 bit integers (4 byte long type). You can test this by using -0.01 as a value, this should give:
... FF FF FF FF ...
in the file.
If you're only interested in reading just these values then you can read and discard the first x values. Something like:
Dim yDiscard(123) As Byte
...
Get #1, ,yDiscard
Or alternatively, just seek to the position first before reading:
Seek #1, 123
To work out what byte values to expect in general, I found the following to be useful. Just run the code in a module:
Sub main()
Dim lValue As Long
Dim cValue As Currency
Dim nValue As Single
Dim dValue As Double
Dim sValue As String
Dim vValue As Variant
lValue = 123456
cValue = 1234.56
nValue = 1234.56
dValue = 1234.56
sValue = "1234.56"
vValue = CDec(1234.56)
Open "c:\test1.bin" For Binary As 1
Open "c:\test2.bin" For Binary As 2
Open "c:\test3.bin" For Binary As 3
Open "c:\test4.bin" For Binary As 4
Open "c:\test5.bin" For Binary As 5
Open "c:\test6.bin" For Binary As 6
Put #1, , lValue
Put #2, , cValue
Put #3, , nValue
Put #4, , dValue
Put #5, , sValue
Put #6, , vValue
Close #1
Close #2
Close #3
Close #4
Close #5
Close #6
End Sub
You can then inspect each file in a hex editor (I use MadEdit but anything will do).
It's probably useful to also try simple values like 1.00, 2.00, 10.00, -1.00 and see how the bytes differ each time.
This may also be informative (fairly in depth):
http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c7495/How-Visual-Basic-6-Stores-Data.htm
And to actually answer the question, something like the following will read a 32 bit integer and convert to currency:
Function ReadAmount(iFileHandle As Integer, lFileBytePosition As Long) As Currency
Dim lValue As Long
Seek #iFileHandle, lFileBytePosition
Get #iFileHandle, , lValue
ReadAmount = CCur(lValue) / 100
End Function
There's no need for an intermediate byte array.
True floating point are bad when using currency, so actually your number is an integer with fixed point.
First : put them in an integer variable (type Long)
Second : divide by 100 to get back the decimal !
Straightforward method to convert it to single:
Dim S(4) As Byte 'your 4 bytes, like (1)=&H40, (2)=&HE2 (3)=&H01, (4)=&H00
Dim Buffer As Long
Buffer = S(4) * 16777116 Or S(3) * 65536 Or S(2) * 256 Or S(1)
Dim flt As Single
flt = Buffer / 100
Related
Following code of Visual Basic 6.0 - SP2 is giving Overflow error. Can somebody explain why?
Private Sub Form_Click()
Dim Qty as Long
Qty= 290 * 113 '' 112 is working fine
MsgBox Qty
End Sub
The type of an expression is determined by its members, not by the variable it is going to be stored in.
113 gets typed as Byte.
290 gets typed as Integer because it won't fit into a byte.
As the largest of the involved types is Integer, the entire expression 290 * 113 is typed as Integer. An Integer can contain at most 32767, which is less than 290 * 113.
It therefore overflows upon multiplication, before the result is stored into a Long variable.
Explicitly type at least one of the numbers as Long:
Qty = 290& * 113
My aims is to do the following
Convert UNIX Time (i.e. 1582818012) to HEX String (i.e. 5E57E2DC) - Solved
Convert HEX String to Byte Array (i.e. 5E57E2DC) to (i.e. &H5E, &H57, &HE2, &HDC) - Pending
How can I do the conversion?
So I this case the result will be something like below:
Dim oneByte() As Byte = {&H5E, &H57, &HE2, &HDC}
oneByte(0)= 5E
oneByte(1)= 57
etc...
Using a couple of standard methods
Dim ut As Integer = 1582818012
Dim uts As String = Convert.ToString(ut, 16)
'look at oneByte in hex
Dim oneByte() As Byte = BitConverter.GetBytes(ut).Reverse.ToArray
' (0) &H5E Byte
' (1) &H57 Byte
' (2) &HE2 Byte
' (3) &HDC Byte
I have tried to write a code for multiplying two double-digit integers like ab * cd using arrays and the preliminary multiplying method. However, when I compile my code and insert any input, the output is a wrong result. I traced my code and I got an appropriate result but in compiling is something different. for example i insert 9 9 9 9 which mean 99 * 99 in this code but the result is 1210 instead of 9801.
program main
! multiplication of two double-digit integer ! array method
implicit none
integer , parameter :: size=2
integer , dimension (size)::A
integer , dimension (size)::B
integer , dimension (size+1)::C
integer , dimension (size+2)::D
integer , dimension (size+2)::E
integer :: i=0,carry1=0,carry2=0,carry3=0
do i=1,size,1
read *,A(i)
end do
do i=1,size,1
read *,B(i)
end do
do i= 3,2,-1
C(i)=B(size)*A(i-1)+carry1
if (C(i)>9)then
C(i)=mod (C(i),10)
carry1 = C(i)/10
else
carry1=0
end if
end do
C(1)=carry1
D(4)=0
do i=3,2,-1
D(i)=B(size-1)*A(i-1)+carry2
if (D(i)>9)then
D(i)=mod (D(i),10)
carry2= D(i)/10
else
carry2=0
end if
end do
D(1)=carry2
do i=4,2,-1
E(i)=D(i)+C(i-1)+carry3
if (E(i)>9) then
E(i)=mod (E(i),10)
carry3=1
else
carry3=0
end if
end do
E(1)=D(1)+carry3
do i=4,1,-1
print*,E(i)
end do
end program main
I'm making a IS task. I have a flatfile column named SCB_ActualMIN with a data type string [DT_STR]. I also have a script component to convert the SCB_ActualMIN column to numeric data type. I have this code in my script component
If Not Row.SCBActualDTime_IsNull AndAlso
Not String.IsNullOrEmpty(Row.SCBActualDTime.Trim) Then
Dim dtDate As Date
If DateTime.TryParse(Row.SCBActualDTime.Trim, dtDate) Then
Row.OutPutColumn = dtDate
Else
'If column cannot be parsed
Row.OutPutColumn_IsNull = True
End If
Else
Row.OutPutColumn_IsNull = True
End If
'''''SCBActualDTime
If Not Row.SCBActualMIN_IsNull AndAlso
Not String.IsNullOrEmpty(Row.SCBActualMIN.Trim) Then
Dim MIN As Integer
If Int32.TryParse(Row.SCBActualMIN.Trim, MIN) Then
Row.OutPut2Column = MIN
Else
'If column cannot be parsed
Row.OutPut2Column_IsNull = True
End If
Else
Row.OutPut2Column_IsNull = True
End If
As you can see the conversion of string to datetime data type is successful. While using the same code for string to integer. The Int32.TryParse(Row.SCBActualMIN.Trim, MIN) always return false even I have the value 09764377211 in the line code. Also is there other way for me to avoid the repetition of code.
9764377211 is bigger than 2147483647 which is the maximum value that can be assigned to Int32
Try converting value to Int64 or Double instead of Int32
Dim MIN As Int64
If Int64.TryParse(Row.SCBActualMIN.Trim, MIN) Then
Row.OutPut2Column = MIN
Else
'If column cannot be parsed
Row.OutPut2Column_IsNull = True
End If
OR
Dim MIN As Double
If Double.TryParse(Row.SCBActualMIN.Trim, MIN) Then
Row.OutPut2Column = MIN
Else
'If column cannot be parsed
Row.OutPut2Column_IsNull = True
End If
You cannot avoid repetition because you have to check each column for null by using it is own _IsNull property. You can try minimizing code by creating functions.
First of all, like #Yahfoufi suggested the exception is thrown because the value "9764377211 is bigger than 2147483647 which is the maximum value that can be assigned to Int32..."
You can Read more in this MSDN article about Data Types and corresponding Maximum values.
Type Storage size Range
Int32 4 bytes -2,147,483,648 to 2,147,483,647
Int64 8 bytes Approximately -9.2E+18 to 9.2E+18
Double 8 bytes Approximate range is -1.79E+308 to 1.79E+308 with accuracy of about 15 digits. Can represent numbers as small as 1E-323.
Decimal 12 bytes Approximate range is -7.9E+28 to 7.9E+28 with accuracy of 28 digits. Can represent numbers as small as 1E-28.
...
You can assign this value to Int64 or Decimal or Double Data Types
Optimizing your code
In this case you cannot avoid the repetition of these parts of code because there are using independent properties that cannot be called dynamically:
Checking if Input Columns is Null or Empty
If Not Row.SCBActualMIN_IsNull AndAlso
Not String.IsNullOrEmpty(Row.SCBActualMIN.Trim) Then
Assigning Null to the output column if value cannot be parsed or input is Null or Empty
Row.OutPut2Column_IsNull = True
You can modify your code to minimize number of lines but i don't think it will improve the performance
For each Data Type declare one variable inside the RowProcessing Sub and make your code as the following:
Assuming that these 2 columns are containing dates
Dim dtDate As Date
If Not Row.SCBActualDTime_IsNull AndAlso
Not String.IsNullOrEmpty(Row.SCBActualDTime.Trim) AndAlso
DateTime.TryParse(Row.SCBActualDTime.Trim, dtDate)Then
Row.OutPutColumn = dtDate
Else
'If column cannot be parsed or it is null
Row.OutPutColumn_IsNull = True
End If
'Assuming that SCBActualMIN is a Date
If Not Row.SCBActualMIN_IsNull AndAlso
Not String.IsNullOrEmpty(Row.SCBActualMIN.Trim) AndAlso
DateTime.TryParse(Row.SCBActualMIN.Trim, dtDate)Then
Row.OutPut2Column = dtDate
Else
'If column cannot be parsed
Row.OutPut2Column_IsNull = True
End If
Having a large amount of lines of code is not an issue if performance is good or optimal, Also minimizing the number of lines of code will not necessary improve the performance
Useful Links on SSIS , SQL , .Net Data Types
https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
http://www.sqlservergeeks.com/sql-server-and-ssis-data-types/
https://learn.microsoft.com/en-us/sql/integration-services/extending-packages-custom-objects/data-flow/working-with-data-types-in-the-data-flow#mapping-data-types-in-the-data-flow
https://learn.microsoft.com/en-us/sql/integration-services/data-flow/integration-services-data-types
Ok... I guess my brain has finally gone on vacation without me today. I have extracted 2 fields from a website and I get this string
vData = "Amount Owed [EXTRACT]$125.00[EXTRACT]
vData was declared as an array (string).
I split vData on [EXTRACT] and I end up with 2 string variables like this:
varA = "Amount Owed"
varB = "$125.00"
To parse varB, I use
Dim varC as Currency
varC = val(varB)
I want to use varC in an If statement:
If Val(VarC) <> 0 Then
I was expecting varC to be 125 but when I look at varC is 0. I can't figure out why varC = 0 and not 125.
Use CCur(varB) instead of Val(varB). CCur converts to a Currency type, so knows about $ and other things.
Explanation from the MS docs:
... when you use CCur, different decimal separators, different thousand separators, and various currency options are properly recognized depending on the locale setting of your computer.
Val is only looking for straight numbers:
The Val function stops reading the string at the first character it can't recognize as part of a number. Symbols and characters that are often considered parts of numeric values, such as dollar signs and commas, are not recognized.