PDA

View Full Version : Handling huge amounts of data



marmin
03-08-2006, 11:06 PM
In a game, the positions , characteristics etc. of 'enemies', (the raw data) , how are they managed by the developer(s)? Is a database used? Or simply a text file that is readed into the program? What is the most common practice.

czar
04-08-2006, 01:40 AM
Depends on what you are doing.

In many games it is possible to randomly generate objects characteristics in the game.

However, in the past I have used ini files, textfile, binary files and databases (Access) to store game data.

It all boils down to you requirements.

Databases are nice if you need to store quite a bit and you want to be able to do SQL queries.

tanffn
04-08-2006, 06:57 AM
I usually create my own data structure and ~simply dump it to a file (WriteBlock), it is also easy to stream that data using TCP for remote file loading.

BaronBigman
30-09-2006, 11:34 AM
How do you send information using a stream?

AthenaOfDelphi
30-09-2006, 12:37 PM
The basics of streaming go something like this:-



var
myFileStream : TFileStream;
begin
myFileStream:=TFileStream.create('C:\MyFile.dat',f mCreate);
myFileStream.writeInteger(intData1);
myFileStream.writeString(strData1);
myFileStream.free;
end;


To read the data back, you then do something like this:-



var
myFileStream : TFileStream;
begin
myFileStream:=TFileStream.create('C:\MyFile.dat',f mOpenRead);
intData1:=myFileStream.readInteger;
strData1:=myFileStream.readString;
myFileStream.free;
end;


The really good thing about streams is that if you have your load and save methods encapsulated as procedures that take the stream as a parameter like this:-



procedure saveMyData(dst:TStream);


You can save the data to a TMemoryStream, TStringStream (any descendant of TStream)... this then allows you to do things like stream the data over a TCP/IP connection for example.

My one bit of advice would be to include versioning information in the stream, so that when you change the data you are storing, you can read the version and then decide how handle it. I know, IIRC, chebmaster has made his persistency system available... whether its appropriate for what you want, only you can decide. I personally favour a more simplistic approach that uses dynamic method calls, to read the version information and then call a method to handle that particular version.

If you want more information on this, let me know and I'll post something.

Hope this helps.

Chesso
05-01-2007, 12:40 AM
I usually use my own format in a text file and create a parser for it, but lately iv'e gone with INI files and they work fairly well and are structured well enough.

Although it would be nice if I could....

[PLAYER]
position=0, 0, 0

You know like have comma delimited values in a single keyvalue, although I could read it in as a string and parse it myself, I might aswell just not use INI at all in that case lol.

czar
05-01-2007, 04:54 AM
You could use a bits, sort of like the way colour is represented $AABBCCDD then you could store a number up to 256 quite easily.

Chesso
05-01-2007, 06:39 AM
But it'd still need to be parsed either pay :P.

I suppose if it was like this:

POSITION=00250015

So it can up to atleast 4 figures, and if the zero's are there, I know exactly where the numbers will be (either the first 4 or the last 4).

But I think using comma's is a little easier to read, if need be.

cairnswm
05-01-2007, 07:31 AM
Why not make your own ini class that allows an array of string for a value - how about like this:


unit GameIni;

interface

uses
IniFiles, Classes;

Type
TGameIni = Class(TiniFile)
Function ReadArrayString(const Section, Ident: String; Default : Array of String) : TStringList;
End;

implementation

{ TGameIni }

function TGameIni.ReadArrayString(const Section, Ident: String;
Default: Array of String): TStringList;
Var
Values, S : String;
SA : TStringList;
I : Integer;
begin
Values := ReadString(Section,Ident,'');
SA := TStringList.Create;
If Values = '' then
Begin
For I := 0 to High(Default) do
SA.Add(Default[I]);
End
Else
Begin
Values := Values + ',';
While Pos(',',Values) > 0 do
Begin
S := Copy(Values,1,Pos(',',Values)-1);
SA.Add(S);
Values := Copy(Values,Pos(',',Values)+1,Length(Values));
End;
End;
Result := SA;
end;

