📄 cpl_csv.cpp
字号:
/************************************************************************//* CSVFindNextLine() *//* *//* Find the start of the next line, while at the same time zero *//* terminating this line. Take into account that there may be *//* newline indicators within quoted strings, and that quotes *//* can be escaped with a backslash. *//************************************************************************/static char *CSVFindNextLine( char *pszThisLine ){ int nQuoteCount = 0, i; for( i = 0; pszThisLine[i] != '\0'; i++ ) { if( pszThisLine[i] == '\"' && (i == 0 || pszThisLine[i-1] != '\\') ) nQuoteCount++; if( (pszThisLine[i] == 10 || pszThisLine[i] == 13) && (nQuoteCount % 2) == 0 ) break; } while( pszThisLine[i] == 10 || pszThisLine[i] == 13 ) pszThisLine[i++] = '\0'; if( pszThisLine[i] == '\0' ) return NULL; else return pszThisLine + i;}/************************************************************************//* CSVIngest() *//* *//* Load entire file into memory and setup index if possible. *//************************************************************************/static void CSVIngest( const char *pszFilename ){ CSVTable *psTable = CSVAccess( pszFilename ); int nFileLen, i, nMaxLineCount, iLine = 0; char *pszThisLine; if( psTable->pszRawData != NULL ) return;/* -------------------------------------------------------------------- *//* Ingest whole file. *//* -------------------------------------------------------------------- */ VSIFSeek( psTable->fp, 0, SEEK_END ); nFileLen = VSIFTell( psTable->fp ); VSIRewind( psTable->fp ); psTable->pszRawData = (char *) CPLMalloc(nFileLen+1); if( (int) VSIFRead( psTable->pszRawData, 1, nFileLen, psTable->fp ) != nFileLen ) { CPLFree( psTable->pszRawData ); psTable->pszRawData = NULL; CPLError( CE_Failure, CPLE_FileIO, "Read of file %s failed.", psTable->pszFilename ); return; } psTable->pszRawData[nFileLen] = '\0';/* -------------------------------------------------------------------- *//* Get count of newlines so we can allocate line array. *//* -------------------------------------------------------------------- */ nMaxLineCount = 0; for( i = 0; i < nFileLen; i++ ) { if( psTable->pszRawData[i] == 10 ) nMaxLineCount++; } psTable->papszLines = (char **) CPLCalloc(sizeof(char*),nMaxLineCount); /* -------------------------------------------------------------------- *//* Build a list of record pointers into the raw data buffer *//* based on line terminators. Zero terminate the line *//* strings. *//* -------------------------------------------------------------------- */ /* skip header line */ pszThisLine = CSVFindNextLine( psTable->pszRawData ); while( pszThisLine != NULL && iLine < nMaxLineCount ) { psTable->papszLines[iLine++] = pszThisLine; pszThisLine = CSVFindNextLine( pszThisLine ); } psTable->nLineCount = iLine;/* -------------------------------------------------------------------- *//* Allocate and populate index array. Ensure they are in *//* ascending order so that binary searches can be done on the *//* array. *//* -------------------------------------------------------------------- */ psTable->panLineIndex = (int *) CPLMalloc(sizeof(int)*psTable->nLineCount); for( i = 0; i < psTable->nLineCount; i++ ) { psTable->panLineIndex[i] = atoi(psTable->papszLines[i]); if( i > 0 && psTable->panLineIndex[i] < psTable->panLineIndex[i-1] ) { CPLFree( psTable->panLineIndex ); psTable->panLineIndex = NULL; break; } } psTable->iLastLine = -1;/* -------------------------------------------------------------------- *//* We should never need the file handle against, so close it. *//* -------------------------------------------------------------------- */ VSIFClose( psTable->fp ); psTable->fp = NULL;}/************************************************************************//* CSVReadParseLine() *//* *//* Read one line, and return split into fields. The return *//* result is a stringlist, in the sense of the CSL functions. *//************************************************************************/char **CSVReadParseLine( FILE * fp ){ const char *pszLine; char *pszWorkLine; char **papszReturn; CPLAssert( fp != NULL ); if( fp == NULL ) return( NULL ); pszLine = CPLReadLine( fp ); if( pszLine == NULL ) return( NULL );/* -------------------------------------------------------------------- *//* If there are no quotes, then this is the simple case. *//* Parse, and return tokens. *//* -------------------------------------------------------------------- */ if( strchr(pszLine,'\"') == NULL ) return CSVSplitLine( pszLine );/* -------------------------------------------------------------------- *//* We must now count the quotes in our working string, and as *//* long as it is odd, keep adding new lines. *//* -------------------------------------------------------------------- */ pszWorkLine = CPLStrdup( pszLine ); while( TRUE ) { int i, nCount = 0; for( i = 0; pszWorkLine[i] != '\0'; i++ ) { if( pszWorkLine[i] == '\"' && (i == 0 || pszWorkLine[i-1] != '\\') ) nCount++; } if( nCount % 2 == 0 ) break; pszLine = CPLReadLine( fp ); if( pszLine == NULL ) break; pszWorkLine = (char *) CPLRealloc(pszWorkLine, strlen(pszWorkLine) + strlen(pszLine) + 2); strcat( pszWorkLine, "\n" ); // This gets lost in CPLReadLine(). strcat( pszWorkLine, pszLine ); } papszReturn = CSVSplitLine( pszWorkLine ); CPLFree( pszWorkLine ); return papszReturn;}/************************************************************************//* CSVCompare() *//* *//* Compare a field to a search value using a particular *//* criteria. *//************************************************************************/static int CSVCompare( const char * pszFieldValue, const char * pszTarget, CSVCompareCriteria eCriteria ){ if( eCriteria == CC_ExactString ) { return( strcmp( pszFieldValue, pszTarget ) == 0 ); } else if( eCriteria == CC_ApproxString ) { return( EQUAL( pszFieldValue, pszTarget ) ); } else if( eCriteria == CC_Integer ) { return( atoi(pszFieldValue) == atoi(pszTarget) ); } return FALSE;}/************************************************************************//* CSVScanLines() *//* *//* Read the file scanline for lines where the key field equals *//* the indicated value with the suggested comparison criteria. *//* Return the first matching line split into fields. *//************************************************************************/char **CSVScanLines( FILE *fp, int iKeyField, const char * pszValue, CSVCompareCriteria eCriteria ){ char **papszFields = NULL; int bSelected = FALSE, nTestValue; CPLAssert( pszValue != NULL ); CPLAssert( iKeyField >= 0 ); CPLAssert( fp != NULL ); nTestValue = atoi(pszValue); while( !bSelected ) { papszFields = CSVReadParseLine( fp ); if( papszFields == NULL ) return( NULL ); if( CSLCount( papszFields ) < iKeyField+1 ) { /* not selected */ } else if( eCriteria == CC_Integer && atoi(papszFields[iKeyField]) == nTestValue ) { bSelected = TRUE; } else { bSelected = CSVCompare( papszFields[iKeyField], pszValue, eCriteria ); } if( !bSelected ) { CSLDestroy( papszFields ); papszFields = NULL; } } return( papszFields );}/************************************************************************//* CSVScanLinesIndexed() *//* *//* Read the file scanline for lines where the key field equals *//* the indicated value with the suggested comparison criteria. *//* Return the first matching line split into fields. *//************************************************************************/static char **CSVScanLinesIndexed( CSVTable *psTable, int nKeyValue ){ int iTop, iBottom, iMiddle, iResult = -1; CPLAssert( psTable->panLineIndex != NULL );/* -------------------------------------------------------------------- *//* Find target record with binary search. *//* -------------------------------------------------------------------- */ iTop = psTable->nLineCount-1; iBottom = 0; while( iTop >= iBottom ) { iMiddle = (iTop + iBottom) / 2; if( psTable->panLineIndex[iMiddle] > nKeyValue ) iTop = iMiddle - 1; else if( psTable->panLineIndex[iMiddle] < nKeyValue ) iBottom = iMiddle + 1; else { iResult = iMiddle; break; } } if( iResult == -1 ) return NULL;/* -------------------------------------------------------------------- *//* Parse target line, and update iLastLine indicator. *//* -------------------------------------------------------------------- */ psTable->iLastLine = iResult; return CSVSplitLine( psTable->papszLines[iResult] );}/************************************************************************//* CSVScanLinesIngested() *//* *//* Read the file scanline for lines where the key field equals *//* the indicated value with the suggested comparison criteria. *//* Return the first matching line split into fields. *//************************************************************************/static char **CSVScanLinesIngested( CSVTable *psTable, int iKeyField, const char * pszValue, CSVCompareCriteria eCriteria ){ char **papszFields = NULL; int bSelected = FALSE, nTestValue; CPLAssert( pszValue != NULL ); CPLAssert( iKeyField >= 0 ); nTestValue = atoi(pszValue); /* -------------------------------------------------------------------- *//* Short cut for indexed files. *//* -------------------------------------------------------------------- */ if( iKeyField == 0 && eCriteria == CC_Integer && psTable->panLineIndex != NULL ) return CSVScanLinesIndexed( psTable, nTestValue ); /* -------------------------------------------------------------------- *//* Scan from in-core lines. *//* -------------------------------------------------------------------- */ while( !bSelected && psTable->iLastLine+1 < psTable->nLineCount ) { psTable->iLastLine++; papszFields = CSVSplitLine( psTable->papszLines[psTable->iLastLine] ); if( CSLCount( papszFields ) < iKeyField+1 ) { /* not selected */ } else if( eCriteria == CC_Integer && atoi(papszFields[iKeyField]) == nTestValue ) { bSelected = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -