急!急!二进制文件操作问题!(200分)

  • 主题发起人 yangzhengling
  • 开始时间
Y

yangzhengling

Unregistered / Unconfirmed
GUEST, unregistred user!
一结构体
typedef struct myStruct
{
ULONG one;
BYTE Two:4;
BYTE three:4;
BYTE four;
USHORT five;
union
{
BYTE six[20];
ULONG seven;
} myUnion;
}
将其存入二进制文件中,第二次存入时接在第一次存入的数据之后,以此类推,次数不定
1。如何存?
2。如何取?请附详码。谢谢!
 
看看这个问题:http://www.delphibbs.com/delphibbs/dispq.asp?lid=1046443
 
能针对我的具体情况在详细写写吗?谢谢了!
 
必须有一个整型值用来标记文件中总共有几结构,否则怎么能够读得出来正确的数据呢。
例:
在一个二进制文件中,前4个字节是用来标记记录数的的(我们不妨把它理解为一个简单
的文件头),这样,在每次打开这个文件的时候,先将文件的前4个字节读入到一个整型
变量中(设这个变量名为StruLen),然后移动文件指针,读取sizeof(myStruct)*StruLen
长度的数据到保存数据结构的数组中,或分为StruLen次读取一个sizeof(myStruct)长度的
数据到一个myStruct类型的结构中。
或者,如果能保证文件的长度是sizeof(myStruct)的整数倍数的话,就是说如果该文件里存
放的只有连续的myStruct类型的数据时,就连长度标识都不用了。
{
TFileStream *fs;
myStruct *st;
int StruSize,iCount;
StruSize = sizeof(myStruct);
try{
//打开文件
fs = new TFileStream("StructData.dat", fmOpenRead);
//确定文件中存了多少个结构
iCount = fs->Size/StruSize;
//为存放数据的动态数组分配内存
st = new[iCount];
//读出数据
fs->ReadBuffer(st, fs->Size);
//在此加入使用各个结构值的代码:
delete fs;
delete[] st;
}catch(Exception &E){
ShowMessage("读取文件失败!");
}
}
 
可以保证文件的长度是sizeof(myStruct)的整数倍数,文件里存
放的只有连续的myStruct类型的数据。可以在读数据处详细点吗?
如对结构体数组数据的读出方面;
st = new[iCount];应为st = new myStruct[iCount]吗?
为什么在delete [] st;这一句出错呢?
存入的代码是怎样的呢?非常感谢!
 
应该是
st=(new myStruct)*iCount吧?
或者开个静态数组得了!
 
抱歉,前面的代码没有调试过,现在的是调试过的了:
//.cpp文件
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ReadButtonClick(TObject *Sender)
{
myStruct st;
int rs;
rs = ReadDataPack(0, &amp;st, "C://temp//StruData.dat");
if (rs<0)
ShowMessage("读取数据文件失败!");
else
ShowMessage(IntToStr(st.one)+","+IntToStr(st.Two)+","+IntToStr(st.three));
}
//---------------------------------------------------------------------------
int __fastcall TForm1::AddDataPack(myStruct *Data, AnsiString FileName)
{
TFileStream *fs;
int rs,StruSize;
StruSize = sizeof(myStruct);
try{
fs = new TFileStream(FileName, fmCreate + fmOpenReadWrite);
//将数据写到文件尾部
fs->Seek(0, soFromEnd);
fs->WriteBuffer(Data, StruSize);
delete fs;
rs = 0;
}catch(Exception &amp;E){
rs = -1;
}
return rs;
}
int __fastcall TForm1::ReadDataPack(int Index, myStruct *Data, AnsiString FileName)
{
TFileStream *fs;
int rs,StruSize;
StruSize = sizeof(myStruct);
try{
fs = new TFileStream(FileName, fmOpenRead);
//读取相应位置的数据
fs->Seek(StruSize*Index, soFrombegin
ning);
fs->ReadBuffer(Data, StruSize);
delete fs;
rs = 0;
}catch(Exception &amp;E){
rs = -1;
}
return rs;
}
void __fastcall TForm1::WriteButtonClick(TObject *Sender)
{
myStruct st;
int rs;
st.one = 1;
st.Two = 2;
st.three = 3;
rs = AddDataPack(&amp;st, "C://temp//StruData.dat");
if (rs<0)
ShowMessage("写数据包失败!");
else
ShowMessage("成功写入数据包!");
}
//---------------------------------------------------------------------------
int __fastcall TForm1::LoadAllData(AnsiString FileName)
{
TFileStream *fs;
myStruct *st;
int StruSize,iCount,rs;
StruSize = sizeof(myStruct);
try{
//打开文件
fs = new TFileStream(FileName, fmOpenRead);
//确定文件中存了多少个结构
iCount = fs->Size/StruSize;
//为存放数据的动态数组分配内存
st = new myStruct[iCount];
//读出数据
fs->ReadBuffer(st, fs->Size);
//在此加入使用各个结构值的代码:
ListBox1->Items->Clear();
for (int i=0;
i<iCount;
i++){
ListBox1->Items->Add(IntToStr(st.one)+","+IntToStr(st.Two)+","+
IntToStr(st.three));
}
delete fs;
delete[] st;
rs = 0;
}catch(Exception &amp;E){
rs = -1;
}
return rs;
}
void __fastcall TForm1::LoadAllClick(TObject *Sender)
{
int rs;
rs = LoadAllData("C://temp//StruData.dat");
if (rs<0)
ShowMessage("读取数据失败!");
}
//---------------------------------------------------------------------------
//.h文件
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
typedef struct _myStruct
{
ULONG one;
BYTE Two:4;
BYTE three:4;
BYTE four;
USHORT five;
union
{
BYTE six[20];
ULONG seven;
} myUnion;
}myStruct;
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *ReadButton;
TButton *WriteButton;
TListBox *ListBox1;
TButton *LoadAll;
void __fastcall ReadButtonClick(TObject *Sender);
void __fastcall WriteButtonClick(TObject *Sender);
void __fastcall LoadAllClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
int __fastcall AddDataPack(myStruct *Data, AnsiString FileName);
int __fastcall ReadDataPack(int Index, myStruct *Data, AnsiString FileName);
int __fastcall LoadAllData(AnsiString FileName);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
 
