📄 qgsdelimitedtextprovider.cpp
字号:
/*************************************************************************** qgsdelimitedtextprovider.cpp - Data provider for delimted text ------------------- begin : 2004-02-27 copyright : (C) 2004 by Gary E.Sherman email : sherman at mrcc.com ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//* $Id: qgsdelimitedtextprovider.cpp 7452 2007-11-18 09:35:31Z g_j_m $ */#include "qgsdelimitedtextprovider.h"#include <QtGlobal>#include <QFile>#include <QDataStream>#include <QTextStream>#include <QStringList>#include <QMessageBox>#include <QSettings>#include <QRegExp>#include <QUrl>#include "qgsapplication.h"#include "qgsdataprovider.h"#include "qgsfeature.h"#include "qgsfield.h"#include "qgslogger.h"#include "qgsmessageoutput.h"#include "qgsrect.h"#include "qgsspatialrefsys.h"#include "qgis.h"static const QString TEXT_PROVIDER_KEY = "delimitedtext";static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri) : QgsVectorDataProvider(uri), mXFieldIndex(-1), mYFieldIndex(-1), mShowInvalidLines(true){ // Get the file name and mDelimiter out of the uri mFileName = uri.left(uri.find("?")); // split the string up on & to get the individual parameters QStringList parameters = QStringList::split("&", uri.mid(uri.find("?"))); QgsDebugMsg("Parameter count after split on &" + QString::number(parameters.size())); // get the individual parameters and assign values QStringList temp = parameters.grep("delimiter="); mDelimiter = temp.size()? temp[0].mid(temp[0].find("=") + 1) : ""; temp = parameters.grep("delimiterType="); mDelimiterType = temp.size()? temp[0].mid(temp[0].find("=") + 1) : ""; temp = parameters.grep("xField="); QString xField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : ""; temp = parameters.grep("yField="); QString yField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : ""; // Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance. mFileName = QUrl::fromPercentEncoding(mFileName.toUtf8()); mDelimiter = QUrl::fromPercentEncoding(mDelimiter.toUtf8()); mDelimiterType = QUrl::fromPercentEncoding(mDelimiterType.toUtf8()); xField = QUrl::fromPercentEncoding(xField.toUtf8()); yField = QUrl::fromPercentEncoding(yField.toUtf8()); QgsDebugMsg("Data source uri is " + uri); QgsDebugMsg("Delimited text file is: " + mFileName); QgsDebugMsg("Delimiter is: " + mDelimiter); QgsDebugMsg("Delimiter type is: " + mDelimiterType); QgsDebugMsg("xField is: " + xField); QgsDebugMsg("yField is: " + yField); // if delimiter contains some special characters, convert them if (mDelimiterType == "regexp") mDelimiterRegexp = QRegExp(mDelimiter); else mDelimiter.replace("\\t", "\t"); // replace "\t" with a real tabulator // Set the selection rectangle to null mSelectionRectangle = QgsRect(); // assume the layer is invalid until proven otherwise mValid = false; if (mFileName.isEmpty() || mDelimiter.isEmpty() || xField.isEmpty() || yField.isEmpty()) { // uri is invalid so the layer must be too... QString("Data source is invalid"); return; } // check to see that the file exists and perform some sanity checks if (!QFile::exists(mFileName)) { QgsDebugMsg("Data source " + dataSourceUri() + " doesn't exist"); return; } // Open the file and get number of rows, etc. We assume that the // file has a header row and process accordingly. Caller should make // sure the the delimited file is properly formed. mFile = new QFile(mFileName); if (!mFile->open(QIODevice::ReadOnly)) { QgsDebugMsg("Data source " + dataSourceUri() + " could not be opened"); delete mFile; return; } // now we have the file opened and ready for parsing // set the initial extent mExtent = QgsRect(); QMap<int, bool> couldBeInt; QMap<int, bool> couldBeDouble; mStream = new QTextStream(mFile); QString line; mNumberFeatures = 0; int lineNumber = 0; bool firstPoint = true; bool hasFields = false; while (!mStream->atEnd()) { lineNumber++; line = mStream->readLine(); // line of text excluding '\n', default local 8 bit encoding. if (!hasFields) { // Get the fields from the header row and store them in the // fields vector QgsDebugMsg("Attempting to split the input line: " + line + " using delimiter " + mDelimiter); QStringList fieldList; if (mDelimiterType == "regexp") fieldList = line.split(mDelimiterRegexp); else fieldList = line.split(mDelimiter); QgsDebugMsg("Split line into " + QString::number(fieldList.size()) + " parts"); // We don't know anything about a text based field other // than its name. All fields are assumed to be text int fieldPos = 0; for (QStringList::Iterator it = fieldList.begin(); it != fieldList.end(); ++it) { QString field = *it; if (field.length() > 0) { // for now, let's set field type as text attributeFields[fieldPos] = QgsField(*it, QVariant::String, "Text"); // check to see if this field matches either the x or y field if (xField == *it) { QgsDebugMsg("Found x field: " + (*it)); mXFieldIndex = fieldPos; } else if (yField == *it) { QgsDebugMsg("Found y field: " + (*it)); mYFieldIndex = fieldPos; } QgsDebugMsg("Adding field: " + (*it)); // assume that the field could be integer or double couldBeInt.insert(fieldPos, true); couldBeDouble.insert(fieldPos, true); fieldPos++; } } QgsDebugMsg("Field count for the delimited text file is " + QString::number(attributeFields.size())); hasFields = true; } else if (mXFieldIndex != -1 && mYFieldIndex != -1) { mNumberFeatures++; // split the line on the delimiter QStringList parts; if (mDelimiterType == "regexp") parts = line.split(mDelimiterRegexp); else parts = line.split(mDelimiter); // Skip malformed lines silently. Report line number with getNextFeature() if (attributeFields.size() != parts.size()) { continue; } // Get the x and y values, first checking to make sure they // aren't null. QString sX = parts[mXFieldIndex]; QString sY = parts[mYFieldIndex]; bool xOk = true; bool yOk = true; double x = sX.toDouble(&xOk); double y = sY.toDouble(&yOk); if (xOk && yOk) { if (!firstPoint) { mExtent.combineExtentWith(x,y); } else { // Extent for the first point is just the first point mExtent.set(x,y,x,y); firstPoint = false; } } int i = 0; for (QStringList::iterator it = parts.begin(); it != parts.end(); ++it, ++i) { // try to convert attribute values to integer and double if (couldBeInt[i]) { it->toInt(&couldBeInt[i]); } if (couldBeDouble[i]) { it->toDouble(&couldBeDouble[i]); } } } } // now it's time to decide the types for the fields for (QgsFieldMap::iterator it = attributeFields.begin(); it != attributeFields.end(); ++it) { if (couldBeInt[it.key()]) { it->setType(QVariant::Int); it->setTypeName("integer"); } else if (couldBeDouble[it.key()]) { it->setType(QVariant::Double); it->setTypeName("double"); } } if (mXFieldIndex != -1 && mYFieldIndex != -1) { QgsDebugMsg("Data store is valid"); QgsDebugMsg("Number of features " + QString::number(mNumberFeatures)); QgsDebugMsg("Extents " + mExtent.stringRep()); mValid = true; } else { QgsDebugMsg("Data store is invalid. Specified x,y fields do not match those in the database"); } QgsDebugMsg("Done checking validity");}QgsDelimitedTextProvider::~QgsDelimitedTextProvider(){ mFile->close(); delete mFile; delete mStream;}QString QgsDelimitedTextProvider::storageType() const{ return "Delimited text file";}bool QgsDelimitedTextProvider::getNextFeature(QgsFeature& feature)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -