Solved

# Dynamic Array with multiple values?

Posted on 2006-04-15
155 Views
Hi,

Let me first explain what I need to do:
I have a table where each record is storing 42 timevalues. The record has also a unique integer number (autoinc).
Record can be added and deleted from this table.

I need to have very quick access to the autoinc-number and the 42 timevalues of all records in the table.

I was thinking about an array of some kind, but I don't know how to add (and later access) the autoinc-number as well as the timevalues.
But when I set it up as I tried below, I get an error, because the autoinc-number will exceed the maximum number allowed for the array (as soon as the autoinc-number is missing one number - 1-2-3-(4 deleted)-5-6-7  in line.

var  Werktijden                    : Array of Array of TTime;   // Gebruikt voor de agenda

SetLength(Werktijden,DM.TMedewerkers.RecordCount,42);

DM.TMedewerkers.First;
For i := 0 to DM.TMedewerkers.RecordCount -1 do
begin
Werktijden[DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger,0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
// etc. for each timevalue
DM.TMedewerkers.Next;
end;

So I need to be able to quickly get all timevalues of a certain autoinc-number.

Can anybody give me a sample on how to set it up correctly.

Regards,
Stef
0
Question by:Delphiwizard

LVL 14

Accepted Solution

Why not use a TList?

type
TTimeRecord = array [0 .. 41] of TTime;
PTimeRecord = ^TTimeRecord;
var
List: TList;
p: PTimeRecord;
begin
List := TList.Create;
for i := 0 to DM.TMedewerkers.RecordCount -1 do
try
New(p);
for j := 0 to 41 do
p^[j] := DM.TMedewerkers.Fields[j].AsDateTime - StrToTime('00:00:01'); // populate each record
DM.TMedewerkers.Next;
except
end;
end;

and when you want to free the list:

for i := List.Count - 1 downto 0 do
begin
p := PTimeRecord(List.Items[i]);
Dispose(p);
end;
List.Free;
0

Author Comment

Thank you.
How do I access the timevalues of a certain record (=autoinc)?
0

LVL 14

Expert Comment

let's say you want to access record number 4:

var
p: PTimeRecord;
begin
p := PTimeRecord(List.Items[4]);
ShowMessage('Second Time is ' + TimeToStr(p^[2]));
end;
0

Author Comment

?    for j := 0 to 41 do
p^[j] := DM.TMedewerkers.Fields[j].AsDateTime - StrToTime('00:00:01'); // populate each record

How is controled which fields are added to the list?
Table TMedewerkers has a lot more fields (and also datatime-fields like date_of_birth).

So how is j=1 related to f.e. DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
0

LVL 14

Expert Comment

Erm.. I was just thinking if your fields in the DB are numbered from 0 to 41, then you don't have to write a statement to get the value for each record...

If you want to, you can still use your normal way of doing

p^[0] := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
p^[1] := DM.TMedewerkers.FieldByName('AgendaZo1C').AsDateTime - strToTime('00:00:01');

DragonSlayer.
0

Author Comment

Stef
0

LVL 14

Expert Comment

0

Author Comment

Well...
After implementing it, I don't seem te have access to the timetable afterall.
This is what I did do:

// Executed in Afterpost-Event and in OnOpen of TMedewerkers
procedure TDM.AgendaWerktijdenInVariablenPlaatsen;
var i : Integer;
begin
TijdelijkeInteger := DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger;
DM.TMedewerkers.First;
for i := Werktijden.Count - 1 downto 0 do
begin
MedewerkersRecord := PTimeRecord(Werktijden.Items[i]);
Dispose(MedewerkersRecord);
end;

Did I miss something or implemeted it incorrectly?
Regards,
Stef
for i := 0 to DM.TMedewerkers.RecordCount -1 do
try
New(MedewerkersRecord);
MedewerkersRecord^[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[1]  := DM.TMedewerkers.FieldByName('AgendaZo1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[2]  := DM.TMedewerkers.FieldByName('AgendaZo2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[3]  := DM.TMedewerkers.FieldByName('AgendaZo2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[4]  := DM.TMedewerkers.FieldByName('AgendaZo3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[5]  := DM.TMedewerkers.FieldByName('AgendaZo3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[6]  := DM.TMedewerkers.FieldByName('AgendaMa1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[7]  := DM.TMedewerkers.FieldByName('AgendaMa1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[8]  := DM.TMedewerkers.FieldByName('AgendaMa2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[9]  := DM.TMedewerkers.FieldByName('AgendaMa2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[10] := DM.TMedewerkers.FieldByName('AgendaMa3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[11] := DM.TMedewerkers.FieldByName('AgendaMa3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[18] := DM.TMedewerkers.FieldByName('AgendaWO1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[19] := DM.TMedewerkers.FieldByName('AgendaWO1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[20] := DM.TMedewerkers.FieldByName('AgendaWO2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[21] := DM.TMedewerkers.FieldByName('AgendaWO2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[22] := DM.TMedewerkers.FieldByName('AgendaWO3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[23] := DM.TMedewerkers.FieldByName('AgendaWO3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[30] := DM.TMedewerkers.FieldByName('AgendaVr1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[31] := DM.TMedewerkers.FieldByName('AgendaVr1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[32] := DM.TMedewerkers.FieldByName('AgendaVr2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[33] := DM.TMedewerkers.FieldByName('AgendaVr2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[34] := DM.TMedewerkers.FieldByName('AgendaVr3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[35] := DM.TMedewerkers.FieldByName('AgendaVr3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[36] := DM.TMedewerkers.FieldByName('AgendaZa1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[37] := DM.TMedewerkers.FieldByName('AgendaZa1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[38] := DM.TMedewerkers.FieldByName('AgendaZa2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[39] := DM.TMedewerkers.FieldByName('AgendaZa2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[40] := DM.TMedewerkers.FieldByName('AgendaZa3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[41] := DM.TMedewerkers.FieldByName('AgendaZa3E').AsDateTime - strToTime('00:00:01');
DM.TMedewerkers.Next;
except
end;
DM.TMedewerkers.Locate('Persoonsnr', TijdelijkeInteger,[]);
end;

In the top of the unit of MainForm:
type
TTimeRecord = array [0 .. 41] of TTime;
PTimeRecord = ^TTimeRecord;
type
TMainForm = class(TForm)

In OnCreat-event of MainForm:
Werktijden := TList.Create;

In OnClose-event of MainForm:
for i := Werktijden.Count - 1 downto 0 do
begin
MedewerkersRecord := PTimeRecord(Werktijden.Items[i]);
Dispose(MedewerkersRecord);
end;
Werktijden.Free;

// Testing if it works .... It doesn't till now.
procedure TFHoofdscherm.Button1Click(Sender: TObject);
begin
// Should give me the value of DM.TMedewerkers.FieldByName('AgendaMa1B').AsDateTime of the first record.
MedewerkersRecord := PTimeRecord(Werktijden.Items[0]);
ShowMessage('Begintijd op maandag: ' + TimeToStr(MedewerkersRecord^[6]));
end;
0

LVL 14

Expert Comment

So instead, what does it show?
0

Author Comment

Always 00:00:01
0

LVL 14

Expert Comment

I don't understand... what is this code for?

procedure TDM.AgendaWerktijdenInVariablenPlaatsen;
var i : Integer;
begin
TijdelijkeInteger := DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger;
DM.TMedewerkers.First;
for i := Werktijden.Count - 1 downto 0 do
begin
MedewerkersRecord := PTimeRecord(Werktijden.Items[i]);
Dispose(MedewerkersRecord);
end;

0

Author Comment

That is what I do after TMedewerkers is changed.

=================================
TijdelijkeInteger := DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger;
=================================
Will get the current record (Persoonsnr) to locate it after all records are added to the list.

=================================
for i := Werktijden.Count - 1 downto 0 do
begin
MedewerkersRecord := PTimeRecord(Werktijden.Items[i]);
Dispose(MedewerkersRecord);
end;
=================================
Clears the whole list.

Below is part of the same procedure: TDM.AgendaWerktijdenInVariablenPlaatsen;

for i := 0 to DM.TMedewerkers.RecordCount -1 do
try
New(MedewerkersRecord);
MedewerkersRecord^[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[1]  := DM.TMedewerkers.FieldByName('AgendaZo1E').AsDateTime - strToTime('00:00:01');
etc...

Regards,
Stef

0

LVL 14

Expert Comment

after the for loop to dispose, you should also do a

Werktijden.Clear;
0

Author Comment

Till here it is working now, however it takes quite some time to save all records into the list.
Is it possible that after an insert/update of a record, only the current record is changed/added to the list?
0

LVL 14

Expert Comment

yea, why not?

if there is an INSERT, you can do

DM.TMedewerkers.Last;
New(MedewerkersRecord);
MedewerkersRecord^[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^[1]  := DM.TMedewerkers.FieldByName('AgendaZo1E').AsDateTime - strToTime('00:00:01');
etc

for an update, if you know the record number, say if it is record number 3:

MedewerkersRecord := PTimeRecord(List[2]);
MedewerkersRecord^[0] := // the new updated time, etc etc
0

Author Comment

So when I go back to my very first question.
** I need to have very quick access to the autoinc-number and the 42 timevalues of all records in the table.
As the autoInc-number isn't stored I still need to look for it in the table, before I can access it's details.
That was exactly what I was trying to avoid.
0

LVL 14

Expert Comment

What database are you using? Seems strange but why don't you get the auto inc number as well?
0

Author Comment

I'm using an MS Access database, but as you know the recordnumber isn't the same as the autoInc-number.
0

Author Comment

How can I get the autoinc-number directly from the List?
0

LVL 14

Expert Comment

Questions:

1. In which instance(s) do you need to use the AutoInc number?
2. If you want to add AutoInc to your List, why not make it a record instead?

type
TMyRecord = record
AutoInc: Integer;
Times: array [0 .. 41] of TTime;
end;
PMyRecord = ^TMyRecord;

and carry on from there?
0

Author Comment

How do I add both to the list and how do I access both afterwords?
0

Author Comment

I load the worktimes to use them in a scheduler.
The worktimes are shown in the scheduler in a different backgroundcolor.
But when I need to load them from a table, it takes too long, so I want them to be accessable from memory.

The autoinc-field is related to the resource in the scheduler. So each employee has it's own workinghours.
0

LVL 14

Expert Comment

Well, now here are some considerations:

1. Would you mind looping through memory to find the auto-inc number? If you don't mind, you can do this

var
MyRecord: PMyRecord;
begin
for i := 0 to DM.TMedewerkers.RecordCount -1 do
try
New(MyRecord);
MyRecord^.AutoInc := DM.TMedewerkers.FieldByName('AutoInc').AsInteger;
MyRecord^.Times[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
MyRecord^.Times[1]  := DM.TMedewerkers.FieldByName('AgendaZo1E').AsDateTime - strToTime('00:00:01');
MyRecord^.Times[2]  := DM.TMedewerkers.FieldByName('AgendaZo2B').AsDateTime - strToTime('00:00:01');
...

and when you need to find that particular record, you can do a

function FindAutoInc(AutoIncNumber: Integer): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to List.Count - 1 do
if PMyRecord(List[i])^.AutoInc = AutoIncNumber then
begin
Result := i;
break;
end;
end;

so, to locate the record for number, say 4827,

var
MyRecord: PMyRecord;
begin
i := FindAutoInc(4827);
if i < 0 then
raise Exception.Create('No matching records!');
MyRecord := PMyRecord(List[i]);
ShowMessage('The 1st time is ' + TimeToStr(MyRecord^.Times[0]));
...

2. Instead of using AutoInc, it is also a good idea to populate the database with your own unique number, in this case a GUID. That way, you have full control over what is the next auto-inc number you will be putting in.
0

Author Comment

When going for the GUID. There still will be the issue when deleting a record.
Suppose I have GUID 1,2,3 and 4 and GUID is deleted.
I can't reassign GUID's to to all records, as than the reference to the scheduler would be lost.
So then I have the sam problem that I had when using and array to store the times.

When loading the scheduler, the worktimes from each employee will be loaded. All individual appointments (events) in the scheduler are assigned to one employee. This is currently done through the autoinc-number.
Loading the worktimes can easily be done by using this unique employee-number. But changing the GUID, would result in having to change all event assigned to that employee also.

So I guess the find-option is best? Or do you have any other ideas? Did I miss something?
0

LVL 14

Expert Comment

GUIDs are unique, so you won't need to reassign them.
0

Author Comment

Ok. I will do some testing tomorrow.
Thanks again and goodnight.
0

Author Comment

Hi DragonSlayer.

I've tried to get it to work but ... it didn't happen yet.

The code below gives me a hard time. The LIST-part in function VindMedewerker isn't known? And I don't know if the adding/changing of a record is implemented correctly.
Also I need to cleanup the record(s) from memory after closing the application. How do I do that?

*** unit main ***
type
TMedewerkersRecord = record
NrPersoon  : Integer;
Werktijden : Array [0 .. 41] of TTime;
end;
PMedewerkersRecord = ^TMedewerkersRecord;

var
MedewerkersRecord             : PMedewerkersRecord;

*** unit Datamodule ***
// Executed after OnAfterPost-event  of the table TMedewerkers  -> LoadAllRecords=False.
// Executed after OnAfterOpen-event of the table TMedewerkers   -> LoadAllRecords=True.
var i, j : Integer;

begin
MedewerkersRecord^.NrPersoon      := DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger;
MedewerkersRecord^.Werktijden[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[1]  := DM.TMedewerkers.FieldByName('AgendaZo1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[2]  := DM.TMedewerkers.FieldByName('AgendaZo2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[3]  := DM.TMedewerkers.FieldByName('AgendaZo2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[4]  := DM.TMedewerkers.FieldByName('AgendaZo3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[5]  := DM.TMedewerkers.FieldByName('AgendaZo3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[6]  := DM.TMedewerkers.FieldByName('AgendaMa1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[7]  := DM.TMedewerkers.FieldByName('AgendaMa1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[8]  := DM.TMedewerkers.FieldByName('AgendaMa2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[9]  := DM.TMedewerkers.FieldByName('AgendaMa2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[10] := DM.TMedewerkers.FieldByName('AgendaMa3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[11] := DM.TMedewerkers.FieldByName('AgendaMa3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[18] := DM.TMedewerkers.FieldByName('AgendaWO1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[19] := DM.TMedewerkers.FieldByName('AgendaWO1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[20] := DM.TMedewerkers.FieldByName('AgendaWO2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[21] := DM.TMedewerkers.FieldByName('AgendaWO2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[22] := DM.TMedewerkers.FieldByName('AgendaWO3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[23] := DM.TMedewerkers.FieldByName('AgendaWO3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[30] := DM.TMedewerkers.FieldByName('AgendaVr1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[31] := DM.TMedewerkers.FieldByName('AgendaVr1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[32] := DM.TMedewerkers.FieldByName('AgendaVr2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[33] := DM.TMedewerkers.FieldByName('AgendaVr2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[34] := DM.TMedewerkers.FieldByName('AgendaVr3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[35] := DM.TMedewerkers.FieldByName('AgendaVr3E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[36] := DM.TMedewerkers.FieldByName('AgendaZa1B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[37] := DM.TMedewerkers.FieldByName('AgendaZa1E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[38] := DM.TMedewerkers.FieldByName('AgendaZa2B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[39] := DM.TMedewerkers.FieldByName('AgendaZa2E').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[40] := DM.TMedewerkers.FieldByName('AgendaZa3B').AsDateTime - strToTime('00:00:01');
MedewerkersRecord^.Werktijden[41] := DM.TMedewerkers.FieldByName('AgendaZa3E').AsDateTime - strToTime('00:00:01');
end;

function VindMedewerker(PersoonsNummer : Integer): Integer;
var i: Integer;
begin
Result := -1;
for i := 0 to List.Count - 1 do
if PMedewerkersRecord(List[i])^.NrPersoon = PersoonsNummer then
begin
Result := i;
Break;
end;
end;

begin
Try
begin
DM.TMedewerkers.First;
for i := 0 to DM.TMedewerkers.RecordCount - 1 do
begin
DM.TMedewerkers.Next
end;
end else
begin
j := VindMedewerker(DM.TMedewerkers.FieldByName('Persoonsnr').AsInteger);
if j < 0 then
else
MedewerkersRecord := PMedewerkersRecord(List[j]);  // Update existing record
end;
except
end;
end;

Regards,
Stef
0

LVL 14

Expert Comment

erm... List in this case, is your TList.

1. Scenario 1, using AutoInc

Because we do not know the value of the AutoInc, you would need to post it in the table first, then seek to the last record and populate your TList, e.g.

TMedewerkers.Insert;
TMedewerkers.FieldByName('AgendaZo1B').AsDateTime := DateTimePicker1.Time;
// ... etc etc
TMedewerkers.Post;
TMedewerkers.Last;
New(MedewerkersRecord);
with MedewerkersRecord^ do
begin
NrPersoon := TMedewerkers.FieldByName('Persoonsnr').AsInteger;
Werktijden[0]  := DM.TMedewerkers.FieldByName('AgendaZo1B').AsDateTime - strToTime('00:00:01');
// ... etc etc
end;

2. Scenario 2, using GUID

uses
ComObj, ActiveX;

function CreateGuid: string;
var
ID: TGUID;
begin
Result := '';
if CoCreateGuid(ID) = S_OK then
Result := GUIDToString(ID);
end;

myGUID := CreateGuid;
// in this case, the unique ID is string, not integer
TMedewerkers.Insert;
TMedewerkers.FieldByName('Persoonsnr').AsString := myGUID;
TMedewerkers.FieldByName('AgendaZo1B').AsDateTime := DateTimePicker1.Time;
TMedewerkers.Post;
// no need to call Last, or to refresh the table
New(MedewerkersRecord);
with MedewerkersRecord^ do
begin
NrPersoon := myGUID;
Werktijden[0]  := DateTimePicker1.Time;
// ... etc etc
end;
0

LVL 14

Expert Comment

To update:

var
RecordNumber: Integer;
// ...

if RecordNumber < 0 then
begin
// update!
MedewerkersRecord := List[RecordNumber];
with MedewerkersRecord^ do
begin
end;
end;
0

LVL 14

Expert Comment

to cleanup, as mentioned earlier:

for i := List.Count - 1 downto 0 do
begin
p := PTimeRecord(List.Items[i]);
Dispose(p);
end;
List.Free;
0

Author Comment

It seems I got to do some more testing tomorrow. Thank you for now...
0

Author Comment

Hello DragonSlayer,

I've got it to work. Thank you very much for your help.

Regards,
Stef
0

LVL 14

Expert Comment

No probs. Really am happy that it works for you Stef!
0

## Featured Post

### Suggested Solutions

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usuaâ€¦
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy reâ€¦
In this sixth video of the Xpdf series, we discuss and demonstrate the PDFtoPNG utility, which converts a multi-page PDF file to separate color, grayscale, or monochrome PNG files, creating one PNG file for each page in the PDF. It does this via a câ€¦
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidtâ€¦