Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Expert Delphi

You're reading from   Expert Delphi Robust and fast cross-platform application development

Arrow left icon
Product type Paperback
Published in Jun 2017
Publisher Packt
ISBN-13 9781786460165
Length 506 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Paweł Głowacki Paweł Głowacki
Author Profile Icon Paweł Głowacki
Paweł Głowacki
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Fasten Your Seat Belts FREE CHAPTER 2. Mind Your Language 3. Packing Up Your Toolbox 4. Playing with FireMonkey 5. FireMonkey in 3D 6. Building User Interfaces with Style 7. Working with Mobile Operating System 8. Extending to the Internet of Things 9. Embedding Databases 10. Integrating with Web Services 11. Building Mobile Backends 12. App Deployment 13. The Road Ahead

Working with files

Almost every app needs to persist data. You have just downloaded an app, worked with it for a while, and the next time you open it, you would like to see that it remembers what you have done so far. An app can store its data in the cloud, in an embedded database or in a file. This last option is the most easy to use. A local file can store information in different formats. It could be a binary file, which is just an array of bytes, that is left to an app to make sense of, or it could be a text file. Your app can store information in plain text or it can use some of the file formats, such as JSON or XML, to make it easier to process text information.

Imagine that you would like to write a small mobile app to keep track of your favorite locations on the internet. To keep it simple, it could be just a list of favorite items made of two strings: an URL and a caption. Let's go for it! Create a new multi-device application in Delphi. Select a blank application template. Save the main form as uFormFavMain and the whole project as FavoritesDemo. Add a new unit to the project and save it as uFavorite. Let's define there a simple TFavorite class for individual favorite items. It will contain only two public string fields, URL and Caption. For convenience, let's add there a constructor that will take initial values for both fields. If we define a custom constructor that takes parameters, we will not be able to call a normal parameterless constructor, so we also need to explicitly define one. We could have defined both string fields as properties, but in fact there is no need for properties here.

There is also the TFavorites class definition, which is a generic object list of TFavorite objects. It is going to be easier to use it in code instead of the full generic notation with < and > characters, as shown in the following code snippet:

unit uFavorite; 

interface

uses
System.Generics.Collections;

type
TFavorite = class
URL: string;
Caption: string;
constructor Create; overload;
constructor Create(AURL, ACaption: string); overload;
end;

TFavorites = class(TObjectList<TFavorite>);

implementation

{ TFavorite }

constructor TFavorite.Create;
begin
end;

constructor TFavorite.Create(AURL, ACaption: string);
begin
URL := AURL;
Caption := ACaption;
end;

end.

We will be first storing favorites in a text file using a convention that each two consecutive strings in the file represent one favorite entry: the first for the URL and the second for the Caption. Later in the chapter, we will use specialized file formats such as JSON and XML.

The main form of our demo app will contain a private field, accessible through a public property, with a list of sample favorite items, which we are going to access from other forms in the application, so we do not duplicate code. That's a proper way of encapsulation. External code will not be able to destroy this instance, because the reference is read-only.

Create an OnCreate event for the main form where we are going to construct a Favorites list and add some sample favorite entries. In the OnDestroy event, we destroy the list. One could argue that Delphi mobile compilers have Automatic Reference Counting (ARC), but it is a good practice to write code, as if there were no ARC in place.

Another good practice is to avoid long identifiers, because your code gets less readable. That is why instead of Favorite in many places of the demo app, we just use Fav as a handy abbreviation, as shown in the following code snippet:

uses 
// ...
uFavorite;

type
TFormFavMain = class(TForm)
// ...
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FFavs: TFavorites;
procedure AddSampleItems;
public
property Favs: TFavorites read FFavs;
end;

var
FormFavMain: TFormFavMain;

implementation

{$R *.fmx}

procedure TFormFavMain.AddSampleItems;
begin
FFavs.Add(TFavorite.Create(
'www.embarcadero.com/products/delphi',
'Delphi Home Page')
);
FFavs.Add(TFavorite.Create(
'docwiki.embarcadero.com/RADStudio/en',
'RAD Studio online documentation')
);
end;

procedure TFormFavMain.FormCreate(Sender: TObject);
begin
FFavs := TFavorites.Create;
AddSampleItems;
end;