end.


and you'll be able to use it like this:

procedure TForm1.Button1Click(Sender: TObject);
Var
Ini : TGameIni;
begin
Ini := TGameIni.Create(ExtractFilePath(Application.ExeNam e)+'/Game.ini');
ListBox1.Items.AddStrings(Ini.ReadArrayString('Tes t','List',['a','b','c']));
end;

Chesso
05-01-2007, 07:39 AM
Never thought of doing that, I usually use the quite fast Copy() function (instead of slower bogged down ones that eventually call Copy()) and just find the position of the first comma, grab what I need, remove anything before, go to the next comma, remove anything before and so on.

I made a little app that did this once to convert a 54mb file worth of data into a small (few mb's) sql like data syntax and it could do it roughly in 4 seconds :P.

P.S. And that's just using the basic file methods, rather than going down any further, I could never understand how to use filestreams and what not.

cairnswm
05-01-2007, 08:23 AM
I was reffering directly to the problem you mentioned with ini files - not the whole idea of bulk data stores.

Ini files are nice and I use them a lot - but I dont think you can really expect high performance from them. If you've got a 54MB data file then it really should not be in ini format but in some custom binary format of your own - and then my code is meaning less.

But for small games with limited data requirements there is nothing better than an ini file - its user editable and easy accessible etc. I'd never thought of the Array problem before but when you brought it up I thought it was a great idea to work with and is somethign I will be using reqularly in the future.

Chesso
05-01-2007, 08:47 AM
Yeah for using with ini, it could be very usefull.

Nitrogen
05-01-2007, 09:06 AM
A warning about ini files: Dont use them if you have more than about 100 bits of data you want to store and retrieve. They become REALLY slow after a while (because of all that string matching), then you have to rip them out and start all over again.

I usually build a ridiculously complex level editor which saves game data in binary form, then read it back into a game class inside the game..

However, it becomes a real pain in the ass when you change the format or even just insert a small bit of data anywhere in the file...

Moral of the story: Use file data types which can cope with change (ie. chunks)

cragwolf
05-01-2007, 12:18 PM
For users of Free Pascal (not sure about Delphi), in the Sysutils unit you'll find the following function:


function SScanf(const s: String; const fmt: String;
const Pointers: Array[] of Pointer): Integer


which is very useful for scanning a string, and extracting information from it in a format that you have the freedom to specify. Very simple to use, too. For example, to parse the following string: s = '200x300+10-10' (a common geometry specification) you would call something like:


SScanf(s, '%dx%d%d%d', [@FWidth, @FHeight, @FLeft, @FTop]);

which would return FWidth = 200, FHeight = 300, FLeft = 10, and FTop = -10.

Chesso
05-01-2007, 12:39 PM
That sounds quite interesting, so I could pull a line from a file and use that on it, I'm not sure as of yet if it is or has an equivalent in Delphi either.

But could you show me a direct example involving , seperated data like such:

Draw_Box=20, 20, 100, 100

Which relates to X1, Y1, X2, Y2 (for a framed, or filled rectangle for example).

Setharian
05-01-2007, 04:30 PM
it has no equivalent...and sscanf is not the fastest routine either....chunky structure is the best...4 bytes Identifier, 4 bytes Size + x bytes data...allows the insertion of new chunk types without breaking an older loader....

cronodragon
05-01-2007, 05:21 PM
I'm using XML files. Are good for structure hierarchies, and are very easy to parse. I also made my own parser/generator, but you can find many components out there. The benefit of XML is that you can also read and write in many different languages, allowing easy data exchange between systems and applications. 8)

Chebmaster
05-01-2007, 07:49 PM
When I wrote my first (anf for now the only) game in TurboPascal for MS-DOS, it had a fixed format with a hard-coded limits of object numbers, based on the static arrays. I used a simple BlockWrite() plus additional checksum for all the arrays representing the game objects. Notable is the fact that the whole level was stored in a savegame (around 40 Kbytes total) -- you didn't need the level file to load a game saved while roaming it.
...oh yes, and that game was a 3D FPS.http://host-17-99.imsys.net/img/g/screen3.png

But now I, even before I started to flesh out my new engine, I anticipated the problem and developed my persistency system (chepersy). Should save a lot of effort on the date storage part, including all the compatibility and performance problems. Nobody seems to be interested, though, despite the fact that it could help a lot of people :cry:

I, honestly, plan to use it for everything, from the save games to 3d models. Because the other known solutions -- Ini files, raw binaries, TPersistent-based streams -- didn't statisfy me. And now, when I almost finished chepersy, they feel like a stone age tools to me.

If somebody at least tried to use chepersy for his own level editor... Honestly, It would benefit him greatly (me too). :roll:

cragwolf
05-01-2007, 09:24 PM
Assuming there's a space between the comma and the next number, and s = '20, 20, 100, 100':


SScanf(s, '%d, %d, %d, %d', [@X1, @Y1, @X2, @Y2]);

I agree it's not the fastest way to read data, but if you want to parse a string it can be a useful function.

cronodragon
05-01-2007, 09:57 PM
I made my own parsing routine:

procedure ExplodeText(
const Text: string;
var Dest: array of string;
const Separator: string = '';
TrimSpaces: Boolean = True
);

var
IText: Integer;
Part: string;

begin
IText := 1;

if Separator = '' then
begin
// Interpret spaces as separators.

while IText <= Length(Text) do
begin
Part := '';

while (IText <= Length(Text)) and (Text[IText] <= #32) do
begin
Inc(IText);
end;

while (IText <Length> #32) do
begin
Part := Part+Text[IText];
Inc(IText);
end;

SetLength(Dest, Length(Dest)+1);
Dest[High(Dest)] := Part;
end;

end else
begin

while IText <= Length(Text) do
begin
Part := '';

while (IText <= Length(Text)) and (Copy(Text, IText,
Length(Separator)) <> Separator) do
begin
Part := Part+Text[IText];
Inc(IText);
end;

SetLength(Dest, Length(Dest)+1);
if TrimSpaces then
Dest[High(Dest)] := Trim(Part) else
Dest[High(Dest)] := Part;
Inc(IText, Length(Separator));
end;

end;

end;

You can use any space (<= #32) as separator, or a given string and remove spaces surrounding the results.

Any syntax error might be due to the translation I just made to post it here. :P

Chebmaster
05-01-2007, 10:40 PM
Things like this
while (IText <Length> #32) do
begin
Part := Part+Text[IText];
kill performance on the spot. Brutally.

EACH time you add a char to a string, a call to realloc its memory is performed. So you can imagine how "fast" will this code execute.

Ideally, you should make two passes. The first one determines subsstring lengths and positions, the second pass allocates memory by calling SetLength for destination strings (once!) and copies the characters.

As a person who is greatly annoed by the lagre save/load times, I pay a big attention to such matter. There are fields that do not worth optimization. This is *not* one of these.

P.S. My game, even on the 80386, performed quicksave and quickload as fast as you can tap a key - unlike, for example, doom/doom2. So I know what I am talking about.

Chesso
05-01-2007, 10:52 PM
What I do is basically use Pos (or similar), Copy and Delete.

So if it's a line like this:

Bleh=40, 40, 40, 400

I do this:

Get the position of the first ,.
Copy everything beforehand.
Remove everything beforehand.
Rinse and repeat.

Dunno if it's the best/fastest method but it seemed pretty quick for my from my tests (compared to other methods and using other functions).

Faster than Q_Strings too.

Nitrogen
05-01-2007, 11:38 PM
I'd guess that XML is only slightly faster than INI files, and dont forget all those bulky XML libraries required to read it.

XML is too much of a buzz word, people throw it in because they can and because they think its a cool thing to use, not because it's best suited to their program (there are exceptions of course).

Chesso
05-01-2007, 11:54 PM
XML from what I know and have heard, is basically not that great performance wise, I high doubt it outperforms ini files, or atleast wouldn't if ini file handler was improved (as the basic fact is, an INI file is simpler then an XML file, atleast as far as I know).

But people shouldn't be using it for it's performance, but for it's ease of structure.

If you want performance, XML isn't the way to go, nor is INI.

cronodragon
06-01-2007, 03:06 AM
Things like this
while (IText <Length> #32) do
begin
Part := Part+Text[IText];
kill performance on the spot. Brutally.

EACH time you add a char to a string, a call to realloc its memory is performed. So you can imagine how "fast" will this code execute.

Ideally, you should make two passes. The first one determines subsstring lengths and positions, the second pass allocates memory by calling SetLength for destination strings (once!) and copies the characters.

Thanks for pointing that out. I still haven't concentrated on lower level optimizations... I'm solving the general problems for my engine, and making all the code to be as useful as possible. For example that function I posted helps to parse data in many different situations. And while reading you comment, I was thinking that is not hard to optimize that function, if the problem is allocating one character at a time, I would just allocate in big blocks (i.e. 256 bytes) and finally cutting it down to the required size. On the other hand, I wouldn't use parsing functions on places that are time critical anyway. It always depends on the given problem.


XML from what I know and have heard, is basically not that great performance wise, I high doubt it outperforms ini files, or atleast wouldn't if ini file handler was improved (as the basic fact is, an INI file is simpler then an XML file, atleast as far as I know).

But people shouldn't be using it for it's performance, but for it's ease of structure.

If you want performance, XML isn't the way to go, nor is INI.

That's true. And XML is for easy exchange of data between systems. 8)

Paizo
08-01-2007, 09:32 AM
i have a question about large data management,
I need to use a database of cards for a cards game (like magic), at the moment the data is in a .xls file (around 900kb).

information like name of the card, text, name of the images...

i think to save it in .csv and read it with delphi, the question is:

can i use the power of sql query on this file "somehow"?
Do you have any suggestions how to better store this data and manage it?

AthenaOfDelphi
08-01-2007, 04:26 PM
Hi Paizo,

What kind of queries do you want to run against the data?

You can use local files to provide data via TClientDataset, but I'm not sure about querying it as I've never used that mechanism for data storage.

But, depending on the kind of information you want to search on (and the number of cards in the list and how quickly you need an answer) you should be able to do it without a database.

The key issues though are the kind of searches you want to run (some examples would help), the number of cards and the amount of time you are prepared to spend searching. I guess the answers to these questions will depend on the kind of game you're writing.

If you can provide a little more information then it will help immensely :-)

Paizo
08-01-2007, 05:13 PM
ok, i'm here :)

i want to use only the 'select' command for 2 services:

a)you are looking for a card in the database, you don't know the name of the card but you know that (for example) the card is green and have a certain icon. So something fast for searching cards

b)every players have their own decks with n > 59 cards, not random, a player choose them as he wish. So at the start of the game i have to load all data about this cards (ie images and text) and store that data in (for example) a Timagelist on a custom sprite engine.

hope its clear.

AthenaOfDelphi
08-01-2007, 06:43 PM
Certainly is... I'd say that whilst you don't want users sitting around waiting, searching manually (i.e. do a whole bunch of comparisons against your in memory data) isn't going to be too slow for your application.

So with that in mind, you could use a collection.

Create an object descended from TCollectionItem that holds the information about the cards, then write yourself a tool to manage the collection. Players decks could also be held as a collection... maybe create an object call TDeck descended from TCollection that implements the methods you need to search through the cards.

Once you've loaded the deck, you could run through the items it contains and extract the information you require for things like your image lists etc. Again, this shouldn't take too long to execute because the data is all held in memory.

I'm guessing someone will popup and say that this isn't an optimal solution... but from what you've said its more than adequate for your purposes.

Just my $0.02 ;-)

Nitrogen
08-01-2007, 11:39 PM
Yea, you not going to be able to get at the data inside an .xls file (text, images etc) without serious effort, or converting it to another format like you suggest..

And a fully fledged database is WAAY overkill for your requirements...

The quickest and easiest would be to use something like the Collections mentioned above.

cairnswm
09-01-2007, 04:41 AM
You might want to look at one of Jans Delphi Components (http://jansfreeware.com/jfdelphi.htm)


TjanSQL 1.1
2-April-2002 size:379kb
TjanSQL is a single user relational Database engine implemented as a Delphi object using plain text files with semi-colon separated data for data storage. Supported SQL: SELECT (with table joins, field aliases and calculated), UPDATE, INSERT (values and sub-select), DELETE, CREATE TABLE, DROP TABLE, ALTER TABLE, CONNECT TO, COMMIT, WHERE (rich bracketed expression), IN (list or sub query), GROUP BY, HAVING, ORDER BY ( ASC, DESC), nested sub queries, statistics (COUNT, SUM, AVG, MAX, MIN), operators (+,-,*,/, and, or,>,>=,<,<=,=,<>,Like), functions (UPPER, LOWER, TRIM, LEFT, MID, RIGHT, LEN, FIX, SOUNDEX, SQR, SQRT). High performance: complete in-memory handling of tables and recordsets; semi-compiled expressions. Released under MOZILLA PUBLIC LICENSE Version 1.1. NEW FEATURES: fixed memory leak, calculated fields (in select and update statements), field aliases, table aliases, join "unlimited" tables, stdDev aggregate function, ASSIGN TO for named temporary tables, SAVE TABLE for persisting recordsets, INSERT INTO, ISO 8601 dates, numerous extra functions.

I have never used it but have always sort of kept it in mind for one day when I want a SQL based text file system.

Paizo
09-01-2007, 09:25 AM
ty for support guys :)

i forgot to say that cards are around 6000+ (growing) :oops:

so i can't store them all in a collection. I will use collections only for builded decks and so i have to load the text from -somewhere- (ie a text file, .xls or others) and the images from a folder.

you can undestand that looking for a specific card's text in a file of 6000 cards for a deck >59 (maybe all unique) is really lagged! That's why i asked for sql queries.

i will take a look to the link above, ty again.

cairnswm
09-01-2007, 10:11 AM
SQL by its nature will always be SLOWER than a custom created binary search. If you take the time to think about it, each SQL query must be parsed for correctness, then 'interpreted' (1) before accessing the data. The data itself may be fragmented accross multiple disk segments etc and will not be the fastest option for single record type searches.

A binary file using the standard Delphi record structures will always be faster unless it does tooo many disk accesses to find the data.



Type
TCardRecord = Record
CardName &#58; String&#91;30&#93;;
CardText &#58; String&#91;255&#93;;
....
End;

Var
CardFile &#58; File of TCardRecord;


Then ensure the file is stored in sorted order, and do a binary search accross the file. (If you want an example just ask).

Or alternativly include a hash along with the card index into an index file. Hash the card name and then search in the index file to get the card index and access it directly from the Card File.

Lastly - if you want to show off - create the card file and then index the card name along with the card index into a B+ tree structure as an index. This will be fast, possibly faster than the hash table idea but while I've always wanted to make a B+ tree structure I never have.





(1) I say interpreted but it could be compiled or similar as well.

Paizo
09-01-2007, 11:28 AM
ok, but for make a binary search on a file mean that i have to load it all into the ram before; and at the moment i can't use a record as you posted since card's text hasn't a fixed lenght in the .xls that i have.
(if you know a way to save fields with a fixed lenght from excel tell me)
otherwise i have to read and parse every row :/ or i should make a prog for parse and than convert it as i want

edited: I have corrected the post, my english sucks!

cairnswm
09-01-2007, 01:32 PM
You can do a binary search using the FileSeek and FilePos functions and do it against the disk instead of in memory.

If I remember I'll do a little example for you tomorrow - need to go homw and takes kids out now. :)

tanffn
09-01-2007, 01:50 PM
I’m sorry for crashing in so late to the conversation. From what I understood you want to store and search a “huge” amount of data, so much data that you can’t load it all into memory.
Therefore you need to store the information sorted with an indexing table, there are many methods to implement that for example:
You need to use 2 files (or more), data file abd index file(s).
* Upon adding a new element calculate his hash (based on the things you’re going to look for) and add it to the data file (saving the position).
* Save the position + hash in the index file.
In runtime you only need to load the hash file (which is small). When you need to find an element you calculate the hash and jump to the correct location in the data file (it also works if the hash isn’t a unique ID)

Delete is a small problem as you will encounter fragmentation.. but it can be solved.

I hope im answering the right thing :?

Goodluck :)

AthenaOfDelphi
09-01-2007, 08:53 PM
[quote="Paizo"]ty for support guys :)

i forgot to say that cards are around 6000+ (growing) :oops:

so i can't store them all in a collection. I will use collections only for builded decks and so i have to load the text from -somewhere- (ie a text file, .xls or others) and the images from a folder.

you can undestand that looking for a specific card's text in a file of 6000 cards for a deck >59 (maybe all unique) is really lagged! That's why i asked for sql queries.

i will take a look to the ]

With regards to the speed... I have just done a quick test... I populated a string list with 10000 random strings... each one was 10 characters long, and then ran through the list looking for ABCDEFGHIJ. I also searched each string using pos() for the substr 'AB'. The whole process (population and running through the list) took less than 200ms. Thats on an Athlon 800.

Searching for strings etc. on in-memory data can be exceedingly fast.

As for memory requirements... if you say you are going to limit yourself to just 20MB, then each of your 6000 cards can provide 3KB of data and you wouldn't blow your 20MB limit. If a card does provide that much data, can it be optimised once loaded? Link images to cards via integer (4 bytes as opposed to a string which could be anything) for example, that could save a whack of data.

Paizo
10-01-2007, 09:19 AM
...
Searching for strings etc. on in-memory data can be exceedingly fast.
....


I agree.
I think that save some ram space (1mb?) and make the search in the disk isn't good. maybe in future implementation the app will offer the opportunity to make some query on the database and, looking at Athena's test, seems without lag.

cairnswm
10-01-2007, 10:05 AM
In my above post I ment Seek not FileSeek.

Here is an example of a custom data structure used to store data - along with the binary search funtion - note the data must be inserted in alphabetical order.

I cannot get times for the search - I've tried files up to 200000 records and all searches give me 0 millisend response times....

unit QuickDB;

interface

Uses
SysUtils;

Type
TDataRecord = Record
Name : String[100];
Data : Array[1..4] of String [255];
End;

Procedure MakeData(FileName : String; NumOfRecord : Integer);
Function GetRecord(FileName : String; inName : String) : TDataRecord;

implementation

Procedure MakeData(FileName : String; NumOfRecord : Integer);
Var
I : Integer;
F : File of TDataRecord;
DR : TDataRecord;
Begin
AssignFile(F,FileName);
Rewrite(F);
For I := 0 to NumOfRecord-1 do
Begin
DR.Name := 'Rec'+FormatFloat('000000000',I);
DR.Data[1] := 'Data1';
DR.Data[2] := 'Data2';
DR.Data[3] := 'Data3';
DR.Data[4] := 'Data4';
Write(F,DR);
End;
CloseFile(F);
End;
Function GetRecord(FileName : String; inName : String) : TDataRecord;
Var
I,H,L,M : Integer;
F : File of TDataRecord;
DR : TDataRecord;
Begin
L := 0;
AssignFile(F,FileName);
Reset(F);
H := FileSize(F)-1;
M := (H+L) div 2;
Seek(F,M);
Read(F,DR);
While (DR.Name <> inName) and (L<>H) do
Begin
if DR.Name > inName then
Begin
H := M-1;
End
else
Begin
L := M+1;
End;
M := (H+L) div 2;
Seek(F,M);
Read(F,DR);
End;
CloseFile(F);
Result := DR;
End;

end.

Paizo
10-01-2007, 10:22 AM
i appreciate your way to solve problems by posting some code :)
i will make some test soon.

cairnswm
10-01-2007, 11:21 AM
Here is another option for large datasets. I used these components a long time ago D1/D2 days and I thought they were great.

http://rmarsh.com/2001/06/18/qdb-quick-database-components/

cronodragon
13-01-2007, 05:33 PM
Things like this
while (IText <Length> #32) do
begin
Part := Part+Text[IText];
kill performance on the spot. Brutally.

EACH time you add a char to a string, a call to realloc its memory is performed. So you can imagine how "fast" will this code execute.

Ideally, you should make two passes. The first one determines subsstring lengths and positions, the second pass allocates memory by calling SetLength for destination strings (once!) and copies the characters.

Just to inform I made the optimization of that code 8)

I'm allocating a big block to build the string Part, and then I cut it creating another string with the standard Copy() function. In total I make just two allocations in that function, and the speed of the program didn't changed significantly on my 4 years old computer. That should mean using Part := Part+Text[IText] is not a brutal performance killer as suggested. Maybe it is already being optimized by the compiler.

Anyway, that helped me to clear a little my code. Thanks. :D

Paizo
24-01-2007, 09:20 AM
ok i made some test.
I read the text file containing the spoiler and save it in a record as i want. the record is (names are in italian .P ):


