peter2005 0 Posted February 2, 2021 (edited) How can I read content of (typed) file of different data types when one of them is null-terminated string? Something like this: THeader = Record flags : integer; dummy : integer; name: string; padding: integer; end; This would work fine if it were not for string field. By definition a record has to be of fixed size but generally strings are not. Another problem with string is the first byte is omitted since it is considered to be length. Most likely Record cannot be used for my purpose...is there anything else? Edited February 2, 2021 by peter2005 Share this post Link to post
Vandrovnik 214 Posted February 2, 2021 (edited) You can create a method (of that record) for reading data from a stream, for example. In that method, you use Stream.Read(flags, sizeof(flags))... To read the string, you probably have to read byte by byte and check, whether it is zero. Do not forget that size of the char is 2 bytes (in Unicode Delphi). Edited February 2, 2021 by Vandrovnik Share this post Link to post
Pat Foley 51 Posted February 2, 2021 S:array[0..23] of ansichar THeader = Record flags : integer; dummy : integer; name: S; //padding: integer; end; That may be enough to get you started just determine the array size and the correct encoding. If you wanting to do the easy way use component streaming or simply loadfromfile and value pairs. This example was "streamed" by copying from design and pasted here. You can "stream" it by copying it and pasting in your design. object Memo1: TMemo Left = 56 Top = 40 Width = 185 Height = 89 Lines.Strings = ( 'Flag=true' 'Dummy=" "' 'name=Pete2005' '') TabOrder = 0 end Share this post Link to post
Fr0sT.Brutal 900 Posted February 3, 2021 (edited) First read string length (obviously it must be written to the file), then set length of a string and read length number of chars Edited February 3, 2021 by Fr0sT.Brutal Share this post Link to post
FPiette 383 Posted February 3, 2021 You want a typed file, right? Then you cannot have any dynamic type in the record which makes the file. A string is a dynamic type. Instead use an array of characters with specific length: THeader = packed record flags : integer; dummy : integer; name: array [0..25] of Char; padding: integer; end; You could add a property or a method to the record to transform that array of characters to a string for ease of use. Don't forget that characters are 16 bit unicode since Delphi 2009. If you need 8 bit characters, use AnsiChar instead. Also not that I used the keyword "packed" so that the compiler do not insert padding data for alignment for better performances. Share this post Link to post
Lars Fosdal 1792 Posted February 3, 2021 If the initial description is accurate - you don't really have a record - but a stream? I.e. the length of the string is variable, not fixed and #0 padded? [int flags][int dummy][shortish string#0][int padding][int flags][int dummy][this is a lot longer string#0][int padding] Decoding the stream would have to be done element by element, and it would be necessary to know the format of the string - is it ASCII, ANSI (if so, what codepage) or UTF-8. To put it into a more manageable format, you could use your initial record - but you would have to read it element by element to stuff that record or object structure. This can be done in a number of ways - such as a TFileStream or by going old school BlockRead. A well designed stream would have had the string length as an int before the string - but now you instead have to scan for that #0 termination. Share this post Link to post
peter2005 0 Posted February 3, 2021 After reading all the responses I realized there is no easy way.... My description is correct , it's a null-terminated ASCII string(one character one byte, no special ones), its length is not stored anywhere. Using static array only fixes problem of missing a first byte.... What I wanted to avoid the most is reading the string byte by byte until #0 is found. Quote To put it into a more manageable format, you could use your initial record - but you would have to read it element by element to stuff that record or object structure. I'll try this way. Quote A well designed stream would have had the string length as an int before the string. Perhaps but the file I want to read was created in Visual Studio ..so I presume in C++ are "normal" ways to read #0 strings. Share this post Link to post
FPiette 383 Posted February 3, 2021 1 hour ago, peter2005 said: My description is correct , it's a null-terminated ASCII string(one character one byte, no special ones), its length is not stored anywhere. Using static array only fixes problem of missing a first byte.... Are you trying to read an existing file format or are you trying to design your own to store your own data? We can only help you correctly if you tell us what you need to do! Telling us a problem you get with a solution you imagined for a problem we don't know is not the best track to the real solution. Share this post Link to post
Fr0sT.Brutal 900 Posted February 4, 2021 (edited) 20 hours ago, peter2005 said: My description is correct , it's a null-terminated ASCII string(one character one byte, no special ones), its length is not stored anywhere. Using static array only fixes problem of missing a first byte.... What I wanted to avoid the most is reading the string byte by byte until #0 is found. If file could be loaded to memory fully, just use strA := StrPas(pCurr); Inc(pCurr, Length(strA) + 1); ... Alternatively, I believe there are plenty of 3rd party buffer/stream readers available (it's weird RTL still doesn't have one!) Edited February 4, 2021 by Fr0sT.Brutal Share this post Link to post