@@ -52,6 +52,7 @@ TWeatherStation = class
5252 lookupStrFloatToIntList: TValidTemperatureDictionary;
5353 procedure CreateLookupTemp ;
5454 procedure ReadMeasurements ;
55+ procedure ReadMeasurementsBuf ;
5556 procedure ParseStationAndTemp (const line: string);
5657 procedure AddCityTemperatureLG (const cityName: string; const newTemp: int64);
5758 procedure SortWeatherStationAndStats ;
@@ -239,10 +240,10 @@ procedure TWeatherStation.AddCityTemperatureLG(const cityName: string;
239240 stat: PStat;
240241begin
241242 // If city name esxists, modify temp as needed
242- if self.weatherDictionary.Contains (cityName) then
243+ if self.weatherDictionary.TryGetValue (cityName, stat ) then
243244 begin
244245 // Get the temp record
245- stat := self.weatherDictionary[cityName];
246+ // stat := self.weatherDictionary[cityName];
246247
247248 // Update min and max temps if needed
248249 // Re-arranged the if statement, to achieve minimal if checks.
@@ -309,11 +310,9 @@ procedure TWeatherStation.ParseStationAndTemp(const line: string);
309310 strFloatTemp := Copy(line, delimiterPos + 1 , Length(line));
310311
311312 // Using a lookup value speeds up 30-45 seconds
312- if self.lookupStrFloatToIntList.Contains (strFloatTemp) then
313+ if self.lookupStrFloatToIntList.TryGetValue (strFloatTemp, parsedTemp ) then
313314 begin
314- parsedTemp := self.lookupStrFloatToIntList[strFloatTemp];
315- self.AddCityTemperatureLG(Copy(line, 1 , delimiterPos - 1 ),
316- parsedTemp);
315+ self.AddCityTemperatureLG(Copy(line, 1 , delimiterPos - 1 ), parsedTemp);
317316 end ;
318317 end ;
319318end ;
@@ -346,11 +345,99 @@ procedure TWeatherStation.ReadMeasurements;
346345 end ;
347346end ;
348347
348+ procedure TWeatherStation.ReadMeasurementsBuf ;
349+ var
350+ fileStream: TFileStream;
351+ memStream: TMemoryStream;
352+ streamReader: TStreamReader;
353+ buffer: TBytes;
354+ bytesRead, totalBytesRead, chunkSize, lineBreakPos, chunkIndex,
355+ index, lineCount: int64;
356+ begin
357+
358+ chunksize := 536870912 * 1 ;
359+
360+ // Open the file for reading
361+ fileStream := TFileStream.Create(self.fname, fmOpenRead);
362+ SetLength(buffer, chunkSize);
363+ try
364+ memStream := TMemoryStream.Create;
365+ try
366+ totalBytesRead := 0 ;
367+ chunkIndex := 0 ;
368+ lineCount := 0 ;
369+
370+ // Read and parse chunks of data until EOF
371+ while totalBytesRead < fileStream.Size do
372+ begin
373+ // Read more bytes and keep track on bytes read
374+ bytesRead := fileStream.Read(buffer[0 ], chunkSize);
375+ Inc(totalBytesRead, bytesRead);
376+
377+ // Find the position of the last newline character in the chunk
378+ lineBreakPos := BytesRead;
379+ while (lineBreakPos > 0 ) and (Buffer[lineBreakPos - 1 ] <> Ord(#10 )) do
380+ Dec(lineBreakPos);
381+
382+ { Now, must ensure that if the last byte read in the current chunk
383+ is not a newline character, the file pointer is moved back to include
384+ that byte and any preceding bytes of the partial line in the next
385+ chunk's read operation.
386+
387+ Also, no need to update the BytesRead variable in this context because
388+ it represents the actual number of bytes read from the file, including
389+ any partial line that may have been included due to moving the file
390+ pointer back.
391+ Ref: https://www.freepascal.org/docs-html/rtl/classes/tstream.seek.html}
392+ if lineBreakPos < bytesRead then
393+ fileStream.Seek(-(bytesRead - lineBreakPos), soCurrent);
394+ // {$IFDEF DEBUG}
395+ // Do something with the chunk here
396+ // Like counting line
397+ for index := 0 to lineBreakPos - 1 do
398+ if buffer[index] = Ord(#10 ) then
399+ lineCount := lineCount + 1 ;
400+ // {$ENDIF DEBUG}
401+
402+ // Use memory stream & stream reader
403+ memStream.Write(buffer[0 ], lineBreakPos - 1 );
404+ memStream.Position:=0 ;
405+ streamReader := TStreamReader.Create(memStream);
406+ try
407+ while not streamReader.EOF do
408+ begin
409+ // WriteLn(streamReader.ReadLine);
410+ self.ParseStationAndTemp(streamReader.ReadLine);
411+ end ;
412+ finally
413+ streamReader.Free;
414+ end ;
415+ // {$IFDEF DEBUG}
416+ // Display user feedback
417+ WriteLn(' Line count: ' , IntToStr(lineCount));
418+ WriteLn(' Chunk ' , chunkIndex, ' , Total bytes read:' , IntToStr(totalBytesRead));
419+ // {$ENDIF DEBUG}
420+
421+ // {$IFDEF DEBUG}
422+ // Increase chunk index - a counter
423+ Inc(chunkIndex);
424+ // {$ENDIF DEBUG}
425+ end ;
426+ finally
427+ memStream.Free;
428+ end ;
429+ finally
430+ // Close the file
431+ fileStream.Free;
432+ end ;
433+ end ;
434+
349435// The main algorithm
350436procedure TWeatherStation.ProcessMeasurements ;
351437begin
352438 self.CreateLookupTemp;
353439 self.ReadMeasurements;
440+ // self.ReadMeasurementsBuf;
354441 self.SortWeatherStationAndStats;
355442 self.PrintSortedWeatherStationAndStats;
356443end ;
0 commit comments