procedure TFormFavMain.FormDestroy(Sender: TObject);
begin
FFavs.Free;
end;

There are many different ways of creating files in code. For example, one could use Delphi classic built-in functions such as AssignFile, Rewrite, Reset, and CloseFile. Another option is to use functionality from specialized classes such as TMemo or TIniFile that provide methods such as SaveToFile and LoadFromFile that could be used directly. There is also the TFile class in System.IOUtils that can be used to write and read different types of data such as strings or just raw arrays of bytes.

Probably the most easy way to work with files is to use the TStreamWriter and TStreamReader classes from the System.Classes unit. They provide an elegant programming model for doing file operations.

The main form of our demo app will also work as a menu to display other forms where we will be trying different approaches of working with text files. Let's add a new multi-device form to our project. Save it in the uFormFavTextFiles unit and rename the form to FormFavTextFiles. That is another useful convention to follow. The name of the unit that stores a form starts with u followed by the name of the form.

First we are going to add some navigation code for moving from the main form to the additional form and back. First add the new form to the uses clause in the implementation part of the main form. Then add a button to the form with a call to show the form, as shown in the following code snippet:

uses  
uFormFavTextFiles;

procedure TFormFavMain.btnTextFilesClick(Sender: TObject);
begin
FormFavTextFiles.Show;
end;

In the other form, we add exactly the same logic to display back the main form.

Now we can focus on implementing the functionality to write favorites from the list in our main form into the text file and to read it back. Add two buttons to the form and align them to the top. In this way, they will always look good at different screen factors on mobile devices. Also add a TMemo component, rename it MemoLog, and align it to Client. Optionally, change all four Margins of the memo from 0 to for example 4, so that there is a little margin around the memo that looks better on a mobile screen. The first button will be used to write favorites to a text file and the second to read this information back and display in the memo, so we know that things work OK.

First we are going to define a separate function, GetFilename, that will centralize accessing the name of the file, so both functions for writing and reading are accessing the same file.

On mobile operating systems, unlike traditional desktop ones, an app can only create and read files from its Documents folder. In the System.IOUtils unit that ships with Delphi, there is the TPath class that offers a number of class methods to work with paths. The location of the Documents folder can be obtained with the TPath.GetDocumentsPath call. In order to construct the full path to our file, we also need to use a delimiter before the actual name of the file. A delimiter can be different on different targets; that is why it is a good practice not to hardcode it. If our text file is called favs.txt then the actual code to get the full filename of the favorites text file could look like this:

uses 
System.IOUtils;

function TFormFavTextFiles.GetFilename: string;
begin
Result := TPath.Combine(TPath.GetDocumentsPath, 'favs.txt');
end;

Double-click on the first button on the form and enter there the following code to put the favorites information into the plain text file:

procedure TFormFavTextFiles.btnWriteClick(Sender: TObject); 
var sw: TStreamWriter; fav: TFavorite; favs: TFavorites;
begin
favs := FormFavMain.Favs;
sw := TStreamWriter.Create(GetFilename, False, TEncoding.UTF8);
try
for fav in favs do
begin
sw.WriteLine(fav.URL);
sw.WriteLine(fav.Caption);
end;
finally
sw.Free;
end;
end;

We are using the Favorites list from the main form. To simplify the code, in the first line we put this property reference into a local variable favs, which is easier to use in code. The rest of the implementation is quite trivial. We are constructing an instance of the TStreamWriter class and in the for loop writing URL and Caption properties of each TFavorite item in the list.

Now let's read this information back. In the OnClick event of the second button, insert the following code:

procedure TFormFavTextFiles.btnReadClick(Sender: TObject); 
var sr: TStreamReader;
begin
sr := TStreamReader.Create(GetFilename, TEncoding.UTF8);
try
while not sr.EndOfStream do
MemoLog.Lines.Add(sr.ReadLine);
finally
sr.Free;
end;
end;

Now run the app. Navigate to the Text Files screen and click on the "write" button first and then on the "read" button. You should see the list of favorites in the memo, as shown in the following screenshot:

The problem with this approach is that there is no structure in the data. By convention, we know that every two lines of text contains one favorite entry. The first is the URL and the second is the description.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime