Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Reading EBCDIC Files.

386 views
Skip to first unread message

jeff M via .NET 247

unread,
Jun 8, 2004, 2:13:58 PM6/8/04
to
I'm still having problems reading EBCDIC files. Currently it looks like the lower range (0 to 127) is working. I have tried the following code pages 20284, 20924, 1140, 37, 500 and 20127. By working I get the correct answer by taking the decimal value and using that as an index to an array that will map to the correct EBCDIC value in hex.

By larger values, an example would be "AA" in EBCDIC hex would give me the value of 63 in decimal (ASCII) when read from the file. My table would then map to "6F". I'm still not sure what is going wrong, so any help would be great.

Someone did post some help regarding a Microsoft page but I was unable to link it back to VB.net through the name spaces. The help was in VB6 and VB5.


Private Sub OpenAndProcessFile(ByVal sInputFileName As String)
Dim FileStream As System.IO.FileStream = New System.IO.FileStream(sInputFileName, _
IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
'Dim StreamIn As System.IO.StreamReader = New System.IO.StreamReader(FileStream, System.Text.Encoding.GetEncoding(1252))
Dim StreamIn As System.IO.StreamReader = New System.IO.StreamReader(FileStream, System.Text.Encoding.GetEncoding("ASCII"))
Dim tmp As Byte
Dim bHigh, bLow As Byte
Static first_time_through As Boolean = True
Dim count As Int16 = 0
While (StreamIn.Peek > -1) And (count <> -1)
count += 1
MsgBox(StreamIn.Peek)
tmp = ASCII_TO_EBCDIC(StreamIn.Read)
If (count = 1) And (tmp = &HC2) Then
While (count < 2048) And (StreamIn.Peek > -1)
tmp = StreamIn.Read
count += 1
End While
End If

Extract_Bits(tmp, bHigh, bLow, first_time_through)
If count = 10 Then
MTXDisplay.AppendText(Chr(13) + Chr(10))
ElseIf ((count - 10) Mod 252) = 0 Then
MTXDisplay.AppendText(Chr(13) + Chr(10))
ElseIf (count > 2049) Then
MTXDisplay.AppendText(Chr(13) + Chr(10))
count = 0
If (MsgBox("Continue", MsgBoxStyle.OKCancel) = MsgBoxResult.Cancel) Then
'check to continue at the end of each 2K block
count = -1
End If
End If
End While
StreamIn.Close()
FileStream.Close()
'Close()
End Sub

Private Sub Extract_Bits(ByVal ByteIn As Byte, ByRef bHigh As Byte, ByRef bLow As Byte, _
ByRef first_time_through As Boolean)
'ByteIn = ASCII_TO_EBCDIC(ByteIn)
bHigh = (ByteIn And &HF0) \ 16
bLow = (ByteIn And &HF)
If (first_time_through) Then
MTXDisplay.Text = Hex(bHigh) + Hex(bLow)
first_time_through = False
Else
MTXDisplay.AppendText(Hex(bHigh) + Hex(bLow))
End If
End Sub

Private Function ASCII_TO_EBCDIC(ByVal ByteIn As Byte) As Byte
Dim EBCDIC_Table() As Byte = {&H0, &H1, &H2, &H3, &H37, &H2D, &H2E, &H2F, &H16, &H5, &H15, _
&HB, &HC, &HD, &HE, &HF, &H10, &H11, &H12, &H13, &H3C, &H3D, _
&H32, &H26, &H18, &H19, &H3F, &H27, &H1C, &H1D, &H1E, &H1F, &H40, _
&H5A, &H7F, &H7B, &H5B, &H6C, &H50, &H7D, &H4D, &H5D, &H5C, &H4E, _
&H6B, &H60, &H4B, &H61, &HF0, &HF1, &HF2, &HF3, &HF4, &HF5, &HF6, _
&HF7, &HF8, &HF9, &H7A, &H5E, &H4C, &H7E, &H6E, &H6F, &H7C, &HC1, _
&HC2, &HC3, &HC4, &HC5, &HC6, &HC7, &HC8, &HC9, &HD1, &HD2, &HD3, _
&HD4, &HD5, &HD6, &HD7, &HD8, &HD9, &HE2, &HE3, &HE4, &HE5, &HE6, _
&HE7, &HE8, &HE9, &H8D, &HE0, &H9D, &H5F, &H6D, &H79, &H81, &H82, _
&H83, &H84, &H85, &H86, &H87, &H88, &H89, &H91, &H92, &H93, &H94, _
&H95, &H96, &H97, &H98, &H99, &HA2, &HA3, &HA4, &HA5, &HA6, &HA7, _
&HA8, &HA9, &HC0, &H4F, &HD0, &HA1, &H7, &H20, &H21, &H22, &H23, _
&H24, &H15, &H6, &H17, &H28, &H29, &H2A, &H2B, &H2C, &H9, &HA, _
&H1B, &H30, &H31, &H33, &H34, &H35, &H36, &H8, &H38, &H39, &H3A, _
&H3B, &H4, &H14, &H3E, &HE1, &H20, &H41, &H42, &H43, &H44, &H45, _
&H46, &H47, &H48, &H49, &H51, &H52, &H53, &H54, &H55, &H56, &H57, _
&H58, &H59, &H62, &H63, &H64, &H65, &H66, &H67, &H68, &H69, &H70, _
&H71, &H72, &H73, &H74, &H75, &H76, &H77, &H78, &H80, &H8A, &H8B, _
&H8C, &H8D, &H8E, &H8F, &H90, &H9A, &H9B, &H9C, &H9D, &H9E, &H9F, _
&HA0, &HAA, &HAB, &HAC, &HAD, &HAE, &HAF, &HB0, &HB1, &HB2, &HB3, _
&HB4, &HB5, &HB6, &HB7, &HB8, &HB9, &HBA, &HBB, &HBC, &HBD, &HBE, _
&HBF, &HCA, &HCB, &HCC, &HCD, &HCE, &HCF, &HDA, &HDB, &HDC, &HDD, _
&HDE, &HDF, &HEA, &HEB, &HEC, &HED, &HEE, &HEF, &HFA, &HFB, &HFC, _
&HFD, &HFE, &HFF}


ASCII_TO_EBCDIC = EBCDIC_Table(ByteIn)
End Function


--------------------------------
From: jeff M

-----------------------
Posted by a user from .NET 247 (http://www.dotnet247.com/)

<Id>tLPJdMVh30K+5IxRhsrpUA==</Id>

AlexS

unread,
Jun 8, 2004, 8:09:04 PM6/8/04
to
Hi, jeff

I think you have to consider that you need different tables for different
data types. For example, packed is not same as signed and not same as text.
Text is language dependent. When I did similar exercise I first detected
which data type must be decoded and only then used corresponding table.
That's why you can more or less decode only lower range, which is more
stable than higher one.

HTH
Alex

"jeff M via .NET 247" <anon...@dotnet247.com> wrote in message
news:elKAfRYT...@tk2msftngp13.phx.gbl...

Jay B. Harlow [MVP - Outlook]

unread,
Jun 8, 2004, 8:12:04 PM6/8/04
to
Jeff,
Is the EBCDIC file straight text or does it have packed or binary fields in
it? (you mentioned BCD in your other post which leads me to believe Packed
or binary Fields).

If you have straight text, the System.Text.Encoding class should do all the
work for you. If possible I would format the file as straight text on the
Mainframe.

If you have packed fields, I would recommend using a BinaryReader & not a
StreamReader. The BinaryReader will allow you to read the packed fields as
is, while you can then use a EBCDIC (code page 37 & 500)
System.Text.Encoding object to convert the text fields an array of EBCDIC
bytes to a String.

Remember that a String in .NET is always in Unicode. When you read or write
that string externally you can use System.Text.Encoding to translate it to &
from a specific encoding, such as EBCDIC. However with packed or binary
fields, you do not want automatic translation to take place, you only want
to translate

Following is a program that will convert an EBCDIC file to a ANSI file.

Option Strict On
Option Explicit On

Imports System.IO
Imports System.Text

Public Class EBCDICSample

Private Const EBCDICCodePage As Integer = 37 ' 37, 500

Public Shared Sub Main()
CopyToEBCDIC("EBCDICSample.vb", "EBCDICSample.ebcdic")
CopyToAnsi("EBCDICSample.ebcdic", "EBCDICSample.ansi")
End Sub

Private Shared Sub CopyToAnsi(ByVal inputPath As String, ByVal
outputPath As String)
Dim EBCDIC As Encoding = Encoding.GetEncoding(EBCDICCodePage)
Dim input As New StreamReader(inputPath, EBCDIC)
Dim output As New StreamWriter(outputPath, False, Encoding.Default)

Dim line As String

line = input.ReadLine()
Do Until line Is Nothing
output.WriteLine(line)
line = input.ReadLine()
Loop
input.Close()
output.Close()
End Sub

Private Shared Sub CopyToEBCDIC(ByVal inputPath As String, ByVal
outputPath As String)
Dim EBCDIC As Encoding = Encoding.GetEncoding(EBCDICCodePage)
Dim input As New StreamReader(inputPath, Encoding.Default)
Dim output As New StreamWriter(outputPath, False, EBCDIC)

Dim line As String

line = input.ReadLine()
Do Until line Is Nothing
output.WriteLine(line)
line = input.ReadLine()
Loop
input.Close()
output.Close()
End Sub

End Class

Hope this helps
Jay


"jeff M via .NET 247" <anon...@dotnet247.com> wrote in message
news:elKAfRYT...@tk2msftngp13.phx.gbl...

I'm still having problems reading EBCDIC files. Currently it looks like the
lower range (0 to 127) is working. I have tried the following code pages
20284, 20924, 1140, 37, 500 and 20127. By working I get the correct answer
by taking the decimal value and using that as an index to an array that will
map to the correct EBCDIC value in hex.

By larger values, an example would be "AA" in EBCDIC hex would give me the
value of 63 in decimal (ASCII) when read from the file. My table would then
map to "6F". I'm still not sure what is going wrong, so any help would be
great.

Someone did post some help regarding a Microsoft page but I was unable to
link it back to VB.net through the name spaces. The help was in VB6 and VB5.

<<snip>>


Jay B. Harlow [MVP - Outlook]

unread,
Jun 8, 2004, 9:37:04 PM6/8/04
to
Jeff,
In addition to my other comments:

> Currently it looks like the lower range (0 to 127)

> Dim StreamIn As System.IO.StreamReader = _
> New System.IO.StreamReader(FileStream, _
> System.Text.Encoding.GetEncoding("ASCII"))

Remember that ASCII has code points from 0 to 127. You could use ANSI, which
is 0 to 255, however you indicated that the file itself is EBCDIC, so you
should use an EBCDIC encoding (37 or 500) & the framework will translate the
EBCDIC text to Unicode for you. StreamIn.Read will always return an Unicode
character (-1 for end of file). StreamIn.Read will use the encoding object
to convert the code point in the file to this Unicode character.

Hope this helps
Jay

"jeff M via .NET 247" <anon...@dotnet247.com> wrote in message
news:elKAfRYT...@tk2msftngp13.phx.gbl...

Jeff

unread,
Jun 9, 2004, 1:02:04 PM6/9/04
to
My file contains Binary Coded Decimal only. So with that in mind I
started to look into the BinaryRead. I must admit, I'm getting very
close now but it's still not 100%. I tried using just StreamIn.Read
and assign the value to a Byte field. The problem was I would get the
odd overflow error so I started to convert the byte in to an integer
using ASC.

Thoughts?

Thanks for the help, my hairline appreciates it.
Jeff

Private Sub OpenAndProcessFile(ByVal sInputFileName As String)
Dim FileStream As System.IO.FileStream = New
System.IO.FileStream(sInputFileName, _
IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)

Dim StreamIn As BinaryReader = New BinaryReader(FileStream)
Dim FileOutStream As FileStream = New
FileStream("tmp_out.txt", FileMode.OpenOrCreate)
Dim StreamOut As StreamWriter = New
StreamWriter(FileOutStream)
Dim tmp As Int16


Dim bHigh, bLow As Byte
Static first_time_through As Boolean = True
Dim count As Int16 = 0

Dim block_count As Int16 = 0
While ((StreamIn.PeekChar > -1) And (count <> -1) And (count <
65000))
count += 1
tmp = ASCII_TO_EBCDIC(Asc(StreamIn.ReadChar))
Extract_Bits(tmp, bHigh, bLow, first_time_through)
StreamOut.Write(CStr(Hex(bHigh)) & CStr(Hex(bLow)))


If count = 10 Then

StreamOut.Write(CStr(Chr(12) & Chr(10)))


ElseIf ((count - 10) Mod 252) = 0 Then

StreamOut.Write(CStr(Chr(12) & Chr(10)))
ElseIf (count > 2049) Then
StreamOut.Write(CStr(Chr(12) & Chr(10)))
count = 0
block_count += 1
If (block_count > 19) Then


If (MsgBox("Continue", MsgBoxStyle.OKCancel) =
MsgBoxResult.Cancel) Then
'check to continue at the end of each 2K block
count = -1
End If
End If
End If
End While
StreamIn.Close()
FileStream.Close()

StreamOut.Close()
FileOutStream.Close()

"Jay B. Harlow [MVP - Outlook]" <Jay_Har...@msn.com> wrote in message news:<#I5#IJcTE...@TK2MSFTNGP10.phx.gbl>...


> Jeff,
> In addition to my other comments:
> > Currently it looks like the lower range (0 to 127)
>
> > Dim StreamIn As System.IO.StreamReader = _
> > New System.IO.StreamReader(FileStream, _
> > System.Text.Encoding.GetEncoding("ASCII"))
>
> Remember that ASCII has code points from 0 to 127. You could use ANSI, which
> is 0 to 255, however you indicated that the file itself is EBCDIC, so you
> should use an EBCDIC encoding (37 or 500) & the framework will translate the
> EBCDIC text to Unicode for you. StreamIn.Read will always return an Unicode
> character (-1 for end of file). StreamIn.Read will use the encoding object
> to convert the code point in the file to this Unicode character.
>
> Hope this helps
> Jay
>

> ----Snip-------

Jay B. Harlow [MVP - Outlook]

unread,
Jun 9, 2004, 8:11:36 PM6/9/04
to
Jeff,

> My file contains Binary Coded Decimal only.
Please define "Binary Coded Decimal", as to me "Binary Coded Decimal" or BCD
is packed fields, where each digit of a number is half of a byte. So for
example the number 1234 is represented as three bytes. &H01, &H23, &H4F,
where the F represents a positive number.

In other words BCD is number formatting that does not really entail EBCDIC
or ASCII.

EBCDIC on the other hand is a character encoding, where each byte is a
single character for example the letter "A" is represented as a single byte
with a value of &HC1.

ASCII is also a character encoding, where each byte is a single character,
for example the letter "A" is represented as a single byte with a value of
&H41.

The Asc function & the StreamReaders are used to convert text from one
character encoding to another, they should not be used on BCD aka packed
fields. They should be used on EBCDIC, ASCII and Ansi text files.

So I think we need to back up and ask what are you attempting to do:
1. Read EBCDIC text in a file?
2. Read BCD (packed numbers) in a file?
3. Read both EBCDIC text & BCD (packed numbers) in a file?

4. What is the file format look like (COBOL copy book?)


For information on EBCDIC in .NET see:
http://www.yoda.arachsys.com/csharp/ebcdic/

For information on Unicode & ASCII in .NET see:
http://www.yoda.arachsys.com/csharp/ebcdic/

Hope this helps
Jay


"Jeff" <duck_t...@msn.com> wrote in message
news:8ddc3b39.04060...@posting.google.com...

Jeff

unread,
Jun 10, 2004, 7:55:16 AM6/10/04
to
I am trying to read a file that is all BCD. It's similar to packed
fields but not quite. Each number is half of a byte but the fields are
not signed. In COBOL you would use comp-3 to define a filed as packed
decimal and because of the sign you would need 4 character positions
to hold a value of 6 digits long (one have of the 4th is used because
of the sign). In BCD every half byte holds a numeric value. In your
example below, 1234 would be represented by &H12 &H34. The file is
broken apart by using the Hex values of the EBCDIC characters on the
MVS and extracting the High and Low bits.

This is the type of file I need to read and process in Windows.

I have downloaded the file using Binary in FTP and I can read the file
in "c" on a UNIX box with no problems. In "c" I read it into a
character filed and logical and the filed with 0xF0 or 0x0F and shift
bits. This is also my objective in Visual Basic :) I'm starting off
easy with this language and believe it or not I have learned allot in
the last few weeks.


"Jay B. Harlow [MVP - Outlook]" <Jay_Har...@msn.com> wrote in message news:<u$8LH#nTEHA...@TK2MSFTNGP12.phx.gbl>...

Cor Ligthert

unread,
Jun 10, 2004, 8:18:03 AM6/10/04
to
Hi Jeff,

Just a little thing, it has always been that when you have to convert files
from EBCDIC to ASCII, you should not go in the packed decimal part. That is
is not EBCDIC, that is IBM mainframe(360/370).

Better is as I thought already Jay stated to bring it back first to straight
EBCDIC and use when needed an extra byte for the plus or minus, which is as
well not standardized in EBCDIC.

Just a little thing

Cor


Jay B. Harlow [MVP - Outlook]

unread,
Jun 10, 2004, 9:40:38 AM6/10/04
to
Jeff,

> In your
> example below, 1234 would be represented by &H12 &H34. The file is
> broken apart by using the Hex values of the EBCDIC characters on the
> MVS and extracting the High and Low bits.
As I have attempted to state. If you only have BCD, then you do not have
EBCDIC characters, you have BCD digits. You have a file of Bytes or Binary.

When you FTP'ed the file, did you use binary mode? If you didn't you should
as this will avoid unnecessary converting your BCD digits to/from ANSI (the
bytes are binary, leave them binary!).

Stay away from Asc, AscW & StreamReaders! As they are attempting to convert
your binary into characters on you.

With C & C++ on Unix a byte and a char are largely treated as the same
thing, with in .NET a Byte is an 8 bit value, in your case this 8 bit value
has 2 digits in it. In .NET a Char is a 16 bit value. Which can be converted
to & from a Byte via an Encoding... One should only use an encoding to
convert a byte if the byte has an encoded character in it! (such as an
EBCDIC "A"). I would avoid encoding if your byte has binary data in it (such
as BCD, Packed Decimal, Integer, Single, Double) In other words .NET has a
clearer definition of Binary files (Stream & BinaryReader) and Text Files
(StreamReader). Note that a Binary file could actually have both Binary data
& Text data, which is where the BinaryReader is useful. Seeing as
BinaryReader has no real support of BCD I would not use it in this case,
BinaryReader is useful if I had Integer, Single and Double fields, along
with Strings, in a file & I wanted to read the different values, the
BinaryReader will read the Bytes in the file and return an Integer for me
(via BinaryReader.ReadInt32). In case you were wondering: BinaryReader using
System.BitConvert.ToInt32 to convert (reassembly really) the bytes in the
file to an Integer.

Now that we know what your input looks like, what do you want your output to
look like?

It appears to be hex digits as text separated by end of line, correct?

What is the significance of &HC2? In EBCDIC its the letter "B". I noticed
its missing in current versions..

Given you have Binary in and Text out I would use something like:

Dim input As New System.IO.FileStream(sInputFileName, _
IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)


Dim output As New StreamWriter(outputPath, False, Encoding.Default)

Dim value As Integer


Dim bHigh, bLow As Byte

Dim count As Integer = 0
Dim block_count As Integer = 0
value = input.ReadByte()
While ((value > -1) And (count <> -1) And (count < 65000))
count += 1
'bHigh = CByte((value >> 4) And &HFF)
'bLow = CByte(value And &HFF)
'output.Write(Hex(bHigh) & Hex(bLow))
output.Write(value.ToString("X2"))


If count = 10 Then

output.WriteLine()


ElseIf ((count - 10) Mod 252) = 0 Then

output.WriteLine()
ElseIf (count > 2049) Then
output.WriteLine()


count = 0
block_count += 1
If (block_count > 19) Then
If (MsgBox("Continue", MsgBoxStyle.OKCancel) =
MsgBoxResult.Cancel) Then
'check to continue at the end of each 2K block
count = -1
End If
End If
End If

value = input.ReadByte()
End While
input.Close()
output.Close()

Note that the follow lines are equivalent:

bHigh = CByte((value >> 4) And &HF)
bLow = CByte(value And &HF)
output.Write(Hex(bHigh) & Hex(bLow))

output.Write(value.ToString("X2"))


Hope this helps
Jay

"Jeff" <duck_t...@msn.com> wrote in message

news:8ddc3b39.04061...@posting.google.com...


> I am trying to read a file that is all BCD. It's similar to packed
> fields but not quite. Each number is half of a byte but the fields are
> not signed. In COBOL you would use comp-3 to define a filed as packed
> decimal and because of the sign you would need 4 character positions
> to hold a value of 6 digits long (one have of the 4th is used because
> of the sign). In BCD every half byte holds a numeric value. In your
> example below, 1234 would be represented by &H12 &H34. The file is
> broken apart by using the Hex values of the EBCDIC characters on the
> MVS and extracting the High and Low bits.
>
> This is the type of file I need to read and process in Windows.
>
> I have downloaded the file using Binary in FTP and I can read the file
> in "c" on a UNIX box with no problems. In "c" I read it into a
> character filed and logical and the filed with 0xF0 or 0x0F and shift
> bits. This is also my objective in Visual Basic :) I'm starting off
> easy with this language and believe it or not I have learned allot in
> the last few weeks.
>

<<snip>>


Jeff

unread,
Jun 11, 2004, 2:14:55 PM6/11/04
to
Reading the file in using filestream works. I missed the part in my
book where it said filestream could be used for binary files and kept
using binaryread and streamread.

Many Thanks for the help.

As a side note "C1" or "C2" etc are values that may be used in flag
indicators and are populated by the hardware. That's the reason I need
this level of detail.

0 new messages