Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何使用非标准代码页读取EBCDIC数据,而不弄乱数字?_.net_Encoding_Codepages_Ebcdic - Fatal编程技术网

.net 如何使用非标准代码页读取EBCDIC数据,而不弄乱数字?

.net 如何使用非标准代码页读取EBCDIC数据,而不弄乱数字?,.net,encoding,codepages,ebcdic,.net,Encoding,Codepages,Ebcdic,这是一个给老手的:——) 我正在从大型机DB2表读取二进制转储。该表有varchar、char、smallint、integer和float列。为了使其有趣,DB2使用代码页424(希伯来语)。我需要我的代码是代码页独立的 因此,我使用System.Text.Encoding使用streamreader打开文件,如下所示: Dim encoding As System.Text.Encoding = System.Text.Encoding.GetEncoding(20424) Dim sr A

这是一个给老手的:——)

我正在从大型机DB2表读取二进制转储。该表有varchar、char、smallint、integer和float列。为了使其有趣,DB2使用代码页424(希伯来语)。我需要我的代码是代码页独立的

因此,我使用System.Text.Encoding使用streamreader打开文件,如下所示:

Dim encoding As System.Text.Encoding = System.Text.Encoding.GetEncoding(20424)
Dim sr As New StreamReader(item.Key, encoding)
并继续使用将VARCHAR和CHAR数据根据其长度读入CHAR数组

sr.ReadBlock(buffer, 0, iFieldBufferSize)
始终记住VARCHAR列中的前2个字节应该被丢弃 并使用

SringValue = encoding.GetString(encoding.GetBytes(buffer))
一切都很好

但现在我转到SMALLINT列,我有麻烦了。有符号数字的值存储在2个字节中,因为它是大端,所以我需要

Dim buffer(iFieldBufferSize - 1) As Byte
buffer(1) = sr.Read ''switch the bytes around!
buffer(0) = sr.Read
Dim byteBuffer(iFieldBufferSize - 1) As Byte
Dim i16 As Int16 = BitConverter.ToUInt16(buffer, 0)
我打错电话了!例如,如果字节是00 03,我在缓冲区(1)中得到0,在缓冲区(0)中得到3-好。但当两个字节为0020时,我将128个字节读入缓冲区(0)

所以,在我做了半天的头发后,我从streamreader声明中删除了编码器,现在我将32个读数据放入缓冲区(0),就像它应该做的那样

底线是,非标准代码页编码器弄乱了字节读数


知道如何解决这个问题吗?

不要使用StreamReader来读取此文件。它将解释文件中的二进制数,就好像它们是字符一样,这会弄乱它们的值。使用文件流和二进制读取器。仅在从表示字符串的文件中翻译一组字节时使用Encoding.GetString()。

@Hans Passant是正确的。如果您正在读取包含二进制数据的文件(如您的描述所示),那么将文件当作文本来读取是不正确的

幸运的是,BinaryReader类包含一个构造函数,该构造函数将字符编码作为参数之一。您可以使用此选项将文件中的任何希伯来EBCDIC字符串自动转换为普通Unicode字符串,而不影响非文本(二进制)部分的解释

此外,您可能应该使用双字节VARCHAR length字段来读取字符串,而不是将其丢弃


ReadString()方法在这种情况下不起作用,因为该文件不是用.NET BinaryWriter类编码的。相反,您应该获取VARCHAR的长度(或CHAR字段的硬编码长度)并将其传递给ReadChars(int)方法。然后从返回的字符数组构造生成的字符串。

不能将EBCDIC文件转储之类的内容作为流读取。StreamReader类是文本阅读器的一种类型,用于读取字符。您正在读取一个记录——一个包含混合二进制和文本的复杂数据结构

您需要使用文件流进行读取,并根据需要读取八位字节块。您将需要一些简单的助手方法,如:

private byte[] ReadOctets( Stream input , int size )
{
    if ( size < 0 ) throw new ArgumentOutOfRangeException() ;

    byte[] octets      = new byte[size] ;
    int    octets_read = input.Read( octets , 0 , size ) ;

    if ( octets_read != size ) throw new InvalidDataException() ;

    return octets ;
}

