Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 09/10/20 in all areas

  1. Remy Lebeau

    What is wrong with TStringList

    You can do something similar using TStreamReader and its ReadLine() method, eg: var Stream := TReadOnlyCachedFileStream.Create('c:\temp\t'); try var Reader := TStreamReader.Create(Stream); try while not Reader.EndOfStream do begin S := Reader.ReadLine; // use S as needed... end; finally Reader.Free; end; finally Stream.Free; end;
  2. The most common way do text-processing in Delphi is to load a file into a TStringList and then process the text line-by-line. Often you need to save the contents of the StringList back to the file. The TStringList is one of the most widely used RTL classes. However there are a number of limitations discussed below: a) No easy way to preserve line breaks on Load/Save TStringList does not make any effort to recognize the type of line breaks (LF, CR or CRLF) in the files it opens, let alone save that for use on saving. b) Information loss without any warning or any option for dealing with that. Internally TStringList uses unicode strings, but when you save its contents to a file using the default encoding (ANSI), this may result in information loss, without getting any warning or having any means for dealing with that. TEncoding.GetBytes also suffers from that. c) No easy way to determine whether a file you loaded into a TStringList contained a BOM When you load a file (LoadFromFile method), the encoding of the file is stored but not the information about whether the file contained a BOM or not. The WriteBOM property is only used when you save a file. d) Last but not least, no easy way of dealing with utf8 encoded files without a BOM The default text file format in Linux systems, in Visual Studio Code and other editors, as well as in languages such as python 3 is utf8 without BOM. Reading such files with TStringList is problematic and can result in errors, because it thinks such files are ANSI encoded. You could change the DefaultEncoding to utf8, but then you get errors when you read ansi files. No effort is made to detect whether a file without a BOM contains utf8 sequences. Overall, it is desirable that, when you load a file using LoadFromFile and then you save it using SavetoFile, the saved copy is identical to the original. I am attaching a general purpose TStringList descendent that deals with all the above issues in case anyone has a use for that. XStringList.pas
  3. Remy Lebeau

    What is wrong with TStringList

    It is worse than that. It loads the entire file into a local byte array, then it decodes the entire byte array into a single Unicode string, and then it parses that string to extract the lines into individual substrings. So, by the time the TStringList has finished being populated, and before TStrings.LoadFrom...() actually exits, you could be using upwards of 4-5 times the original file size in memory! Granted, this is temporary, and all of that memory gets freed when LoadFrom...() finally exits. But there is small window where you have a LOT of memory allocated at one time.
  4. Stefan Glienke

    What is wrong with TStringList

    Loading an entire file into a TStringList is a bad way to begin with tbh yet often the most easy way because there are no nice to use alternatives out of the box.
  5. pyscripter

    What is wrong with TStringList

    Agree. In the old days (pre Unicode) I wrote the attached Strmtxt.pas (converts a stream to a text file). It would need to be updated to work with recent versions of Delphi. And it works great with buffered streams such as @David Heffernan's TReadOnlyCachedFileStream. With that you could do something like: var Stream := TReadOnlyCachedFileStream.Create('c:\temp\t'); AssignStream(Txt, Stream); while not EOF(Txt) do begin Readln(Txt,S); Writeln(MemoText, S); end; However when you build a text editor such as SynEdit, you typically load the whole file in memory. In any case, the focus of this topic was the limitations of TStringList with regards to dealing with encodings, BOM and Line breaks. It was not about what is the most efficient way to do text processing in Delphi. STRMTXT.PAS
  6. We don't need a topic or any examples. We all know that records can be used as generic types.
  7. As for me, everywhere I need search in arrays, I use generic classes or wrappers. Of course, if I have an array and need finding an item in just one place, I don't implement separate functions @dummzeuch, @Remy Lebeau good point though I prefer separating the methods
  8. In cases where I need the index of a found item, I prefer to have my Find* functions accept an optional parameter to output the index. That way, I can still return a pointer to the actual data and not have to re-index back into the data storage after Find* exits, but I can still use the index for other things as needed. For example: function FindRecord(aID: Integer; vIndex: PInteger = nil): PDataRec; var i: Integer; begin Result := nil; if vIndex <> nil then vIndex^ := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; if vIndex <> nil then vIndex^ := i; Exit; end; end; end; Or: function FindRecord(aID: Integer; var vIndex: Integer): PDataRec; overload; var i: Integer; begin Result := nil; vIndex := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; vIndex := i; Exit; end; end; end; function FindRecord(aID: Integer): PDataRec; overload; var ignore: Integer; begin Result := FindRecord(aProjectID, aID, ignore); end;
  9. Stefan Glienke

    On the use of Interposers

    Interposer classes are only good for components/controls that you already placed on forms because you can keep using them as is while you would need to replace a lets say TButton with TMyAwesomeButton. Where I also like to use them is for extending DUnit as I can use my unit with the TTestCase class then instead of the DUnit one and add functionality - but I would stay away from using it on RTL classes. Funny story: just yesterday we had a sudden compile error from a unit that was not touched in months. A class that was implementing an interface and the compiler complained about missing 2 method implementations. Turned out it was caused by the fact that a junior had added a TAction interposer class into a form unit. That unit was used in the unit which now failed - because those interface methods had TAction in their signature and now they did not match anymore.
  10. Regarding Find-methods: I always make them return a boolean. If I need the index too, I make that an additional out parameter. If it gets too much hassle to always pass a dummy variable, I overload that method with one that does it for me and declare it inline: function TBla.Find(const _Key: TSomeType; out _Data: TSomeOtherType): Boolean; overload; inline; var Idx: Integer; begin Result := Find(_Key, _Data, Idx); end;
  11. For reference, I managed last year to get the "autofocus" working on Android. You can check it on my repo there : - https://github.com/flydev-fr/ZXing.Delphi.Demo - https://github.com/flydev-fr/ZXing.Delphi.Demo/blob/master/AdvancedTestApp/uMain.pas#L487-L515
  12. FPiette

    What is wrong with TStringList

    That looks easy at first. You've found yourself there are limitations. But you forgot one important: using a TStringList load the full file into memory. This is probably not desirable if you want to support arbitrary large files. As previous answers mentioned, there are other possibilities. The best solution depends on what you intent to do. Sometimes it is easy to use memory mapped file.
  13. Arnaud Bouchez

    Firedac - Sqlite - DateTime field

    As I wrote it never stores a double - SQLite3 doesn't support TDateTime double which is Ole/Windows specific. In your code, text will be stored. It is because that SQliteStudio display what is stored, i.e. text, trying several date/time layouts. It seems that FireDac expects ISO-8601 encoding - just as SQLite3. And don't forget to set the seconds - even :00.
  14. Larry Hengen

    Issues Deploying Firebird DB on Ubuntu 8.04LTS

    I reported this as RSP-30899 and posted on the Firebird support forums as well asking for a workaround.
  15. Vandrovnik

    Delphi 10.4 (.1) Welcome Page

    Disabling Welcome Page is on my check list for Delphi installation 🙂
  16. pyscripter

    August 2020 GM Blog post

    It refers to the intention to promote Python4Delphi as a means of bringing Python and Delphi closer together: Python for Delphi (P4D) is a set of free components that wrap up the Python dll into Delphi and Lazarus (FPC). They let you easily execute Python scripts, create new Python modules and new Python types. You can create Python extensions as dlls and much more. P4D provides different levels of functionality: Low-level access to the python API High-level bi-directional interaction with Python Access to Python objects using Delphi custom variants (VarPyth.pas) Wrapping of Delphi objects for use in python scripts using RTTI (WrapDelphi.pas) Creating python extension modules with Delphi classes and functions P4D makes it very easy to use python as a scripting language for Delphi applications. It comes with an extensive range of demos and tutorials.
  17. Lars Fosdal

    August 2020 GM Blog post

    A forum is a place for reasoning and discussion. SO, not so much. What do you prefer? I guess most people go to SO to get an answer, provided one exists, and if not - use a forum. Edit: I gave up on SO for asking questions a long time ago.
  18. Lars Fosdal

    August 2020 GM Blog post

    But SO is not a forum. Questions that are ... unprecise ... get eradicated fast and hard.
  19. Dalija Prasnikar

    August 2020 GM Blog post

    Not really... official forums were already dead. They basically died when NNTP was dropped.
×