Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Reading a CSV file into an array
Message
From
30/11/2001 09:03:09
 
 
To
29/11/2001 11:57:12
John Marrone
Bloodstock Research Inc.
Lexington, Kentucky, United States
General information
Forum:
Visual FoxPro
Category:
Other
Miscellaneous
Thread ID:
00587527
Message ID:
00587939
Views:
243
Hi John,

As you may know, in FoxPro there are usually different ways to resolve a problem. Particularly when dealing with data. Here's another approach that seems to be quite fast. On my notebook, it took 1.2 seconds to import a 500KB file containing 1500 fields. A file of 5MB took 12 seconds which shows that there should be no performance degradation when the files are bigger. Should you have really large files, then I suggest you replace FILETOSTR() with LLFFs. Note that the import function is only about 15 lines and uses arrays. Anyway here's the code:
o = NEWOBJECT("ImportCsv","ImportCsv.prg")

*-- with a 500KB file

*-- create some sample data
o.CreateSampleData("c:\temp\test1.txt", 20, 1500) && 20 rows, 1500 fields = 500KB
*-- create the necessary cursors
nTables = o.CreateAllTables(1500, 250, "CURSOR", "CSV", "Fld")
*-- import the file into the different cursors
o.ImportCsv("c:\temp\test1.txt", nTables) && 1.2 seconds

*-- with 5MB file
o.CreateSampleData("c:\temp\test2.txt", 200, 1500) ) && 200 rows, 1500 fields = 5MB
*-- create the necessary cursors
nTables = o.CreateAllTables(1500, 250, "CURSOR", "CSV", "Fld")
o.ImportCsv("c:\temp\test2.txt", nTables) && 12 seconds
And here's the class:
#DEFINE ccCrLf CHR(13)+CHR(10)

DEFINE CLASS ImportCsv AS Custom

   nFieldsPerTable = 249       && number of fields per cursor/table
   cCreateType     = "CURSOR"  && type of table to create (CURSOR or TABLE)
   cTableName      = "CSV"     && prefix of Cursor/Table name e.g. csv001, csv002, etc.
   cFieldName      = "Fld"     && prefix of field names e.g. Fld001, Fld002, etc.   
   cFieldDelimiter = ["]       && field delimiter for character strings

   ************************************************
   PROCEDURE ImportCsv
   ************************************************
   LPARAMETERS tcInputFile, tnTables

   WITH This

      LOCAL lnRows

      lnRows = ALINES(laRecords, FILETOSTR(tcInputFile))

      IF lnRows = 0
         RETURN .f.
      ENDIF

      FOR lnRow = 1 TO lnRows
         *-- get record and remove field delimiters
         lcRecord = CHRTRAN(laRecords[lnRow], .cFieldDelimiter, "")
         *-- put record into an array
         lnFields = ALINES(laFields, STRTRAN(lcRecord, ",", ccCrLf))
         *-- get the number of remaining fields for the last table
         lnRemainingFields = MOD(lnFields, .nFieldsPerTable)
         lnFieldsForLastTable = IIF(lnRemainingFields = 0, .nFieldsPerTable, lnRemainingFields)

         *-- split record over several tables
         FOR lnTable = 1 TO tnTables
            lnFieldCount = IIF(lnTable = tnTables, lnFieldsForLastTable, .nFieldsPerTable)
            DIMENSION laRecord[lnFieldCount]
            ACOPY(laFields, laRecord, (lnTable-1) * .nFieldsPerTable+ 1, lnFieldCount, 1)
            INSERT INTO (.cTableName + PADL(lnTable, 3, "0")) FROM ARRAY laRecord
         ENDFOR

      ENDFOR

   ENDWITH

   *-- EOF Method ImportCsv ---------------------------------------------------------------------------------

   ************************************************
   PROCEDURE CreateTable
   ************************************************
   LPARAMETERS tcName, tcType, tnFields

   lcCreateCommand = "CREATE " + tcType + " " + tcName + " (;" + ccCrLf

   FOR i = 1 TO tnFields
      lcCreateCommand = lcCreateCommand + "cField" + PADL(i, 3, "0") + " C(30),"
   ENDFOR &&* i = 1 TO tnFields

   lcCreateCommand = LEFT(lcCreateCommand, LEN(lcCreateCommand)-1) + ")"

   RETURN lcCreateCommand

   *-- EOF Method CreateTable -------------------------------------------------------------------------------

   ************************************************
   PROCEDURE CreateAllTables
   ************************************************
   LPARAMETERS tnTotalFields, tnFieldsPerTable, tcCreateType, tcTableName, tcFieldName

   LOCAL lnTables, i, lnFieldCount, lcCommand, lcTempFile

   lnTables = CEILING(tnTotalFields/tnFieldsPerTable)
   lnFieldCountForLastTable = MOD(tnTotalFields, tnFieldsPerTable)
   lnFieldCountForLastTable = IIF(lnFieldCountForLastTable = 0, tnFieldsPerTable, lnFieldCountForLastTable)

   FOR i = 1 TO lnTables
      lnFieldCount = IIF(i=lnTables, lnFieldCountForLastTable, tnFieldsPerTable)
      lcCommand = This.CreateTable(tcTableName + PADL(i, 3, "0"), tcCreateType, lnFieldCount)
      lcTempFile = AddBs(SYS(2023)) + "A" + RIGHT(SYS(3), 7) + ".TMP"
      STRTOFILE(lcCommand, lcTempFile)
      COMPILE(lcTempFile)
      DO (lcTempFile)
      IF FILE(lcTempFile)
         DELETE FILE (FORCEEXT(lcTempFile, "*"))
      ENDIF  
   ENDFOR &&* i = 1 TO tnTotalFields/250
   *-- update properties

   WITH This
      .nFieldsPerTable = tnFieldsPerTable
      .cCreateType     = tcCreateType
      .cTableName      = tcTableName
      .cFieldName      = tcFieldName
   ENDWITH

   RETURN lnTables

   *-- EOF Method CreateAllTables ---------------------------------------------------------------------------

   ************************************************
   PROCEDURE CreateSampleData
   ************************************************
   LPARAMETERS tcOutputFile, tnRows, tnFields

   LOCAL lnRow, lcFile, lcRecord, lnField

   lcFile = ""
   lcRecord = ""

   FOR lnRow = 1 TO tnRows

      FOR lnField = 1 TO tnFields
          lcRecord = lcRecord + ["] + "Field" + PADL(lnField, 4, "0") + " Row" + PADL(lnRow, 4, "0") + [",]
      ENDFOR
      lcFile = lcFile + LEFT(lcRecord, LEN(lcRecord)-1) + CHR(13)+CHR(10)
      lcRecord = ""
   ENDFOR

   STRTOFILE(lcFile, tcOutputFile)

   *-- EOF Method CreateSampleData --------------------------------------------------------------------------

ENDDEFINE
>I need to read a comma seperated text file with quotes around strings.
>Each record has 1500 fields. Since VFW tables can have only 255 fields I
>need to read this file I quess byte by byte into an array, then assign to
>different tables the data I need. Could someone explain to me the best way
>to do this. I did it by useing FileToStr and then did a substr loop to read
>each character and pharsed the filethat way. It took forever to complete the
>process. The average file is about 500k. Thank you in advance for any help.
>I am starting a very data intensive project that will proably take over a year
>todo. I can do this easlie in VB. But don't know the best way in VFW.
>
>Thanks
>John Marrone
>Bloodstock Research Inc.
>jmarrone@brisnet.com
Daniel
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform