如何在解析字节数据出错的情况下继续循环
本文关键字:出错 情况下 继续 循环 数据 字节数 字节 | 更新日期: 2023-09-27 18:18:57
我的问题是这个的延续:(循环读取不同的数据类型&
我有一个原始字节流存储在一个文件(rawbytes.txt或bytes.data)中,我需要解析并输出到csv样式的文本文件。
原始字节的输入(当作为字符/long/int等读取时)看起来像这样:
A2401028475764B241102847576511001200C...
解析后应该是:
OutputA.txt
(Field1,Field2,Field3) - heading
A,240,1028475764
OutputB.txt
(Field1,Field2,Field3,Field4,Field5) - heading
B,241,1028475765,1100,1200
OutputC.txt
C,...//and so on
本质上,它是一个十六进制转储风格的字节输入,它是连续的,没有任何需要解析的行终止符或数据之间的空白。如上所示,数据由不同的数据类型一个接一个地组成。
这是我的代码片段-因为在任何字段内都没有逗号,也不需要使用"(即CSV包装器),我只是使用textwwriter来创建CSV风格的文本文件,如下所示:
if (File.Exists(fileName))
{
using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open)))
{
while (reader.BaseStream.Position != reader.BaseStream.Length)
{
inputCharIdentifier = reader.ReadChar();
switch (inputCharIdentifier)
case 'A':
field1 = reader.ReadUInt64();
field2 = reader.ReadUInt64();
field3 = reader.ReadChars(10);
string strtmp = new string(field3);
//and so on
using (TextWriter writer = File.AppendText("outputA.txt"))
{
writer.WriteLine(field1 + "," + field2 + "," + strtmp); // +
}
case 'B':
//code...
我的问题是基于这样一个事实,即一些原始字节数据包含空值,这很难解析-因为在连续的数据块(如果数据块没有损坏,每个数据块以A, b或C开头)之间存在未知的数量的空字节(或非空,不在位置的字节)。
问题那么,如何添加默认情况或其他机制来继续循环,尽管可能由于损坏或错误的数据而出现错误?下面的代码可以工作吗?
inputCharIdentifier = reader.ReadChar();
...
case default:
//I need to know what to add here, instead of default
//(i.e. the case when the character could not be read)
while (binReader.PeekChar() != -1)
{
filling = binReader.readByte();
//filling is a single byte
try {
fillingChar = Convert.ToChar(filling);
break;
}
catch (Exception ex) { break; }
if (fillingChar == 'A' || fillingChar == 'B')
break;
剩余的部分-添加代码到每个开关情况下(如'A')继续而不停止程序-有没有办法做到这一点,没有多个try-catch块?[即代码块字符标识符是A,但A之后的字节是损坏的-在这种情况下,我需要退出循环或读取(即跳过)一个定义的字节数-在这里,如果消息头正确识别剩余的字节,将知道。]
[注:情况A, B等有不同大小的输入-换句话说,A可能总共是40字节,而B是50字节。所以使用固定大小的缓冲区,比如inputBuf[1000],或者[50]——如果它们都是相同的大小——也不会很好地工作,AFAIK。
有什么建议吗?请帮助!我是c#新手(2个月)…
更新:我的全部代码如下:
class Program
{
const string fileName = "rawbytes.txt";
static void Main(string[] args)
{
try
{
var program = new Program();
program.Parser();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
public void Parser()
{
char inputCharIdentifier = 'Z';
//only because without initializing inputCharIdentifier I ended up with an error
//note that in the real code, 'Z' is not a switch-case alphabet
//it's an "inconsequential character", i.e. i have defined it to be 'Z'
//just to avoid that error, and to avoid leaving it as a null value
ulong field1common = 0;
ulong field2common = 0;
char[] charArray = new char[10];
char char1;
char char2;
char char3;
int valint1 = 0;
int valint2 = 0;
int valint3 = 0;
int valint4 = 0;
int valint5 = 0;
int valint6 = 0;
int valint7 = 0;
double valdouble;
/*
char[] filler = new char[53];
byte[] filling = new byte[4621];
byte[] unifiller = new byte[8];
//these values above were temporary measures to manually filter through
//null bytes - unacceptable for the final program
*/
if (File.Exists(fileName))
{
using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open)))
{
while (reader.BaseStream.Position != reader.BaseStream.Length)
{
//inputCharIdentifier = reader.ReadChar();
//if (inputCharIdentifier != null)
//{
try
{
inputCharIdentifier = reader.ReadChar();
try
{
switch (inputCharIdentifier)
{
case 'A':
field1common = reader.ReadUInt64();
field2common = reader.ReadUInt64();
//unifiller = reader.ReadBytes(8);
//charArray = reader.ReadString();
//result.ToString("o");
//Console.WriteLine(result.ToString());
charArray = reader.ReadChars(10);
string charArraystr = new string(charArray);
char1 = reader.ReadChar();
valint1 = reader.ReadInt32();
valint2 = reader.ReadInt32();
valint3 = reader.ReadInt32();
valint4 = reader.ReadInt32();
using (TextWriter writer = File.AppendText("A.txt"))
{
writer.WriteLine(field1common + "," + /*result.ToString("o")*/ field2common + "," + charArraystr + "," + char1 + "," + valint1 + "," + valint2 + "," + valint3 + "," + valint4);
writer.Close();
}
break;
case 'B':
case 'C':
field1common = reader.ReadUInt64();
field2common = reader.ReadUInt64();
//charArray = reader.ReadString();
charArray = reader.ReadChars(10);
string charArraystr2 = new string(charArray);
char1 = reader.ReadChar();
valint1 = reader.ReadInt32();
valint2 = reader.ReadInt32();
using (TextWriter writer = File.AppendText("C.txt"))
{
writer.WriteLine(field1common + "," + result2.ToString("o") + "," + charArraystr2 + "," + char1 + "," + valint1 + "," + valint2);
writer.Close();
}
break;
case 'S':
//market status message
field1common = reader.ReadUInt64();
char2 = reader.ReadChar();
char3 = reader.ReadChar();
break;
case 'L':
filling = reader.ReadBytes(4);
break;
case 'D':
case 'E':
field1common = reader.ReadUInt64();
field2common = reader.ReadUInt64();
//charArray = reader.ReadString();
charArray = reader.ReadChars(10);
string charArraystr3 = new string(charArray);
//char1 = reader.ReadChar();
valint1 = reader.ReadInt32();
valint2 = reader.ReadInt32();
valint5 = reader.ReadInt32();
valint7 = reader.ReadInt32();
valint6 = reader.ReadInt32();
valdouble = reader.ReadDouble();
using (TextWriter writer = File.AppendText("D.txt"))
{
writer.WriteLine(field1common + "," + result3.ToString("o") + "," + charArraystr3 + "," + valint1 + "," + valint2 + "," + valint5 + "," + valint7 + "," + valint6 + "," + valdouble);
writer.Close();
}
break;
}
}
catch (Exception ex)
{
Console.WriteLine("Parsing didn't work");
Console.WriteLine(ex.ToString());
break;
}
}
catch (Exception ex)
{
Console.WriteLine("Here's why the character read attempt didn't work");
Console.WriteLine(ex.ToString());
continue;
//continue;
}
//}
}
}
}
}
我收到的错误如下:
Here's why the character read attempt didn't work
System.ArgumentException: The output char buffer is too small to contain the decoded characters, encoding 'Unicode (UTF-8)' fallback 'System.Text.DecoderReplacementFallback'.
Parameter name: chars
at System.Text.Encoding.ThrowCharsOverflow()
at System.Text.Encoding.ThrowCharsOverflow(DecoderNLS decoder, Boolean nothingDecoded)
at System.Text.UTF8Encoding.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, DecoderNLS baseDecoder)
at System.Text.DecoderNLS.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, Boolean flush)
at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex, Boolean flush)
at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex)
at System.IO.BinaryReader.InternalReadOneChar()
at System.IO.BinaryReader.Read()
at System.IO.BinaryReader.ReadChar()
at line 69: i.e. inputCharIdentifier = reader.ReadChar();
更新:一个产生相同错误的示例文件在下面的链接:http://www.wikisend.com/download/106394/rawbytes.txt
特别注意连续数据块之间的8个意外空字节,即使数据块头-即inputCharIdentifier -是有效的。这种报头后面的字节数总是不可预测的,并且通常是变化的。我的问题是,当出现下一个可用的无损数据块时,我需要能够删除或跳过这种情况-在示例文件的情况下,在8个不合适的空字节之后发生的最后一个(单个)数据块。
8个空字节可以在文件中找到如下:字节计数器:1056第783列第2行(根据notepad++)
问题的关键在于8个空字节可以是任何大小- 3,7,15,50等。它总是未知的-作为数据损坏的直接结果。但与"传统"数据损坏不同,即在数据块中有固定数量的字节,例如50,可能是不可读的,因此可以跳过(通过确切的字节数)-我面临的数据损坏由有效数据块之间未知数量的字节组成。
由于目标变量(inputCharIdentifier)为空,因此无法为这些情况分配case;因此,有一个避免这些情况的条件就足够了。我还包括了一个尝试…Catch,只是为了完全确定(在执行所有给定操作时的任何错误都会使代码自动跳到下一个迭代)。
try
{
using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open), Encoding.ASCII))
{
while (reader.BaseStream.Position != reader.BaseStream.Length)
{
inputCharIdentifier = reader.ReadChar();
if(inputCharIdentifier != null)
{
switch (inputCharIdentifier)
case 'A':
field1 = reader.ReadUInt64();
field2 = reader.ReadUInt64();
field3 = reader.ReadChars(10);
string strtmp = new string(field3);
//and so on
using (TextWriter writer = File.AppendText("outputA.txt"))
{
writer.WriteLine(field1 + "," + field2 + "," + strtmp);
}
case 'B':
//code...
}
}
}
}
catch
{
}