QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
qgsfileutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfileutils.cpp
3 ---------------------
4 begin : November 2017
5 copyright : (C) 2017 by Etienne Trimaille
6 email : etienne.trimaille at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include "qgsconfig.h"
16#include "qgsfileutils.h"
17
18#include "qgis.h"
19#include "qgsexception.h"
20#include "qgslogger.h"
21#include "qgsprovidermetadata.h"
22#include "qgsproviderregistry.h"
23
24#include <QDir>
25#include <QDirIterator>
26#include <QFileInfo>
27#include <QObject>
28#include <QRegularExpression>
29#include <QSet>
30#include <QString>
31
32#include "moc_qgsfileutils.cpp"
33
34using namespace Qt::StringLiterals;
35
36#ifdef Q_OS_UNIX
37// For getrlimit()
38#include <sys/resource.h>
39#include <sys/time.h>
40#include <dirent.h>
41#endif
42
43#ifdef _MSC_VER
44#include <Windows.h>
45#include <ShlObj.h>
46#pragma comment( lib, "Shell32.lib" )
47#endif
48
49QString QgsFileUtils::representFileSize( qint64 bytes )
50{
51 QStringList list;
52 list << QObject::tr( "KB" ) << QObject::tr( "MB" ) << QObject::tr( "GB" ) << QObject::tr( "TB" );
53
54 QStringListIterator i( list );
55 QString unit = QObject::tr( "B" );
56
57 double fileSize = bytes;
58 while ( fileSize >= 1024.0 && i.hasNext() )
59 {
60 fileSize /= 1024.0;
61 unit = i.next();
62 }
63 return u"%1 %2"_s.arg( QString::number( fileSize, 'f', bytes >= 1048576 ? 2 : 0 ), unit );
64}
65
66QStringList QgsFileUtils::extensionsFromFilter( const QString &filter )
67{
68 const thread_local QRegularExpression rx( u"\\*\\.([a-zA-Z0-9\\.]+)"_s );
69 QStringList extensions;
70 QRegularExpressionMatchIterator matches = rx.globalMatch( filter );
71
72 while ( matches.hasNext() )
73 {
74 const QRegularExpressionMatch match = matches.next();
75 if ( match.hasMatch() )
76 {
77 QStringList newExtensions = match.capturedTexts();
78 newExtensions.pop_front(); // remove whole match
79 extensions.append( newExtensions );
80 }
81 }
82 return extensions;
83}
84
85QString QgsFileUtils::wildcardsFromFilter( const QString &filter )
86{
87 const thread_local QRegularExpression globPatternsRx( u".*\\((.*?)\\)$"_s );
88 const QRegularExpressionMatch matches = globPatternsRx.match( filter );
89 if ( matches.hasMatch() )
90 return matches.captured( 1 );
91 else
92 return QString();
93}
94
95bool QgsFileUtils::fileMatchesFilter( const QString &fileName, const QString &filter )
96{
97 QFileInfo fi( fileName );
98 const QString name = fi.fileName();
99 const QStringList parts = filter.split( u";;"_s );
100 for ( const QString &part : parts )
101 {
102 const QStringList globPatterns = wildcardsFromFilter( part ).split( ' ', Qt::SkipEmptyParts );
103 for ( const QString &glob : globPatterns )
104 {
105 const QString re = QRegularExpression::wildcardToRegularExpression( glob );
106
107 const QRegularExpression globRx( re );
108 if ( globRx.match( name ).hasMatch() )
109 return true;
110 }
111 }
112 return false;
113}
114
115QString QgsFileUtils::ensureFileNameHasExtension( const QString &f, const QStringList &extensions )
116{
117 if ( extensions.empty() || f.isEmpty() )
118 return f;
119
120 QString fileName = f;
121 bool hasExt = false;
122 for ( const QString &extension : std::as_const( extensions ) )
123 {
124 const QString extWithDot = extension.startsWith( '.' ) ? extension : '.' + extension;
125 if ( fileName.endsWith( extWithDot, Qt::CaseInsensitive ) )
126 {
127 hasExt = true;
128 break;
129 }
130 }
131
132 if ( !hasExt )
133 {
134 const QString extension = extensions.at( 0 );
135 const QString extWithDot = extension.startsWith( '.' ) ? extension : '.' + extension;
136 fileName += extWithDot;
137 }
138
139 return fileName;
140}
141
142QString QgsFileUtils::addExtensionFromFilter( const QString &fileName, const QString &filter )
143{
144 const QStringList extensions = extensionsFromFilter( filter );
145 return ensureFileNameHasExtension( fileName, extensions );
146}
147
148QString QgsFileUtils::stringToSafeFilename( const QString &string )
149{
150 const thread_local QRegularExpression rx( u"[/\\\\\\?%\\*\\:\\|\"<>]"_s );
151 QString s = string;
152 s.replace( rx, u"_"_s );
153 return s;
154}
155
156QString QgsFileUtils::findClosestExistingPath( const QString &path )
157{
158 if ( path.isEmpty() )
159 return QString();
160
161 QDir currentPath;
162 QFileInfo fi( path );
163 if ( fi.isFile() )
164 currentPath = fi.dir();
165 else
166 currentPath = QDir( path );
167
168 QSet< QString > visited;
169 while ( !currentPath.exists() )
170 {
171 const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + u"/.."_s );
172 if ( visited.contains( parentPath ) )
173 return QString(); // break circular links
174
175 if ( parentPath.isEmpty() || parentPath == "."_L1 )
176 return QString();
177 currentPath = QDir( parentPath );
178 visited << parentPath;
179 }
180
181 const QString res = QDir::cleanPath( currentPath.absolutePath() );
182
183 if ( res == QDir::currentPath() )
184 return QString(); // avoid default to binary folder if a filename alone is specified
185
186 return res == "."_L1 ? QString() : res;
187}
188
189QStringList QgsFileUtils::findFile( const QString &file, const QString &basePath, int maxClimbs, int searchCeilling, const QString &currentDir )
190{
191 int depth = 0;
192 QString originalFolder;
193 QDir folder;
194 const QString fileName( basePath.isEmpty() ? QFileInfo( file ).fileName() : file );
195 const QString baseFolder( basePath.isEmpty() ? QFileInfo( file ).path() : basePath );
196
197 if ( QFileInfo( baseFolder ).isDir() )
198 {
199 folder = QDir( baseFolder );
200 originalFolder = folder.absolutePath();
201 }
202 else // invalid folder or file path
203 {
204 folder = QDir( QFileInfo( baseFolder ).absolutePath() );
205 originalFolder = folder.absolutePath();
206 }
207
208 QStringList searchedFolder = QStringList();
209 QString existingBase;
210 QString backupDirectory = QDir::currentPath();
211 QStringList foundFiles;
212
213 if ( !currentDir.isEmpty() && backupDirectory != currentDir && QDir( currentDir ).exists() )
214 QDir::setCurrent( currentDir );
215
216 // find the nearest existing folder
217 while ( !folder.exists() && folder.absolutePath().count( '/' ) > searchCeilling )
218 {
219 existingBase = folder.path();
220 if ( !folder.cdUp() )
221 folder = QFileInfo( existingBase ).absoluteDir(); // using fileinfo to move up one level
222
223 depth += 1;
224
225 if ( depth > ( maxClimbs + 4 ) ) //break early when no folders can be found
226 break;
227 }
228 bool folderExists = folder.exists();
229
230 if ( depth > maxClimbs )
231 maxClimbs = depth;
232
233 if ( folder.absolutePath().count( '/' ) < searchCeilling )
234 searchCeilling = folder.absolutePath().count( '/' ) - 1;
235
236 while ( depth <= maxClimbs && folderExists && folder.absolutePath().count( '/' ) >= searchCeilling )
237 {
238 QDirIterator localFinder( folder.path(), QStringList() << fileName, QDir::Files, QDirIterator::NoIteratorFlags );
239 searchedFolder.append( folder.absolutePath() );
240 if ( localFinder.hasNext() )
241 {
242 foundFiles << localFinder.next();
243 return foundFiles;
244 }
245
246
247 const QFileInfoList subdirs = folder.entryInfoList( QDir::AllDirs );
248 for ( const QFileInfo &subdir : subdirs )
249 {
250 if ( !searchedFolder.contains( subdir.absolutePath() ) )
251 {
252 QDirIterator subDirFinder( subdir.path(), QStringList() << fileName, QDir::Files, QDirIterator::Subdirectories );
253 if ( subDirFinder.hasNext() )
254 {
255 QString possibleFile = subDirFinder.next();
256 if ( !subDirFinder.hasNext() )
257 {
258 foundFiles << possibleFile;
259 return foundFiles;
260 }
261
262 foundFiles << possibleFile;
263 while ( subDirFinder.hasNext() )
264 {
265 foundFiles << subDirFinder.next();
266 }
267 return foundFiles;
268 }
269 }
270 }
271 depth += 1;
272
273 if ( depth > maxClimbs )
274 break;
275
276 folderExists = folder.cdUp();
277 }
278
279 if ( QDir::currentPath() == currentDir && currentDir != backupDirectory )
280 QDir::setCurrent( backupDirectory );
281
282 return foundFiles;
283}
284
285#ifdef _MSC_VER
286std::unique_ptr< wchar_t[] > pathToWChar( const QString &path )
287{
288 const QString nativePath = QDir::toNativeSeparators( path );
289
290 std::unique_ptr< wchar_t[] > pathArray( new wchar_t[static_cast< uint>( nativePath.length() + 1 )] );
291 nativePath.toWCharArray( pathArray.get() );
292 pathArray[static_cast< size_t >( nativePath.length() )] = 0;
293 return pathArray;
294}
295
296
297void fileAttributesOld( HANDLE handle, DWORD &fileAttributes, bool &hasFileAttributes )
298{
299 hasFileAttributes = false;
300 BY_HANDLE_FILE_INFORMATION info;
301 if ( GetFileInformationByHandle( handle, &info ) )
302 {
303 hasFileAttributes = true;
304 fileAttributes = info.dwFileAttributes;
305 }
306}
307
308// File attributes for Windows starting from version 8.
309void fileAttributesNew( HANDLE handle, DWORD &fileAttributes, bool &hasFileAttributes )
310{
311 hasFileAttributes = false;
312#if WINVER >= 0x0602
313 _FILE_BASIC_INFO infoEx;
314 if ( GetFileInformationByHandleEx( handle, FileBasicInfo, &infoEx, sizeof( infoEx ) ) )
315 {
316 hasFileAttributes = true;
317 fileAttributes = infoEx.FileAttributes;
318 }
319 else
320 {
321 // GetFileInformationByHandleEx() is observed to fail for FAT32, QTBUG-74759
322 fileAttributesOld( handle, fileAttributes, hasFileAttributes );
323 }
324#else
325 fileAttributesOld( handle, fileAttributes, hasFileAttributes );
326#endif
327}
328
329bool pathIsLikelyCloudStorage( QString path )
330{
331 // For OneDrive detection need the attributes of a file from the path, not the directory itself.
332 // So just grab the first file in the path.
333 QDirIterator dirIt( path, QDir::Files );
334 if ( dirIt.hasNext() )
335 {
336 path = dirIt.next();
337 }
338
339 std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
340 const HANDLE handle = CreateFileW( pathArray.get(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr );
341 if ( handle != INVALID_HANDLE_VALUE )
342 {
343 bool hasFileAttributes = false;
344 DWORD attributes = 0;
345 fileAttributesNew( handle, attributes, hasFileAttributes );
346 CloseHandle( handle );
347 if ( hasFileAttributes )
348 {
349 /* From the Win32 API documentation:
350 *
351 * FILE_ATTRIBUTE_RECALL_ON_OPEN:
352 * When this attribute is set, it means that the file or directory has no physical representation
353 * on the local system; the item is virtual. Opening the item will be more expensive than normal,
354 * e.g. it will cause at least some of it to be fetched from a remote store
355 *
356 * FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
357 * When this attribute is set, it means that the file or directory is not fully present locally.
358 * For a file that means that not all of its data is on local storage (e.g. it may be sparse with
359 * some data still in remote storage).
360 */
361 return ( attributes & FILE_ATTRIBUTE_RECALL_ON_OPEN ) || ( attributes & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS );
362 }
363 }
364 return false;
365}
366#endif
367
369{
370#ifdef _MSC_VER
371 auto pathType = []( const QString &path ) -> Qgis::DriveType {
372 std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
373 const UINT type = GetDriveTypeW( pathArray.get() );
374 switch ( type )
375 {
376 case DRIVE_UNKNOWN:
378
379 case DRIVE_NO_ROOT_DIR:
381
382 case DRIVE_REMOVABLE:
384
385 case DRIVE_FIXED:
387
388 case DRIVE_REMOTE:
390
391 case DRIVE_CDROM:
393
394 case DRIVE_RAMDISK:
396 }
397
399 };
400
401 const QString originalPath = QDir::cleanPath( path );
402 QString currentPath = originalPath;
403 QString prevPath;
404 while ( currentPath != prevPath )
405 {
406 if ( pathIsLikelyCloudStorage( currentPath ) )
408
409 prevPath = currentPath;
410 currentPath = QFileInfo( currentPath ).path();
411
412 const Qgis::DriveType type = pathType( currentPath );
413 if ( type != Qgis::DriveType::Unknown && type != Qgis::DriveType::Invalid )
414 return type;
415 }
417
418#else
419 ( void ) path;
420 throw QgsNotSupportedException( u"Determining drive type is not supported on this platform"_s );
421#endif
422}
423
424bool QgsFileUtils::pathIsSlowDevice( const QString &path )
425{
426#ifdef ENABLE_TESTS
427 if ( path.contains( "fake_slow_path_for_unit_tests"_L1 ) )
428 return true;
429#endif
430
431 try
432 {
433 const Qgis::DriveType type = driveType( path );
434 switch ( type )
435 {
440 return false;
441
446 return true;
447 }
448 }
449 catch ( QgsNotSupportedException & )
450 {}
451 return false;
452}
453
454QSet<QString> QgsFileUtils::sidecarFilesForPath( const QString &path )
455{
456 QSet< QString > res;
457 const QStringList providers = QgsProviderRegistry::instance()->providerList();
458 for ( const QString &provider : providers )
459 {
462 {
463 const QStringList possibleSidecars = metadata->sidecarFilesForUri( path );
464 for ( const QString &possibleSidecar : possibleSidecars )
465 {
466 if ( QFile::exists( possibleSidecar ) )
467 res.insert( possibleSidecar );
468 }
469 }
470 }
471 return res;
472}
473
474bool QgsFileUtils::renameDataset( const QString &oldPath, const QString &newPath, QString &error, Qgis::FileOperationFlags flags )
475{
476 if ( !QFile::exists( oldPath ) )
477 {
478 error = QObject::tr( "File does not exist" );
479 return false;
480 }
481
482 const QFileInfo oldPathInfo( oldPath );
483 QSet< QString > sidecars = sidecarFilesForPath( oldPath );
485 {
486 const QString qmdPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + u".qmd"_s );
487 if ( QFile::exists( qmdPath ) )
488 sidecars.insert( qmdPath );
489 }
491 {
492 const QString qmlPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + u".qml"_s );
493 if ( QFile::exists( qmlPath ) )
494 sidecars.insert( qmlPath );
495 }
496
497 const QFileInfo newPathInfo( newPath );
498
499 bool res = true;
500 QStringList errors;
501 errors.reserve( sidecars.size() );
502 // first check if all sidecars CAN be renamed -- we don't want to get partly through the rename and then find a clash
503 for ( const QString &sidecar : std::as_const( sidecars ) )
504 {
505 const QFileInfo sidecarInfo( sidecar );
506 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + '.' + sidecarInfo.suffix() );
507 if ( newSidecarName != sidecar && QFile::exists( newSidecarName ) )
508 {
509 res = false;
510 errors.append( QDir::toNativeSeparators( newSidecarName ) );
511 }
512 }
513 if ( !res )
514 {
515 error = QObject::tr( "Destination files already exist %1" ).arg( errors.join( ", "_L1 ) );
516 return false;
517 }
518
519 if ( !QFile::rename( oldPath, newPath ) )
520 {
521 error = QObject::tr( "Could not rename %1" ).arg( QDir::toNativeSeparators( oldPath ) );
522 return false;
523 }
524
525 for ( const QString &sidecar : std::as_const( sidecars ) )
526 {
527 const QFileInfo sidecarInfo( sidecar );
528 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + '.' + sidecarInfo.suffix() );
529 if ( newSidecarName == sidecar )
530 continue;
531
532 if ( !QFile::rename( sidecar, newSidecarName ) )
533 {
534 errors.append( QDir::toNativeSeparators( sidecar ) );
535 res = false;
536 }
537 }
538 if ( !res )
539 {
540 error = QObject::tr( "Could not rename %1" ).arg( errors.join( ", "_L1 ) );
541 }
542
543 return res;
544}
545
547{
548#ifdef Q_OS_UNIX
549 struct rlimit rescLimit;
550 if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
551 {
552 return rescLimit.rlim_cur;
553 }
554#endif
555 return -1;
556}
557
559{
560#ifdef Q_OS_LINUX
561 int fileCount = 0;
562
563 DIR *dirp = opendir( "/proc/self/fd" );
564 if ( !dirp )
565 return -1;
566
567 while ( struct dirent *entry = readdir( dirp ) )
568 {
569 if ( entry->d_type == DT_REG )
570 {
571 fileCount++;
572 }
573 }
574 closedir( dirp );
575 return fileCount;
576#else
577 return -1;
578#endif
579}
580
582{
583 const int nFileLimit = QgsFileUtils::openedFileLimit();
584 const int nFileCount = QgsFileUtils::openedFileCount();
585 // We need some margin as Qt will crash if it cannot create some file descriptors
586 constexpr int SOME_MARGIN = 20;
587 return nFileCount > 0 && nFileLimit > 0 && nFileCount + filesToBeOpened > nFileLimit - SOME_MARGIN;
588}
589
590QStringList QgsFileUtils::splitPathToComponents( const QString &input )
591{
592 QStringList result;
593 QString path = QDir::cleanPath( input );
594 if ( path.isEmpty() )
595 return result;
596
597 const QString fileName = QFileInfo( path ).fileName();
598 if ( !fileName.isEmpty() )
599 result << fileName;
600 else if ( QFileInfo( path ).path() == path )
601 result << path;
602
603 QString prevPath = path;
604 while ( ( path = QFileInfo( path ).path() ).length() < prevPath.length() )
605 {
606 const QString dirName = QDir( path ).dirName();
607 if ( dirName == "."_L1 )
608 break;
609
610 result << ( !dirName.isEmpty() ? dirName : path );
611 prevPath = path;
612 }
613
614 std::reverse( result.begin(), result.end() );
615 return result;
616}
617
618QString QgsFileUtils::uniquePath( const QString &path )
619{
620 if ( !QFileInfo::exists( path ) )
621 {
622 return path;
623 }
624
625 QFileInfo info { path };
626 const QString suffix { info.completeSuffix() };
627 const QString pathPattern { QString( suffix.isEmpty() ? path : path.chopped( suffix.length() + 1 ) ).append( suffix.isEmpty() ? u"_%1"_s : u"_%1."_s ).append( suffix ) };
628 int i { 2 };
629 QString uniquePath { pathPattern.arg( i ) };
630 while ( QFileInfo::exists( uniquePath ) )
631 {
632 ++i;
633 uniquePath = pathPattern.arg( i );
634 }
635 return uniquePath;
636}
637
638bool QgsFileUtils::copyDirectory( const QString &source, const QString &destination, CopyFlags flags )
639{
640 QDir sourceDir( source );
641 if ( !sourceDir.exists() )
642 {
643 QgsDebugError( u"Cannot copy %1 to %2, source directory does not exist"_s.arg( source, destination ) );
644 return false;
645 }
646
647 QDir destDir( destination );
648 if ( !destDir.exists() )
649 {
650 if ( !destDir.mkdir( destination ) )
651 {
652 QgsDebugError( u"Cannot copy %1 to %2, could not make target directory"_s.arg( source, destination ) );
653 return false;
654 }
655 }
656
657 bool copiedAll = true;
658
659 QDir::Filters fileFilters = QDir::Files;
660 if ( flags & CopyFlag::NoSymLinks )
661 {
662 fileFilters |= QDir::NoSymLinks;
663 }
664 const QStringList files = sourceDir.entryList( fileFilters );
665 for ( const QString &file : files )
666 {
667 const QString srcFileName = sourceDir.filePath( file );
668 const QString destFileName = destDir.filePath( file );
669 if ( !QFile::copy( srcFileName, destFileName ) )
670 {
671 QgsDebugError( u"Cannot copy %1 to %2"_s.arg( srcFileName, destFileName ) );
672 copiedAll = false;
673 }
674 }
675
676 QDir::Filters dirFilters = QDir::AllDirs | QDir::NoDotAndDotDot;
677 if ( flags & CopyFlag::NoSymLinks )
678 {
679 dirFilters |= QDir::NoSymLinks;
680 }
681 const QStringList dirs = sourceDir.entryList( dirFilters );
682 for ( const QString &dir : dirs )
683 {
684 const QString srcDirName = sourceDir.filePath( dir );
685 const QString destDirName = destDir.filePath( dir );
686 if ( !copyDirectory( srcDirName, destDirName, flags ) )
687 {
688 copiedAll = false;
689 }
690 }
691 return copiedAll;
692}
693
694bool QgsFileUtils::replaceTextInFile( const QString &path, const QString &searchString, const QString &replacement )
695{
696 QFile file( path );
697 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
698 {
699 QgsDebugError( u"Could not open file for reading: %1"_s.arg( file.errorString() ) );
700 return false;
701 }
702
703 QTextStream in( &file );
704 const QString originalFileContent = in.readAll();
705 file.close();
706
707 QString fileContent = originalFileContent;
708 fileContent.replace( searchString, replacement );
709 if ( fileContent == originalFileContent )
710 return true;
711
712 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
713 {
714 QgsDebugError( u"Could not open file for writing: %1"_s.arg( file.errorString() ) );
715 return false;
716 }
717
718 QTextStream out( &file );
719 out << fileContent;
720 file.close();
721
722 return true;
723}
DriveType
Drive types.
Definition qgis.h:1152
@ Fixed
Fixed drive.
Definition qgis.h:1156
@ Invalid
Invalid path.
Definition qgis.h:1154
@ Unknown
Unknown type.
Definition qgis.h:1153
@ RamDisk
RAM disk.
Definition qgis.h:1159
@ Cloud
Cloud storage – files may be remote or locally stored, depending on user configuration.
Definition qgis.h:1160
@ CdRom
CD-ROM.
Definition qgis.h:1158
@ Removable
Removable drive.
Definition qgis.h:1155
@ Remote
Remote drive.
Definition qgis.h:1157
@ IncludeMetadataFile
Indicates that any associated .qmd metadata file should be included with the operation.
Definition qgis.h:2346
@ IncludeStyleFile
Indicates that any associated .qml styling file should be included with the operation.
Definition qgis.h:2347
QFlags< FileOperationFlag > FileOperationFlags
File operation flags.
Definition qgis.h:2350
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
static bool replaceTextInFile(const QString &path, const QString &searchString, const QString &replacement)
Replaces all occurrences of a given string in a file.
static QStringList findFile(const QString &file, const QString &basepath=QString(), int maxClimbs=4, int searchCeiling=4, const QString &currentDir=QString())
Will check basepath in an outward spiral up to maxClimbs levels to check if file exists.
static int openedFileCount()
Returns the number of currently opened files by the process.
@ NoSymLinks
If present, indicates that symbolic links should be skipped during the copy.
static QString wildcardsFromFilter(const QString &filter)
Given a filter string like GeoTIFF Files (*.tiff *.tif), extracts the wildcard portion of this filter...
static bool renameDataset(const QString &oldPath, const QString &newPath, QString &error, Qgis::FileOperationFlags flags=Qgis::FileOperationFlag::IncludeMetadataFile|Qgis::FileOperationFlag::IncludeStyleFile)
Renames the dataset at oldPath to newPath, renaming both the file at oldPath and all associated sidec...
static QSet< QString > sidecarFilesForPath(const QString &path)
Returns a list of the sidecar files which exist for the dataset a the specified path.
static bool pathIsSlowDevice(const QString &path)
Returns true if the specified path is assumed to reside on a slow device, e.g.
static bool isCloseToLimitOfOpenedFiles(int filesToBeOpened=1)
Returns whether when opening new file(s) will reach, or nearly reach, the limit of simultaneously ope...
static Qgis::DriveType driveType(const QString &path)
Returns the drive type for the given path.
static bool fileMatchesFilter(const QString &fileName, const QString &filter)
Returns true if the given fileName matches a file filter string.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static QString representFileSize(qint64 bytes)
Returns the human size from bytes.
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.
static int openedFileLimit()
Returns the limit of simultaneously opened files by the process.
static QStringList splitPathToComponents(const QString &path)
Given a file path, returns a list of all the components leading to that path.
static QString findClosestExistingPath(const QString &path)
Returns the top-most existing folder from path.
QFlags< CopyFlag > CopyFlags
Flags controlling behavior of file copy operations.
static bool copyDirectory(const QString &source, const QString &destination, QgsFileUtils::CopyFlags flags=QgsFileUtils::CopyFlags())
Recursively copies a whole directory.
static QStringList extensionsFromFilter(const QString &filter)
Returns a list of the extensions contained within a file filter string.
Custom exception class which is raised when an operation is not supported.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QgsProviderMetadata::ProviderCapabilities providerCapabilities() const
Returns the provider's capabilities.
@ FileBasedUris
Indicates that the provider can utilize URIs which are based on paths to files (as opposed to databas...
virtual QStringList sidecarFilesForUri(const QString &uri) const
Given a uri, returns any sidecar files which are associated with the URI and this provider.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QStringList providerList() const
Returns list of available providers by their keys.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
#define QgsDebugError(str)
Definition qgslogger.h:59