注意:上一条贴子的代码又更新过,请注意收录
 
To:Sachow:
多谢回答!
可读第二段数据总是出错,不知为什么?可否劳烦再指点一二,不胜感激!
 
我试过,没有啊。如果你在一个数据文件里写了两段数据(此时文件大小就应该是56字节了,
每段数据占28字节),就可以使用
ReadDataPack(1, &amp;st, "C://temp//StruData.dat");
来读取第二段数据,以此类推,这就是我提到的索引不要越界的问题。
如果你在写了几次数据以后,文件大小还是28字节的话,请注意重新取上面一段代码,我
把先前的一个小BUG更新了。
 
在这一步出错!:fs = new TFileStream(FileName, fmCreate + fmOpenReadWrite);
如改为fs = new TFileStream(FileName, fmCreate | fmOpenReadWrite);则
始终为一条数据了!
 
我觉得这是CB6的BUG,我原来也是按照你下面那一句写的,但数据只能覆盖,不能追加,
如果用CB5,下面一句是有效的——我又看了一下我原来用CB5写过的类似程序。
 
可是我用的就是CB5啊
 
[删除本贴代码,看下一贴的]
 
用标准C的文件操作函数好了:
int __fastcall TForm1::AddDataPack(myStruct *Data, AnsiString FileName)
{
FILE *fp;
int rs,StruSize;
StruSize = sizeof(myStruct);
if ((fp = fopen(FileName.c_str(),"a+"))==NULL)
return -1;
try{
fseek(fp, 0, SEEK_END);
fwrite(Data, StruSize, 1, fp);
rs = 0;
}catch(...){
rs = -1;
}
fclose(fp);
return rs;
}
int __fastcall TForm1::ReadDataPack(int Index, myStruct *Data, AnsiString FileName)
{
FILE *fp;
int rs,StruSize;
StruSize = sizeof(myStruct);
if ((fp = fopen(FileName.c_str(),"r"))==NULL)
return -1;
try{
//读取相应位置的数据
fseek(fp, StruSize*Index, SEEK_SET);
fread(Data, StruSize, 1, fp);
rs = 0;
}catch(...){
rs = -1;
}
fclose(fp);
return rs;
}
 
果然没问题了!!
顺便问一句有谁知道结构体前加
#pragma pack(1)
是什么意思吗?
 
#pragma pack是设定字节对齐的方式
为了使程序更规范(更符合需求及C/C++语言的语法),我又做了如下改动(实际上只是
改了文件打开方式及文件名参数类型):
int __fastcall TForm1::AddDataPack(myStruct *Data, const char *FileName)
{
FILE *fp;
int rs,StruSize;
StruSize = sizeof(myStruct);
if ((fp = fopen(FileName,"ab+"))==NULL)
return -1;
try{
fseek(fp, 0, SEEK_END);
fwrite(Data, StruSize, 1, fp);
rs = 0;
}catch(...){
rs = -1;
}
fclose(fp);
return rs;
}
int __fastcall TForm1::ReadDataPack(int Index, myStruct *Data,
const char *FileName)
{
FILE *fp;
int rs,StruSize;
StruSize = sizeof(myStruct);
if ((fp = fopen(FileName,"rb"))==NULL)
return -1;
try{
//读取相应位置的数据
fseek(fp, StruSize*Index, SEEK_SET);
fread(Data, StruSize, 1, fp);
rs = 0;
}catch(...){
rs = -1;
}
fclose(fp);
return rs;
}
 
顺便把LoadAllData也改了:
int __fastcall TForm1::LoadAllData(const char *FileName)
{
FILE *fp;
myStruct *st;
int StruSize,iCount,rs;
char buf[128];
StruSize = sizeof(myStruct);
if ((fp = fopen(FileName, "rb"))==NULL)
return -1;
try{
//确定文件中存了多少个结构
fseek(fp, 0, SEEK_END);
iCount = ftell(fp)/StruSize;
rewind(fp);
//为存放数据的动态数组分配内存
st = new myStruct[iCount];
//读出数据
fread(st, StruSize, iCount, fp);
fclose(fp);
//在此加入使用各个结构值的代码:
ListBox1->Items->Clear();
for (int i=0;
i<iCount;
i++){
sprintf(buf,"%d,%d,%d",st.one, st.Two, st.three);
ListBox1->Items->Add(buf);
}
delete[] st;
rs = 0;
}catch(...){
rs = -1;
}
return rs;
}
 
能详细说说#pragma pack吗?或举个例子什么的
还有six的参数如何读入和写入啊?多谢了
 
#pragma 是用来指示编译器工具的预处理指令,也就是说对编译器进行微调的指令,不同的
编译支持的指示关键字是不同的,当编译器遇到它不能识别的预处理指令就可忽略之。如果
你想通过微调编译器来优化程序,就需要阅读相关编译器的说明书。实际上,即使不用任何
预处理指令,程序同样能够运行得很好。
你的结构定义里的six是一个unsigned char类型的数据,可以把它当作字符串来用
void __fastcall TForm1::Button1Click(TObject *Sender)
{
BYTE b[20];
strcpy(b,"今天你QQ了吗?");
MessageBox(Handle,b,"",MB_OK);
}
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部