Welcome to our new forum
All users of the legacy CODESYS Forums, please create a new account at account.codesys.com. But make sure to use the same E-Mail address as in the old Forum. Then your posts will be matched. Close

reading string from file issue (more than 255 bytes)

mikeardy
2018-04-04
2023-08-02
  • mikeardy - 2018-04-04

    Hi,
    I'm trying to read strings from file.
    The file is organized in this way:

    [CONFIG FILE]
    Value A=xxxxx
    Value B=xxxxx
    Value C=xxxxx
    Value D=xxxxx
    Value E=xxxxx
    Value F=xxxxx
    and so on...
    

    The total length of the file is about 600 bytes.
    The file is written by part of the same application in CODESYS. The writing process goes right.
    The issue happens when the reading routine starts.
    The code I used is the following:

    PROGRAM ConfigFileLoad
    VAR
       sFileName       : CAA.FILENAME;
       FileOpen       : File.Open;
       FileClose      : File.Close;
       FileRead      : File.Read;
       iState         : UINT;   
       hfile         : CAA.HANDLE;
       sReadLine      : STRING(1000);   
    END_VAR
    VAR_INPUT
       xInit         : BOOL;
    END_VAR
    VAR_OUTPUT
       xError         : BOOL;
       xDone         : BOOL;   
    END_VAR
       CASE iState OF
         0: 
          sFileName := '/configfile.cfg';
          xDone := FALSE;
          xError := FALSE;
          iState:= 3;
       
       3: // Open the file with read access.
          FileOpen(xExecute:= TRUE, sFileName:= sFileName, xExclusive:= FALSE, eFileMode:= File.MODE.MREAD);
          IF FileOpen.xDone = TRUE THEN
             hfile := FileOpen.hFile;
             FileOpen(xExecute:= FALSE);
             iState := 4;
          ELSIF FileOpen.xError = TRUE THEN
             iState:= 32767;
             FileOpen(xExecute:= FALSE);
          END_IF
       
       4: // Read the string from the file.
          FileRead(xExecute:= TRUE, hFile:= hfile, pBuffer:= ADR(sReadLine), szBuffer:= SIZEOF(sReadLine));
          IF FileRead.xDone = TRUE THEN
             iState := 5;
             // Cut off the unused characters.
             //sReadLine := MID(sReadLine, ANY_TO_INT(FileRead.szSize), 1);
             FileRead(xExecute:= FALSE);
          ELSIF FileRead.xError = TRUE THEN
             iState:= 32767;
             FileRead(xExecute:= FALSE);
          END_IF
          
       5: // Close that file.
          FileClose(xExecute:= TRUE, hFile:= hfile);
          IF FileClose.xDone = TRUE THEN
             iState:= 6;
             FileClose(xExecute:= FALSE);
          ELSIF FileClose.xError = TRUE THEN
             iState:= 32767;
             FileClose(xExecute:= FALSE);
          END_IF
       
       6: // extract values
       
       [......]
    

    At the step 4:

       4: // Read the string from the file.
          FileRead(xExecute:= TRUE, hFile:= hfile, pBuffer:= ADR(sReadLine), szBuffer:= SIZEOF(sReadLine));
    

    the function FileRead seems to return into sReadLine a string 266 bytes long and no other. All the remaining bytes are lost. The string sReadline is defined like

    sReadLine      : STRING(1000);   
    

    I expect to read a total bytes of 1000.
    Could someone help me to solve the reading issue?
    Many thanks.

     
  • Lo5tNet - 2018-04-04

    Nothing sticks out based off the information you have here. I see you have MID commented out which is only a string of 255 and you should look at using StrMidA in the StringUtils library.

    What does the buffer equal after read is complete? Have you tried increasing sReadLine to STRING(2000) and see if you get more back?

     
  • mikeardy - 2018-04-04

    The issue is around FileRead function: the function does not return a string longer than 255 bytes.

    Actually, I'm trying to solve the problem using file position pointer reading byte per byte and generating substring less than 255 bytes long. I will post code as soon as I tested it... could be useful for others

     
  • Lo5tNet - 2018-04-04

    I think you are going the wrong direction.

    The File.Read doesn't have a limit besides the size of the buffer. I have multiple applications that read well over 255 (closer to 1600) and you said even yours returns over 255 (266 to be exact) so not sure why you have come up with that assumption.

    Any of the string functions built into the STANDARD library (LEN, MID, FIND, REPLACE, LEFT, RIGHT, ....) have a limit of 255 and that is one reason you should use the STRING UTIL library. Also from what has been said on the forums the STRING UTIL library is much quicker.

    Hope you find an answer either way but reading byte for byte sounds slow.

     
  • mikeardy - 2018-04-04

    At this point, I think you are right.
    Could you post some piece of code to better understand what you are saying me?

     
  • Lo5tNet - 2018-04-04

    Mine looks very similar to yours. I would still be interested in seeing the output of sReadLine to see if it is reading the whole file at state 5 before you hit state 6. The difference of mine is I am looking for Unicode characters (16bit) instead of ANSI characters(8bit) since the files i'm reading can be in many different languages.

    To extract data from the buffer you would use something like (Not Tested but hopefully gives you the idea):

    VAR
        sValueDelimiter: STRING := '=';
        sNewLineDelimiter: STRING := '$r$n';
        nBufferLength: DINT;
        nValueLocation: INT;
        nNewLineStart: INT;
        ExtractedValue: STRING;
    END_VAR
    //Find the length of buffer (Replaces LEN)
        nBufferLength:= StrLenA(pstData:= ADR(sReadLine));
    //Locate the equals sign to separate the data from the label (Replaces FIND)
        nValueLocation:= StrFindA(pst1:= ADR(sReadLine), pst2:= (sValueDelimiter), uiSearchStart:= 1);
        
    //Locate end of line to know how long the data field is (Replaces FIND) (If you have [CONFIG FILE] written in the file you will need to cycle past this first before going to StrMidA)
        nNewLineStart:= StrFindA(pst1:= ADR(sReadLine), pst2:= (sNewLineDelimiter), uiSearchStart:= 1);
        
    //Extract the data from the buffer and place it in variable ExtractedValue (Replaces MID/LEFT/RIGHT)
        StrMidA(pwst:= ADR(sReadLine), uiInputBufferSize:= (SIZEOF(sReadLine), iLength:= (nNewLineStart - nValueLocation), iPosition:= nValueLocation, pwstResult:= 
        ADR(ExtractedValue), uiResultBufferSize:= SIZEOF(ExtractedValue)));
        
    //Delete extracted data from the buffer (Replaces Delete) (Not needed but I do this to create a loop out of the first parts)
        StrDeleteA(pwd:= ADR(sReadLine), iLength:= nNewLineStart + 1, iPosition:= 1);
    
     
  • mikeardy - 2018-04-05

    I like your solution! It's quite similar to mine previous. Where can I found the library you used for this application? I don't found into the library repository.
    Thanks

     
  • Lo5tNet - 2018-04-05

    I find mine in "Library Manager->Add Library->Advanced->Intern->Utils" and choose StringUtils. Or once you are on the advanced screen just search for StringUtils.

     
  • mikeardy - 2018-04-05

    IT PERFECTLY WORKS!
    Thank you!

     
    • master-student - 2022-06-29

      Hi, I am having a similar issue. I need to get readings from a temp sensor and make a string by opening and reading a file. it seems you already got the solution for a similar issue. Could you may be share the code you made please?. That would be very helpful.
      Thanks

       
  • kishan - 2023-08-02

    i have same issue with string(8000000) when i using string utility it not extract all file.
    in side txt file there is 67000 lines but after extracting using string utility i just get 3700 lines
    is there any limits in string util lib.

     

Log in to post a comment.