从固定长度文件中读取数据到类对象中 [英] Reading data from Fixed Length File into class objects
问题描述
我有一个固定长度的文件,想将其数据读入类对象.这些对象将进一步用于在数据库中插入/更新数据.尽管可以使用StreamReader完成,但我正在寻找更高级的解决方案. FileHelper是另一个解决方案,但我不想在程序中使用开放源代码.还有其他选择吗?
I have a fixed length file and would like to read its data into class objects. These objects will be further used to insert/update data in Database. Although it can be done with StreamReader, I am looking for a more sophisticated solution. FileHelper is another solution but I do not want to use an open source code in my program. Is there any other option?
在下面的链接中,一个用户回答了类似的问题,但未详细说明:
In the below link, one user has answered this similar question but it is not elaborated:
https://codereview.stackexchange.com /questions/27782/如何在网中读取固定宽度的数据字段
我尝试实现此功能,但是找不到Layout()属性.
I tried to implement this but I am unable to find Layout() Attribute.
谢谢.
样本定长文件:
aCSTDCECHEUR20140701201409161109 //Header of the file
b0000000000050115844085700800422HB HERBOXAN-COMPACT WHITE 12,5L 0000002297P0000000184L0000000000 0000000000
zCSTDCECH201409161109 148 //Footer of the file
推荐答案
我不知道您的数据如何序列化(您未指定任何协议或数据描述);但是您说过,为其他问题精心设计解决方案将解决您的问题.我对此进行详细说明:您很容易更改实现,以便根据您的格式解析数据(而不是像下面的示例中那样使用二进制流).
I don't know how your data was serialized (you are not specifying any protocol nor data description); however you said that an elaboration of solution for the other question would solve your issue. I'm giving you an elaboration for that: it will be easy for you to change my implementation so that data will be parsed according to your format (instead of using a binary stream, as I did in the following example).
我认为,在您提到的问题中,他们建议实施自己的属性以获取解决方案.
I think that in the question you are referring to, they were suggesting to implement their own attributes in order to obtain the solution.
我可以在此处给出一个实现示例(仅是一个示例,请在生产前对其进行编辑...):
I can give an example of implementation here (it's just an example, edit it before production use...):
包含您的数据结构的文件:
File containing your data structure:
//MyData.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FixedLengthFileReader
{
class MyData
{
[Layout(0, 10)]
public string field1;
[Layout(10, 4)]
public int field2;
[Layout(14, 8)]
public double field3;
public override String ToString() {
return String.Format("String: {0}; int: {1}; double: {2}", field1, field2, field3);
}
}
}
属性:
// LayoutAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FixedLengthFileReader
{
[AttributeUsage(AttributeTargets.Field)]
class LayoutAttribute : Attribute
{
private int _index;
private int _length;
public int index
{
get { return _index; }
}
public int length
{
get { return _length; }
}
public LayoutAttribute(int index, int length)
{
this._index = index;
this._length = length;
}
}
}
阅读器实现示例:
//FixedLengthReader.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
namespace FixedLengthFileReader
{
class FixedLengthReader
{
private Stream stream;
private byte[] buffer;
public FixedLengthReader(Stream stream)
{
this.stream = stream;
this.buffer = new byte[4];
}
public void read<T>(T data)
{
foreach (FieldInfo fi in typeof(T).GetFields())
{
foreach (object attr in fi.GetCustomAttributes())
{
if (attr is LayoutAttribute)
{
LayoutAttribute la = (LayoutAttribute)attr;
stream.Seek(la.index, SeekOrigin.Begin);
if (buffer.Length < la.length) buffer = new byte[la.length];
stream.Read(buffer, 0, la.length);
if (fi.FieldType.Equals(typeof(int)))
{
fi.SetValue(data, BitConverter.ToInt32(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(bool)))
{
fi.SetValue(data, BitConverter.ToBoolean(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(string)))
{
// --- If string was written using UTF8 ---
byte[] tmp = new byte[la.length];
Array.Copy(buffer, tmp, tmp.Length);
fi.SetValue(data, System.Text.Encoding.UTF8.GetString(tmp));
// --- ALTERNATIVE: Chars were written to file ---
//char[] tmp = new char[la.length - 1];
//for (int i = 0; i < la.length; i++)
//{
// tmp[i] = BitConverter.ToChar(buffer, i * sizeof(char));
//}
//fi.SetValue(data, new string(tmp));
}
else if (fi.FieldType.Equals(typeof(double)))
{
fi.SetValue(data, BitConverter.ToDouble(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(short)))
{
fi.SetValue(data, BitConverter.ToInt16(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(long)))
{
fi.SetValue(data, BitConverter.ToInt64(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(float)))
{
fi.SetValue(data, BitConverter.ToSingle(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(ushort)))
{
fi.SetValue(data, BitConverter.ToUInt16(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(uint)))
{
fi.SetValue(data, BitConverter.ToUInt32(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(ulong)))
{
fi.SetValue(data, BitConverter.ToUInt64(buffer, 0));
}
}
}
}
}
}
}
最后是程序实现的示例(非常简单):
And finally an example of program implementation (very simple):
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace FixedLengthFileReader
{
class Program
{
static void Main(string[] args)
{
MyData md = new MyData();
Console.WriteLine(md);
Stream s = File.OpenRead("testFile.bin");
FixedLengthReader flr = new FixedLengthReader(s);
flr.read(md);
s.Close();
Console.WriteLine(md);
}
}
}
如果要针对示例二进制文件测试该代码,则可以使用以下十六进制代码创建文件:
If you want to test that code against an example binary file, you could create a file with the following hex code:
41 42 43 44 45 46 47 48 49 4A 01 00 00 00 00 00 00
00 00 00 E0 3F
哪个代表以下字节:
- 字符串ABCDEFGHIJ(10个字节)
- 整数1(4个字节)
- 0.5的两倍(8个字节)
(我使用XVI32创建了一个文件,添加了十六进制代码并将其保存为testFile.bin)
(I created a file using XVI32, adding that hex code and saving it as testFile.bin)
这篇关于从固定长度文件中读取数据到类对象中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!