📄 csvfileloader.cpp
字号:
/**
*
* @brief Class to load a list of elements from a comma separated value (csv file
*
* Copyright (c) EMCC Software Ltd 2003
* @version 1.0
*/
// INCLUDE FILES
// Class include
#include "csvfileloader.h"
// User includes
#include "csvfileloaderobserver.h"
#include "elementlist.h"
// ================= MEMBER FUNCTIONS =======================
_LIT8(KTxtLineDelimiter, "\n"); // To delimit lines within the CSV file--might not necessarily be just \n!
CCsvFileLoader::CCsvFileLoader(RFs& aFs, CElementList& aElementList, MCsvFileLoaderObserver& aObserver)
: CActive(EPriorityStandard),
iFs(aFs),
iElementList(aElementList),
iObserver(aObserver)
{
}
CCsvFileLoader::~CCsvFileLoader()
{
Cancel(); // All AOs should cancel when they are deleted
iFile.Close();
iTimeWaster.Close();
}
void CCsvFileLoader::ConstructL(const TDesC& aFileName)
{
iFileName = aFileName;
User::LeaveIfError(iFile.Open(iFs, iFileName, EFileRead));
User::LeaveIfError(iTimeWaster.CreateLocal());
CActiveScheduler::Add(this); // Not done automatically!
}
CCsvFileLoader* CCsvFileLoader::NewLC(RFs& aFs, CElementList& aElementList, MCsvFileLoaderObserver& aObserver,
const TDesC& aFileName)
{
CCsvFileLoader* self = new (ELeave) CCsvFileLoader(aFs, aElementList, aObserver);
CleanupStack::PushL(self);
self->ConstructL(aFileName);
return self;
}
CCsvFileLoader* CCsvFileLoader::NewL(RFs& aFs, CElementList& aElementList, MCsvFileLoaderObserver& aObserver,
const TDesC& aFileName)
{
CCsvFileLoader* self = CCsvFileLoader::NewLC(aFs, aElementList, aObserver, aFileName);
CleanupStack::Pop(self);
return self;
}
void CCsvFileLoader::DoCancel()
{
if (iWastingTime || !iHaveTriedToLoad)
{
iTimeWaster.Cancel();
}
//Cannot cancel a file read!
}
void CCsvFileLoader::Start()
{
iFilePos = 0; //Just in case this isn't the first time round!
iHaveTriedToLoad = EFalse; //I want to start with a random wait first rather than a load (for the purposes of
//this example). Hence I need a way of telling RunL() that the reason there's nothing
//in the buffer first time round is that we haven't tried to load anything yet!
//Wait for a randomish amount of time before doing anything else
TInt delay = (iFileName.Size() % 10) * 100000; //"random" enough!
iTimeWaster.After(iStatus, delay);
SetActive();
}
void CCsvFileLoader::FillReadBufferL()
{
iHaveTriedToLoad = ETrue; // Only check readbuffer size in RunL() if we've tried loading before!
// Seek to current file position. We're not bothered if this is past the EOF,
// in that case Read() returns a zero-sized descriptor via iReadBuffer(), tested in RunL().
User::LeaveIfError(iFile.Seek(ESeekStart, iFilePos));
//R ead from the file into the buffer. iStatus will be completed by the fileserver once done.
iFile.Read(iReadBuffer, iReadBuffer.MaxSize(), iStatus);
SetActive();
}
TPtrC8 CCsvFileLoader::ExtractToNewLineL(const TDesC8& aBuffer) const
{
//Search for the line delimiter within the buffer
TInt foundPos = aBuffer.Find(KTxtLineDelimiter);
if (foundPos < 0)
{
//End of line not found--malformed csv file?
User::Leave(KErrGeneral);
}
//return an immutable pointer descriptor to the leftmost portion up to the delimiter location
return aBuffer.Left(foundPos);
}
void CCsvFileLoader::RunL()
//RunL is called on completion of the iStatus member, i.e. when the asynchronous request has finished
//(whether successfully or not)
{
if (!iHaveTriedToLoad)
{
//Fill the read buffer if we haven't yet tried to do so...
FillReadBufferL();
return;
}
if ((iStatus.Int() != KErrNone) || (iReadBuffer.Size() == 0))
{
//An error has occurred, or the buffer contained no data hence reading is complete. In either case,
//return the error code (which will be KErrNone if reading has completed) to the observer.
iObserver.NotifyLoadCompleted(iStatus.Int(), *this);
return;
}
//This code is added simply to demonstrate the asynchronous behaviour more clearly, since without it
//the file loading will happen so quickly that no other active object of the same or lower priority
//than this is ever likely to get a look in...
//Comment it out if you like. If so, you'll notice that the first instance of this class added to the
//scheduler will "hog" it, executing every time around the scheduler's wait loop until it is fully
//complete. Pausing a random amount of time allows other active objects to have a look in whilst this
//instance awaits completion of the timer.
if (iWastingTime)
{
//Just wait a randomish amount of time
TInt delay = (iFilePos % 10) * 100000;
iTimeWaster.After(iStatus, delay);
SetActive();
iWastingTime = EFalse; //Don't waste time next time around!
return;
}
//Extract and convert the buffer
TPtrC8 elementBuf8 = ExtractToNewLineL(iReadBuffer);
HBufC* elementBuf16 = HBufC::NewLC(elementBuf8.Length()); //elementBuf16 left on cleanup stack
TPtr elementPtr16 = elementBuf16->Des();
elementPtr16.Copy(elementBuf8); //Copy the 8 bit buffer to the 16 bit buffer, with alternate zero padding
//(i.e. convert from ASCII to UNICODE!)
//Read the element from the buffer
iElementList.AppendL(*elementBuf16); //(could equally well have used elementPtr16)
//Report the element that's just been loaded to the observer
TInt lastElementLoadedIndex = iElementList.NumberOfElements() - 1; //-1 since zero based index!
iObserver.NotifyElementLoaded(lastElementLoadedIndex);
//Increment the file position
iFilePos += elementBuf16->Length() + KTxtLineDelimiter().Length(); //Start next read from after the newline
//NB the use of overloaded () operator
//to cast a TLitC to a TDesC
//Re-issue the request
FillReadBufferL();
//Cleanup
CleanupStack::PopAndDestroy(elementBuf16);
//Waste some time next time round before processing the file input (see comment earlier)...
iWastingTime = ETrue;
}
TInt CCsvFileLoader::RunError(TInt aError)
//This function is called if a leave occurs during RunL(). aError is the leave code. If the leave is
//unhandled, then RunError() should return the leavecode for handling by the active scheduler,
//otherwise it must return KErrNone
{
//Notify the observer of the error
iObserver.NotifyLoadCompleted(aError, *this);
return KErrNone; //KErrNone indicates we have dealt with the error so the scheduler won't panic
}
// End of File
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -