110,549
社区成员
发帖
与我相关
我的任务
分享
public static byte[] ConvertStringToBytes(string tempStr, int limitLength)
{
byte[] result = null;
byte[] tempBytes = UTF8Encoding.GetEncoding("gb2312").GetBytes(tempStr.Trim());//gb2312
if (tempBytes.Length == limitLength)
{
result = tempBytes;
}
else if (tempBytes.Length > limitLength)
{
for (int i = 0; i < limitLength; i++)
{
result[i] = tempBytes[i];
}
}
else if (tempBytes.Length < limitLength)
{
result = new byte[limitLength];
for (int i = 0; i < tempBytes.Length; i++)
{
result[i] = tempBytes[i];
}
} return result;
}
/// <summary>
/// 保存DBF文件
/// </summary>
/// <param name="filepath">DBF文件保存路径</param>
/// <param name="dataGridView">表格对象</param>
private void WriteDBFFile(string filepath, DataGridView dataGridView)
{
try
{
int rowCount = dataGridView.RowCount;
int columnCount = dataGridView.ColumnCount;
if (rowCount > 0 && columnCount > 0)
{
FileStream fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fs);
byte tempByte;
byte[] tempBytes;
int i, j, tempInt; int[] fieldLength = new int[columnCount];
int tempMax = 0;
for (i = 0; i < columnCount; i++)
{
tempMax = 0;
for (j = 0; j < rowCount; j++)
{
//if (dataGridView[i, j].Value != null && dataGridView[i, j].Value.ToString() != "")
if (dataGridView[i, j].Value != null )
{
if (dataGridView[i, j].Value.ToString().Length > tempMax)
{
tempMax = dataGridView[i, j].Value.ToString().Length;
}
}
}
fieldLength[i] = tempMax * 2;
//ywk 处理空值情况下写入列名2016年1月6日 11:27:30
if (fieldLength[i] == 0)
{
fieldLength[i] = 10;
}
}
//写入文件头
{
//第0个字节为数据库类型
tempByte = 0x03;
bw.Write(tempByte); tempBytes = new byte[3];
//第1个字节为保存时的年份-1990
tempInt = DateTime.Now.Year - 1900;
tempBytes[0] = System.Convert.ToByte(tempInt);
//第2个字节为保存时的月份
tempBytes[1] = System.Convert.ToByte(DateTime.Now.Month);
//第3个字节为保存时的日
tempBytes[2] = (byte)(DateTime.Now.Day);
bw.Write(tempBytes);
//第4-7个字节为行数
bw.Write(rowCount); //第8-9字节为文件头的长度
tempInt = 33 + columnCount * 32;
bw.Write((Int16)tempInt); //第10-11为每行数据所占长度
tempInt = 1;
for (i = 0; i < columnCount; i++)
{
tempInt += fieldLength[i];
}
bw.Write((Int16)tempInt); //第12-31为保留字段,默认为0
tempBytes = new byte[20];
bw.Write(tempBytes); string tempColumnName;
//开始写字段
for (i = 0; i < columnCount; i++)
{
tempColumnName = dataGridView.Columns[i].Name;
tempBytes = ConvertStringToBytes(tempColumnName, 11);
bw.Write(tempBytes);
//第11个字节为数据类型
tempByte = (byte)('C');//数据类型为字符串
bw.Write(tempByte);
//第12-15为保留字节
tempBytes = new byte[4];
bw.Write(tempBytes);
//第16个字节为字段长度
tempByte = (byte)fieldLength[i];
bw.Write(tempByte);
//接着第17-31都为保留字节
tempBytes = new byte[15];
bw.Write(tempBytes);
}
//最后以0D结尾
tempByte = 0x0D;
bw.Write(tempByte);
} object tempValue;
//写入单元格数据
for (i = 0; i < rowCount; i++)
{
//每一行第一个字节默认为20
tempByte = 0x20;
bw.Write(tempByte);
for (j = 0; j < columnCount; j++)
{
tempValue = dataGridView[j, i].Value;
if (tempValue != null)
{
tempBytes = ConvertStringToBytes(tempValue.ToString(), fieldLength[j]);
//byte cut = 0x20;//0x00;
//tempBytes = byteCut(tempBytes);
bw.Write(tempBytes);
}
else
{
tempBytes = ConvertStringToBytes("", fieldLength[j]);
bw.Write(tempBytes);
}
}
} bw.Close();
fs.Close();
}
else
{
MessageBox.Show("表格中没有数据", "提示!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception except)
{
MessageBox.Show(except.Message, "提示!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
表头记录的结构
字节偏移 说明
0 文件类型
0x02FoxBASE
0x03FoxBASE+/dBASE III PLUS,无备注
0x30Visual FoxPro
0x43dBASE IV SQL 表文件,无备注
0x63dBASE IV SQL 系统文件,无备注
0x83FoxBASE+/dBASE III PLUS,有备注
0x8BdBASE IV 有备注
0xCBdBASE IV SQL 表文件,有备注
0xF5FoxPro 2.x(或更早版本)有备注
0xFBFoxBASE
1 – 3 最近一次更新的时间(YYMMDD)
4 – 7 文件中的记录数目
8 – 9 第一个数据记录的位置
10 – 11 每个数据记录的长度(包括删除标记)
12 – 27 保留
28 表的标记
0x01具有 .cdx 结构的文件
0x02文件包含备注。
0x04文件是数据库(.dbc)
请注意,这个字节可以包含任何上面值的和。例如,0x03 表明表具有结构化 .cdx 和一个备注字段。
29 代码页标记
30 – 31 保留,包含 0x00
32 – n 字段子记录
字段的数目决定了字段子记录的数目。表中每个字段都对应一个字段子记录。
n+1 头记录终止符(0x0D)
n+2 到 n+264 此范围内的 263 个字节包含后链信息(相关数据库 (.dbc) 的相对路径)。如果第一个字节为 0x00,则该文件不与数据库关联。因此数据库文件本身总是包含 0x00。
1 头记录中的第 8 到第 9 个字节指示数据文件中数据的起始位置。数据记录从删除标记字节开始。如果此字节为 ASCII 空格 (0x20),该记录没有删除标记,如果第一字节为星号 (0x2A),该记录有删除标记。在标记之后是字段记录中所命名各字段中的数据。
字段子记录结构
字节偏移 说明
0 - 10 字段名(最多 10 个字符 —若少于 10 则用空字符 (0x00) 填充)
11 字段类型
C–字符型
Y–货币型
N–数值型
F–浮点型
D–日期型
T–日期时间型
B–双精度型
I–整型
L–逻辑型
M–备注型
G–通用型
C–字符型(二进制)
M–备注型(二进制)
P–图片型
12 - 15 记录中该字段的偏移量
16 字段长度(以字节为单位)
17 小数位数
18 字段标记
0x01系统列(用户不可见)
0x02可存储 null 值的列
0x04二进制列(只适于字符型和备注型)
19 – 32 保留
有关对每个记录中字符的限制以及字段数目的最大值等详细内容,请参阅“Visual FoxPro 系统容量”。
说明
除非在文件中添加下列功能,否则 Visual FoxPro 将不修改按 FoxPro 2.x 文件格式保存的文件标头:
支持 null 值
日期时间型、货币型及双精度型数据
字符字段和备注字段标记为二进制
在数据库 (.dbc) 文件中添加表
提示 可以使用下面的公式求出表文件中字段的数目:(x – 296/32) 公式中,x 表示第一个记录的位置(表头记录的第 8 到第 9 个字节),296 表示 263(后链信息)+ 1(头记录终止符)+ 32(第一个字段子记录),32 是字段子记录的长度。
删除标记 1 字节,在每条记录的前面
只要没有备注字段,基本没有困难