public string readCharVarying( Stream input )
{
    short    size        = readShort( input ) ;

    return readCharFixed( input , size ) ;
}

public string readCharFixed( Stream input , int size )
{
    Encoding e           = System.Text.Encoding.GetEncoding(20424) ;
    byte[]   octets      = ReadOctets( input , size ) ;
    string   value       = e.GetString( octets ) ;

    return value ;
}

private short readShort( Stream input )
{
    byte[] octets            = ReadOctets(input,2) ;
    short  bigEndianValue    = BitConverter.ToInt16(octets,0) ;
    short  littleEndianValue = System.Net.IPAddress.NetworkToHostOrder( bigEndianValue ) ;

    return littleEndianValue ;
}

private int readInt( Stream input )
{
    byte[] octets            = ReadOctets(input,4) ;
    int    bigEndianValue    = BitConverter.ToInt32(octets,0) ;
    int    littleEndianValue = System.Net.IPAddress.NetworkToHostOrder( bigEndianValue ) ;

    return littleEndianValue ;
}

private long readLong( Stream input )
{
    byte[] octets            = ReadOctets(input,8) ;
    long   bigEndianValue    = BitConverter.ToInt64(octets,0) ;
    long   littleEndianValue = System.Net.IPAddress.NetworkToHostOrder( bigEndianValue ) ;

    return littleEndianValue ;
}
private byte[]ReadOctets(流输入,整数大小)
{
如果(大小<0)抛出新ArgumentOutOfRangeException();
字节[]八位字节=新字节[大小];
int-octets_-read=input.read(八位字节,0,大小);
如果(八位字节_read!=大小)抛出新的InvalidDataException();
返回八位组;
}
公共字符串readCharVariable(流输入)
{
短尺寸=读短(输入);
返回readCharFixed(输入,大小);
}
公共字符串readCharFixed(流输入,整数大小)
{
编码e=System.Text.Encoding.GetEncoding(20424);
字节[]八位字节=读取八位字节(输入,大小);
字符串值=e.GetString(八位字节);
返回值;
}
专用short readShort(流输入)
{
字节[]八位字节=读取八位字节(输入,2);
短bigEndianValue=位转换器.ToInt16(八位字节,0);
short littleEndianValue=System.Net.IPAddress.NetworkToHostOrder(bigEndianValue);
返回LittleEndian值;
}
私有int readInt(流输入)
{
字节[]八位字节=读取八位字节(输入,4);
int bigEndianValue=位转换器.ToInt32(八位字节,0);
int littleEndianValue=System.Net.IPAddress.NetworkToHostOrder(bigEndianValue);
返回LittleEndian值;
}
私有long readLong(流输入)
{
字节[]八位字节=读取八位字节(输入,8);
long bigEndianValue=位转换器.ToInt64(八位字节,0);
long littleEndianValue=System.Net.IPAddress.NetworkToHostOrder(bigEndianValue);
返回LittleEndian值;
}
IBM大型机的文件系统中通常有固定或可变长度的记录。固定长度很简单:您只需要知道记录长度,就可以在对read()方法的一次调用中读取记录的所有字节,然后根据需要转换片段

可变长度记录有点棘手,它们从4个八位记录描述符字开始,由2个八位(16位)逻辑记录长度组成,然后是一个2个八位(16位)0值。逻辑记录长度不包括4个八位字节的记录描述符字

您可能还会看到可变的、跨越的记录。这些记录类似于可变长度记录,不同之处在于4-octet前缀是段描述符字。前两个八位字节包含段长度,下一个八位字节标识段类型,最后一个八位字节为NUL(0x00)。段类型如下:

  • 0x00表示完整的逻辑记录
  • 0x01表示这是跨距记录的第一段
  • 0x10表示这是已跨越记录的最后一段
  • 0x11表示这是跨记录的“内部”段,即“除第一段或最后一段以外的多段记录段”
您可以将可变长度和可变跨距记录视为相同的记录。要读取其中一个,首先需要解析出段/记录/描述符字,并将完整记录读取/组装成一个by