Login Page - Create Account

Support Board


Date/Time: Mon, 25 Nov 2024 02:55:36 +0000



[Programming Help] - How to read file with sc.ReadFile()?

View Count: 2196

[2022-01-20 02:31:01]
User538858 - Posts: 11
With my ACSIL study, there is a bunch of data that I would like to plot. I have already taken care of the code to plot it, but what would be the best way to read data? I have already tried ifstream, but this made the study "unstable" and thus I turned to sc.ReadFile(). However, I cannot figure out how to read the data and store the resulting strings from each line.

On a related note, what would be the "official" way to store a variable array of strings (what is read in from the file). If there is an easier/better way than std::vector, then any help would be greatly appreciated. Thank you in advance.
[2022-01-20 16:28:29]
Tony - Posts: 518
What you have already done and what error messages you got? When
you mentioned "store the resulting string", did you mean to write
the result to a new file?
[2022-01-20 18:19:37]
User538858 - Posts: 11
Using ifstream to read the file into a vector of strings, I did not receive any explicit error messages during compilation, but the message log stated that the study made Sierra Chart unstable. I also do not need to write it to a new file, I merely need to read the file into the study and use it to plot on the chart (the plotting part is complete and works as long as the strings are passed to it).
[2022-01-20 19:12:57]
Tony - Posts: 518
I see, this is what I am doing:

above study function, I have:


SCString ReadTextFile(SCStudyInterfaceRef sc, SCString FileLocation)
{
  char TextBuffer[320000] = {}; // string size 320k, adjust as needed,
  int FileHandle = 1; // File Handle cannot be just an integer numbers, has to be defined first, sc.OpenFile requires int&
  unsigned int *p_BytesRead = new unsigned int(0); // sc.ReadFile() requires unsigned int pointer
  sc.OpenFile(FileLocation.GetChars(), n_ACSIL::FILE_MODE_OPEN_EXISTING_FOR_SEQUENTIAL_READING, FileHandle);
  sc.ReadFile(FileHandle, TextBuffer, 320000, p_BytesRead);
  sc.CloseFile(FileHandle);
  return TextBuffer;
}

inside study function, I have:


SCSFExport scsf_MyStudy(SCStudyInterfaceRef sc)
{

// ... other codes

static SCString MyInputString("");
// has to be static, otherwise the content will be cleared on very next loop

MyInputString.Format(ReadTextFile(sc, "C:\\SierraChart\\Data\\MyData.txt").GetSubString(ReadTextFile(sc, "C:\\SierraChart\\Data\\MyData.txt").GetLength()-1, 0));
// to remove EOF charactor

// or MyInputString.Format(ReadTextFile(sc, "C:\\SierraChart\\Data\\MyData.txt"); depend on your OS

//... other codes

}

now you have read the data from MyData.txt to SCString variable MyInputString
Date Time Of Last Edit: 2022-05-24 01:18:38
[2022-05-21 01:00:56]
ertrader - Posts: 672
Thanks for posting this, it has helped me. I would like to read in a single value from a text file, then draw a line with that value. To draw the line, the value retrieved from the text file has to be converted from text to float so there is code added for this on the last line.

The code below works fine, it's just that I would like to get the performance in the sub 5 ms. It's currently about 30-40 ms on a ramdisk. Is there a better/faster way to accomplish what I'm trying to do?

#include "sierrachart.h"
#include <stdio.h>
#include <stdlib.h>

SCString ReadTextFile(SCStudyInterfaceRef sc, SCString FileLocation)
{
char TextBuffer[1000] = {}; // string size 1k, adjust as needed,
int FileHandle = 1; // File Handle cannot be just an integer numbers, has to be defined first, sc.OpenFile requires int&
unsigned int *p_BytesRead = new unsigned int(0); // sc.ReadFile() requires unsigned int pointer
sc.OpenFile(FileLocation.GetChars(), n_ACSIL::FILE_MODE_OPEN_EXISTING_FOR_SEQUENTIAL_READING, FileHandle);
sc.ReadFile(FileHandle, TextBuffer, 1000, p_BytesRead);
sc.CloseFile(FileHandle);
return TextBuffer;
}

SCDLLName("ReadLineFromFile")
SCSFExport scsf_ReadLineFromFile(SCStudyGraphRef sc)
{

  SCSubgraphRef Line1         = sc.Subgraph[0];
  SCInputRef PathAndFile      = sc.Input[0];
  
if(sc.SetDefaults)
{
sc.GraphName="Read Line Value From File";
sc.StudyDescription="Read Line Value From File";
sc.DrawZeros = 0;
sc.AutoLoop = true;
sc.GraphRegion = 0;
    sc.ValueFormat = 4;
    sc.MaintainAdditionalChartDataArrays = 1;    
    sc.CalculationPrecedence = LOW_PREC_LEVEL;    
    
    Line1.Name = "Line 1";
    Line1.DrawStyle = DRAWSTYLE_LINE;
    Line1.PrimaryColor = COLOR_CYAN;
    Line1.DrawZeros = false;
  
   PathAndFile.Name = "Path and Filename";
    PathAndFile.SetPathAndFileName("");

return;
}

    SCString PathAndFileName = PathAndFile.GetPathAndFileName();
    
    static SCString MyInputString("");
    // has to be static, otherwise the content will be cleared on very next loop

    MyInputString.Format(ReadTextFile(sc, PathAndFileName).GetSubString(ReadTextFile(sc, PathAndFileName).GetLength()-1, 0));
    
    // read the string and convert to float
    Line1[sc.Index] = strtof(MyInputString,NULL);
}

