我是工程师,而不是软件程序员,所以请原谅我的无知。
我编写了一个Delphi(7SE)程序,用于从连接到两个数字温度计的USB端口读取“真实”数据类型。
我已经完成了很多这个程序。
我尚未完成的内容解释如下:
我希望将这个“真实”数据保存到二进制文件中。一个文本文件也可以,但我担心有一个大数据文件。
我还希望从二进制/文本文件中读取这些数据,以便使用我的Delphi应用程序显示数据。
我认为这不会太难。我目前以.CSV格式保存我的数据。
这里的扭曲是二进制文件应该包含来自我的应用程序用户发起的不同会话的数据。
因此,当我点击一个名为“历史”数据的按钮时,会弹出一个新窗口/窗体,显示我已经开始的不同会话时间&早些时候停了下来。然后选择一个会话,然后检索数据以便显示。
这可以在一个二进制文件中完成,还是必须使用2个文件:一个用于“真实”数据,另一个用于索引不同的会话时间?
我对这种保存二进制数据的方法的要求是,我不必一直输入文件名,因此要跟踪许多数据文件。
例如,thermo.hst(历史数据)和thermo.idx(索引文件)文件将包含所有信息,例如实际临时数据,读取数据的时间,会话开始和时间。结束时间等。
任何有用的指针,并希望代码与尽可能多的细节将非常感谢。
答案 0 :(得分:3)
我希望此示例代码不会太晚,无法提供帮助。
(我已将此作为我的另一个答案添加,以便我可以干净地列出代码。如果这个或我之前的帖子回答了你的问题,请点击答案图标,以便获得声望点!)
下面是一些粗略的代码,展示了如何读取ini文件中的部分并找到最大的文件名。我确认它编译并且似乎返回有效值,但您需要确认它可以满足您的需要。它更多的是向您展示这个想法......
请注意,如果您的数据文件名具有扩展名,则您将添加代码以使用以下内容删除示例代码中的扩展名:FileName:= ChangeFileExt(Filename,'')。
// Call with an open inifile. Returns the name of the next filename, or '' if trouble
Function GetNextFileName( const IniFile: TInifile):String;
const
BASE_FILENAME = 'File.'; // sections in the ini file will be [File.1], [File.2], ... [File.100], etc.
var
Sections: TStringList;
NumericPartAsString: String;
NumericPartAsInteger: Integer;
ListIndex: Integer;
LargestFileNumberSeenSoFar: Integer;
begin
Result := '';
Sections := TStringList.Create;
IniFile.ReadSections(Sections); // fills StringList with the names of all sections in the ini file
if( Sections.Count = 0) then
Result := BASE_FILENAME + '1'
else
begin // find largest extension
LargestFileNumberSeenSoFar := -1;
ListIndex := 0;
while ListIndex <= (Sections.Count - 1) do // for every string (which is also a filename) in the string list:
begin
NumericPartAsString := StringReplace(Sections.Strings[ListIndex], BASE_FILENAME, '', []); // remove base filename
if (NumericPartAsString <> '') then
begin
NumericPartAsInteger := StrToIntDef(NumericPartAsString, -1);
if (NumericPartAsInteger > LargestFileNumberSeenSoFar) then
LargestFileNumberSeenSoFar := NumericPartAsInteger;
end;
inc(ListIndex);
end;
if (LargestFileNumberSeenSoFar > -1) then
Result := BASE_FILENAME + IntToStr(LargestFileNumberSeenSoFar + 1);
end;
Sections.Free;
end; { GetNextFileName }
procedure TForm1.Button1Click(Sender: TObject);
var
IniFile: TInifile;
NewFileName: String;
begin
IniFile := TInifile.Create('c:\junk\ini.ini');
NewFileName := GetNextFileName(Inifile);
if (NewFileName = '') then
ShowMessage('Error finding new filename')
else
ShowMessage('New filename is ' + NewFileName);
IniFile.Free;
end;
答案 1 :(得分:2)
通过使用数据库,您可以部分地将问题的一部分从“键入文件名并跟踪许多数据文件”重命名为“键入数据集名称并跟踪许多数据集”。
在这两种情况下,作为示例,用户或程序必须创建新的文件/数据集名称,并从稍后打开的文件/数据集列表中进行选择。在这两种情况下,您都必须调用名为“DeleteDataSet”的函数。
您可能会重新考虑是否确实需要数据库(具有相关的API学习曲线,如何定义数据结构,在更改内容时在字段中更新,在查看器中浏览数据,以编程方式访问数据,专有格式,数据库维护,修复工具,安装等)我相信你可以学到所有这些,并且它们在未来的项目中可能很有价值。但是,对于非软件工程师来说,这种一次性项目可能更简单,更合适。
如果您愿意在一个文件夹中添加许多独特的独立数据文件,我建议您坚持使用正常工作:每个数据集使用一个CSV文件。 (到目前为止,您是否遇到包含单个数据集的CSV文件的速度或大小问题?这将是大量数据!)CSV文件的一个好处是您可以将它们弹出到编辑器中查看或编辑...
然后,添加包含文件名和其他描述性信息的第二个文件。这个文件是一个简单的TIniFile:
[My Name one]
Date=06 June 2010
StartTime=12:30pm
StopTime=3:15pm
FileName=Data1.csv
[My Name two]
...
Delphi for TIniFile中提供的工具可让您轻松管理此列表,包括ReadSections到字符串列表中,您可以将其分配给组合框以供用户选择数据集。 (参见下面的示例)并且,与CSV文件一样,您只需在任何文本编辑器中编辑.ini文件。
您需要构建一个UI以允许用户删除数据集(ini文件和相关的.csv文件中的部分)。为了让您了解如何使用ini文件,这里是删除数据集的伪代码:
(在IDE Object Inspector中,设置ComboBox.Style:= csDropDownList以防止用户输入不存在的名称。)
加载显示可用数据集的组合框。
1. ComboBox.Items := IniFile.ReadSections;
在组合框的OnSelect事件处理程序中:
2. DeleteFile(IniFile.ReadString(CombBox.Text, 'FileName', ''));
3. IniFile.EraseSection(ComboBox.Text); // remove the section from the inifile
哎呀,即使你添加了一些保护和错误检查,这也不是很多代码!
也许上面的解决方案会被其他人拒绝,因为他们试图在一个方孔中放一个圆钉或重新发明轮子。我可能同意他们的观点。反对这种方法有很好的论据,包括许多文件的扩散。但是,如果是我,我至少会认为这种方法保持简单并且不需要任何新东西,但是你学习了TIniFile对象,这是非常强大的。
答案 2 :(得分:0)
数据可以交错。只需使用标识块的标题启动每个块(一组历史记录)并包含其长度。阅读时,您可以轻松地将其分开。
如果需要,您可以在其旁边保留一个额外的索引文件以便快速访问,但如果是这种情况,我会开始研究一些嵌入式数据库。 (TDBF,sqlite或嵌入式火鸟)。
如果我预计将来我的查询会变得更复杂,我也会走向数据库方向。
如果完全是关于日志记录,那么数据就不会很大并且视图的性能很好,我会保留二进制文件,避免让用户安装和维护数据库解决方案的麻烦。 (TDBF可能是一个例外,因为它完全静态链接)