Type
TCardRecord = Record
Serie &#58; String&#91;25&#93;;
Categoria &#58; String&#91;25&#93;;
Corporazione &#58; String&#91;30&#93;;
Nome &#58; String&#91;30&#93;;
Testo &#58; Array &#91;0..900&#93; of Char;
L &#58; String&#91;2&#93;;
Errata &#58; Array &#91;0..900&#93; of Char;
R &#58; String&#91;3&#93;;
C &#58; String&#91;3&#93;;
S &#58; String&#91;3&#93;;
A &#58; String&#91;3&#93;;
V &#58; String&#91;3&#93;;
P &#58; String&#91;2&#93;;
Tipo &#58; String&#91;25&#93;;
Grafico &#58; String&#91;20&#93;;
Cerchietto&#58; String&#91;40&#93;;
End;

then i try to implement binary search as suggested, but i don't understand this:


FSize &#58;= FileSize&#40;F&#41;;//file size in bytes, return 2047
RSize&#58;=Sizeof&#40;TCardRecord&#41;;//Record size in bytes, return 2030

the file i created is around 4 mb; why filesize return this value? (i can read it all with no errors)

AthenaOfDelphi
24-01-2007, 10:35 AM
If a file variable links to a typed file (ie f : file of TCardRecord), then the position and size functions work on record numbers.

So, from that I'd say you have 2047 records in your card list.

If you then use Seek(0) (IIRC) you will end up at record 0... the start of the file. Seek(2046) will take you to the last record in the file and Seek(2047) will take you past the end of the file ready to write another record.

To get the file size in bytes, you must connect to it with a file of byte or textfile.

Paizo
24-01-2007, 11:05 AM
ok thanks; i thinked so but by reading some manuals they always say that filesize return the size in bytes (for untyped and typed files). Nice to know that :)