Date Time Of Last Edit: 2022-05-21 01:49:09
[2022-05-21 20:23:38]
Tony - Posts: 518
Hi ertrader,

That would be exactly what I would do, I code as a hobby, not anywhere close to a professional. You must have a high end computer, mine can only handle 250 ms chart update interval:)

Sorry couldn't help, hope other users would have a better solution.

Good luck
[2022-05-21 21:26:19]
User431178 - Posts: 541
I assume your 40ms is the calculation time shown in the studies window?

Use manual looping and only open/read the file once, outside of the main loop.
By using auto loop and structuring the code the way you have, the file is opened/read/closed once for every bar in the chart.

EDIT:
I lied, the file is opened/read/closed twice for every chart bar, as you have two calls to ReadTextFile in this line -

MyInputString.Format(ReadTextFile(sc, PathAndFileName).GetSubString(ReadTextFile(sc, PathAndFileName).GetLength()-1, 0));

Date Time Of Last Edit: 2022-05-22 11:33:39
[2022-05-22 11:42:30]
User431178 - Posts: 541
Here is a modified version, probably not perfect and would certainly need to be modified if the value contained in text file changes.


#include "sierrachart.h"
#include <stdio.h>
#include <stdlib.h>

SCDLLName("ReadLineFromFile")

SCString ReadTextFile(SCStudyInterfaceRef sc, SCString FileLocation)
{
char TextBuffer[1000] = {}; // string size 1k, adjust as needed,
int FileHandle = 1; // File Handle cannot be just an integer numbers, has to be defined first, sc.OpenFile requires int&

//unsigned int *p_BytesRead = new unsigned int(0); // sc.ReadFile() requires unsigned int pointer
// Don't do this, it is not necessary, also, using new without a corresponding delete = memory/resource leak
// see edit below using address of operator (&)

unsigned int bytesRead{ 0 };

sc.OpenFile(FileLocation.GetChars(), n_ACSIL::FILE_MODE_OPEN_EXISTING_FOR_SEQUENTIAL_READING, FileHandle);
sc.ReadFile(FileHandle, TextBuffer, 1000, &bytesRead); // use & operator here
sc.CloseFile(FileHandle);

return TextBuffer;
}

SCSFExport scsf_ReadLineFromFile(SCStudyGraphRef sc)
{
SCSubgraphRef Line1 = sc.Subgraph[0];
SCInputRef PathAndFile = sc.Input[0];

if(sc.SetDefaults)
{
sc.GraphName = "Read Line Value From File";
sc.StudyDescription = "Read Line Value From File";;
sc.DrawZeros = 0;
sc.AutoLoop = 0;
sc.GraphRegion = 0;
sc.ValueFormat = 4;
sc.CalculationPrecedence = LOW_PREC_LEVEL;

Line1.Name = "Line 1";
Line1.DrawStyle = DRAWSTYLE_LINE;
Line1.PrimaryColor = COLOR_CYAN;
Line1.DrawZeros = false;

PathAndFile.Name = "Path and Filename";
PathAndFile.SetPathAndFileName("");

return;
}

float& r_LineValue = sc.GetPersistentFloatFast(0);

if (sc.UpdateStartIndex == 0)
{
r_LineValue = 0.0f;

SCString buffer = ReadTextFile(sc, PathAndFile.GetPathAndFileName());

if (buffer.GetLength() > 0)
{
buffer = buffer.GetSubString(buffer.GetLength() - 1);
r_LineValue = std::strtof(buffer, nullptr);
}
}

for (int index = sc.UpdateStartIndex; index < sc.ArraySize; index++)
Line1[index] = r_LineValue;
}

Testing on chart with 5 days of data, this version had a calculation time of 0ms, whereas the code posted previously had a calculation time of 261ms.
[2022-05-22 18:25:47]
ertrader - Posts: 672
Wow...thank you! Yes, this brings the calculation time down to 0ms. You rock...I really appreciate you updating the code!
Date Time Of Last Edit: 2022-05-22 18:45:40
[2022-05-23 18:04:02]
Tony - Posts: 518
Thanks so much, User431178!

So, I guess the proper way to remove 'EOF' is this, so it doesn't open/read/close text file twice.


MyInputString.Format(ReadTextFile(sc, "C:\\SierraChart\\Data\\MyData.txt"));

MyInputString.Format(MyInputString.GetSubString(MyInputString.GetLength()-1, 0);

You are right, 320k is way too big, I don't know why I did that. Thanks for pointing out the */& issue.
Date Time Of Last Edit: 2022-05-24 01:16:55

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account