QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
32using namespace Qt::StringLiterals;
33
34#ifdef Q_OS_UNIX
35// For getrlimit()
36#include <sys/resource.h>
37#include <sys/time.h>
38#include <dirent.h>
39#endif
40
41#ifdef _MSC_VER
42#include <Windows.h>
43#include <ShlObj.h>
44#pragma comment( lib, "Shell32.lib" )
45#endif
46
47QString QgsFileUtils::representFileSize( qint64 bytes )
48{
49 QStringList list;
50 list << QObject::tr( "KB" ) << QObject::tr( "MB" ) << QObject::tr( "GB" ) << QObject::tr( "TB" );
51
52 QStringListIterator i( list );
53 QString unit = QObject::tr( "B" );
54
55 double fileSize = bytes;
56 while ( fileSize >= 1024.0 && i.hasNext() )
57 {
58 fileSize /= 1024.0;
59 unit = i.next();
60 }
61 return u"%1 %2"_s.arg( QString::number( fileSize, 'f', bytes >= 1048576 ? 2 : 0 ), unit );
62}
63
64QStringList QgsFileUtils::extensionsFromFilter( const QString &filter )
65{
66 const thread_local QRegularExpression rx( u"\\*\\.([a-zA-Z0-9\\.]+)"_s );
67 QStringList extensions;
68 QRegularExpressionMatchIterator matches = rx.globalMatch( filter );
69
70 while ( matches.hasNext() )
71 {
72 const QRegularExpressionMatch match = matches.next();
73 if ( match.hasMatch() )
74 {
75 QStringList newExtensions = match.capturedTexts();
76 newExtensions.pop_front(); // remove whole match
77 extensions.append( newExtensions );
78 }
79 }
80 return extensions;
81}
82
83QString QgsFileUtils::wildcardsFromFilter( const QString &filter )
84{
85 const thread_local QRegularExpression globPatternsRx( u".*\\((.*?)\\)$"_s );
86 const QRegularExpressionMatch matches = globPatternsRx.match( filter );
87 if ( matches.hasMatch() )
88 return matches.captured( 1 );
89 else
90 return QString();
91}
92
93bool QgsFileUtils::fileMatchesFilter( const QString &fileName, const QString &filter )
94{
95 QFileInfo fi( fileName );
96 const QString name = fi.fileName();
97 const QStringList parts = filter.split( u";;"_s );
98 for ( const QString &part : parts )
99 {
100 const QStringList globPatterns = wildcardsFromFilter( part ).split( ' ', Qt::SkipEmptyParts );
101 for ( const QString &glob : globPatterns )
102 {
103 const QString re = QRegularExpression::wildcardToRegularExpression( glob );
104
105 const QRegularExpression globRx( re );
106 if ( globRx.match( name ).hasMatch() )
107 return true;
108 }
109 }
110 return false;
111}
112
113QString QgsFileUtils::ensureFileNameHasExtension( const QString &f, const QStringList &extensions )
114{
115 if ( extensions.empty() || f.isEmpty() )
116 return f;
117
118 QString fileName = f;
119 bool hasExt = false;
120 for ( const QString &extension : std::as_const( extensions ) )
121 {
122 const QString extWithDot = extension.startsWith( '.' ) ? extension : '.' + extension;
123 if ( fileName.endsWith( extWithDot, Qt::CaseInsensitive ) )
124 {
125 hasExt = true;
126 break;
127 }
128 }
129
130 if ( !hasExt )
131 {
132 const QString extension = extensions.at( 0 );
133 const QString extWithDot = extension.startsWith( '.' ) ? extension : '.' + extension;
134 fileName += extWithDot;
135 }
136
137 return fileName;
138}
139
140QString QgsFileUtils::addExtensionFromFilter( const QString &fileName, const QString &filter )
141{
142 const QStringList extensions = extensionsFromFilter( filter );
143 return ensureFileNameHasExtension( fileName, extensions );
144}
145
146QString QgsFileUtils::stringToSafeFilename( const QString &string )
147{
148 const thread_local QRegularExpression rx( u"[/\\\\\\?%\\*\\:\\|\"<>]"_s );
149 QString s = string;
150 s.replace( rx, u"_"_s );
151 return s;
152}
153
154QString QgsFileUtils::findClosestExistingPath( const QString &path )
155{
156 if ( path.isEmpty() )
157 return QString();
158
159 QDir currentPath;
160 QFileInfo fi( path );
161 if ( fi.isFile() )
162 currentPath = fi.dir();
163 else
164 currentPath = QDir( path );
165
166 QSet< QString > visited;
167 while ( !currentPath.exists() )
168 {
169 const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + u"/.."_s );
170 if ( visited.contains( parentPath ) )
171 return QString(); // break circular links
172
173 if ( parentPath.isEmpty() || parentPath == "."_L1 )
174 return QString();
175 currentPath = QDir( parentPath );
176 visited << parentPath;
177 }
178
179 const QString res = QDir::cleanPath( currentPath.absolutePath() );
180
181 if ( res == QDir::currentPath() )
182 return QString(); // avoid default to binary folder if a filename alone is specified
183
184 return res == "."_L1 ? QString() : res;
185}
186
187QStringList QgsFileUtils::findFile( const QString &file, const QString &basePath, int maxClimbs, int searchCeilling, const QString &currentDir )
188{
189 int depth = 0;
190 QString originalFolder;
191 QDir folder;
192 const QString fileName( basePath.isEmpty() ? QFileInfo( file ).fileName() : file );
193 const QString baseFolder( basePath.isEmpty() ? QFileInfo( file ).path() : basePath );
194
195 if ( QFileInfo( baseFolder ).isDir() )
196 {
197 folder = QDir( baseFolder );
198 originalFolder = folder.absolutePath();
199 }
200 else // invalid folder or file path
201 {
202 folder = QDir( QFileInfo( baseFolder ).absolutePath() );
203 originalFolder = folder.absolutePath();
204 }
205
206 QStringList searchedFolder = QStringList();
207 QString existingBase;
208 QString backupDirectory = QDir::currentPath();
209 QStringList foundFiles;
210
211 if ( !currentDir.isEmpty() && backupDirectory != currentDir && QDir( currentDir ).exists() )
212 QDir::setCurrent( currentDir );
213
214 // find the nearest existing folder
215 while ( !folder.exists() && folder.absolutePath().count( '/' ) > searchCeilling )
216 {
217 existingBase = folder.path();
218 if ( !folder.cdUp() )
219 folder = QFileInfo( existingBase ).absoluteDir(); // using fileinfo to move up one level
220
221 depth += 1;
222
223 if ( depth > ( maxClimbs + 4 ) ) //break early when no folders can be found
224 break;
225 }
226 bool folderExists = folder.exists();
227
228 if ( depth > maxClimbs )
229 maxClimbs = depth;
230
231 if ( folder.absolutePath().count( '/' ) < searchCeilling )
232 searchCeilling = folder.absolutePath().count( '/' ) - 1;
233
234 while ( depth <= maxClimbs && folderExists && folder.absolutePath().count( '/' ) >= searchCeilling )
235 {
236 QDirIterator localFinder( folder.path(), QStringList() << fileName, QDir::Files, QDirIterator::NoIteratorFlags );
237 searchedFolder.append( folder.absolutePath() );
238 if ( localFinder.hasNext() )
239 {
240 foundFiles << localFinder.next();
241 return foundFiles;
242 }
243
244
245 const QFileInfoList subdirs = folder.entryInfoList( QDir::AllDirs );
246 for ( const QFileInfo &subdir : subdirs )
247 {
248 if ( !searchedFolder.contains( subdir.absolutePath() ) )
249 {
250 QDirIterator subDirFinder( subdir.path(), QStringList() << fileName, QDir::Files, QDirIterator::Subdirectories );
251 if ( subDirFinder.hasNext() )
252 {
253 QString possibleFile = subDirFinder.next();
254 if ( !subDirFinder.hasNext() )
255 {
256 foundFiles << possibleFile;
257 return foundFiles;
258 }
259
260 foundFiles << possibleFile;
261 while ( subDirFinder.hasNext() )
262 {
263 foundFiles << subDirFinder.next();
264 }
265 return foundFiles;
266 }
267 }
268 }
269 depth += 1;
270
271 if ( depth > maxClimbs )
272 break;
273
274 folderExists = folder.cdUp();
275 }
276
277 if ( QDir::currentPath() == currentDir && currentDir != backupDirectory )
278 QDir::setCurrent( backupDirectory );
279
280 return foundFiles;
281}
282
283#ifdef _MSC_VER
284std::unique_ptr< wchar_t[] > pathToWChar( const QString &path )
285{
286 const QString nativePath = QDir::toNativeSeparators( path );
287
288 std::unique_ptr< wchar_t[] > pathArray( new wchar_t[static_cast< uint>( nativePath.length() + 1 )] );
289 nativePath.toWCharArray( pathArray.get() );
290 pathArray[static_cast< size_t >( nativePath.length() )] = 0;
291 return pathArray;
292}
293
294
295void fileAttributesOld( HANDLE handle, DWORD &fileAttributes, bool &hasFileAttributes )
296{
297 hasFileAttributes = false;
298 BY_HANDLE_FILE_INFORMATION info;
299 if ( GetFileInformationByHandle( handle, &info ) )
300 {
301 hasFileAttributes = true;
302 fileAttributes = info.dwFileAttributes;
303 }
304}
305
306// File attributes for Windows starting from version 8.
307void fileAttributesNew( HANDLE handle, DWORD &fileAttributes, bool &hasFileAttributes )
308{
309 hasFileAttributes = false;
310#if WINVER >= 0x0602
311 _FILE_BASIC_INFO infoEx;
312 if ( GetFileInformationByHandleEx( handle, FileBasicInfo, &infoEx, sizeof( infoEx ) ) )
313 {
314 hasFileAttributes = true;
315 fileAttributes = infoEx.FileAttributes;
316 }
317 else
318 {
319 // GetFileInformationByHandleEx() is observed to fail for FAT32, QTBUG-74759
320 fileAttributesOld( handle, fileAttributes, hasFileAttributes );
321 }
322#else
323 fileAttributesOld( handle, fileAttributes, hasFileAttributes );
324#endif
325}
326
327bool pathIsLikelyCloudStorage( QString path )
328{
329 // For OneDrive detection need the attributes of a file from the path, not the directory itself.
330 // So just grab the first file in the path.
331 QDirIterator dirIt( path, QDir::Files );
332 if ( dirIt.hasNext() )
333 {
334 path = dirIt.next();
335 }
336
337 std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
338 const HANDLE handle = CreateFileW( pathArray.get(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr );
339 if ( handle != INVALID_HANDLE_VALUE )
340 {
341 bool hasFileAttributes = false;
342 DWORD attributes = 0;
343 fileAttributesNew( handle, attributes, hasFileAttributes );
344 CloseHandle( handle );
345 if ( hasFileAttributes )
346 {
347 /* From the Win32 API documentation:
348 *
349 * FILE_ATTRIBUTE_RECALL_ON_OPEN:
350 * When this attribute is set, it means that the file or directory has no physical representation
351 * on the local system; the item is virtual. Opening the item will be more expensive than normal,
352 * e.g. it will cause at least some of it to be fetched from a remote store
353 *
354 * FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
355 * When this attribute is set, it means that the file or directory is not fully present locally.
356 * For a file that means that not all of its data is on local storage (e.g. it may be sparse with
357 * some data still in remote storage).
358 */
359 return ( attributes & FILE_ATTRIBUTE_RECALL_ON_OPEN ) || ( attributes & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS );
360 }
361 }
362 return false;
363}
364#endif
365
367{
368#ifdef _MSC_VER
369 auto pathType = []( const QString &path ) -> Qgis::DriveType {
370 std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
371 const UINT type = GetDriveTypeW( pathArray.get() );
372 switch ( type )
373 {
374 case DRIVE_UNKNOWN:
376
377 case DRIVE_NO_ROOT_DIR:
379
380 case DRIVE_REMOVABLE:
382
383 case DRIVE_FIXED:
385
386 case DRIVE_REMOTE:
388
389 case DRIVE_CDROM:
391
392 case DRIVE_RAMDISK:
394 }
395
397 };
398
399 const QString originalPath = QDir::cleanPath( path );
400 QString currentPath = originalPath;
401 QString prevPath;
402 while ( currentPath != prevPath )
403 {
404 if ( pathIsLikelyCloudStorage( currentPath ) )
406
407 prevPath = currentPath;
408 currentPath = QFileInfo( currentPath ).path();
409
410 const Qgis::DriveType type = pathType( currentPath );
411 if ( type != Qgis::DriveType::Unknown && type != Qgis::DriveType::Invalid )
412 return type;
413 }
415
416#else
417 ( void ) path;
418 throw QgsNotSupportedException( u"Determining drive type is not supported on this platform"_s );
419#endif
420}
421
422bool QgsFileUtils::pathIsSlowDevice( const QString &path )
423{
424#ifdef ENABLE_TESTS
425 if ( path.contains( "fake_slow_path_for_unit_tests"_L1 ) )
426 return true;
427#endif
428
429 try
430 {
431 const Qgis::DriveType type = driveType( path );
432 switch ( type )
433 {
438 return false;
439
444 return true;
445 }
446 }
447 catch ( QgsNotSupportedException & )
448 {}
449 return false;
450}
451
452QSet<QString> QgsFileUtils::sidecarFilesForPath( const QString &path )
453{
454 QSet< QString > res;
455 const QStringList providers = QgsProviderRegistry::instance()->providerList();
456 for ( const QString &provider : providers )
457 {
460 {
461 const QStringList possibleSidecars = metadata->sidecarFilesForUri( path );
462 for ( const QString &possibleSidecar : possibleSidecars )
463 {
464 if ( QFile::exists( possibleSidecar ) )
465 res.insert( possibleSidecar );
466 }
467 }
468 }
469 return res;
470}
471
472bool QgsFileUtils::renameDataset( const QString &oldPath, const QString &newPath, QString &error, Qgis::FileOperationFlags flags )
473{
474 if ( !QFile::exists( oldPath ) )
475 {
476 error = QObject::tr( "File does not exist" );
477 return false;
478 }
479
480 const QFileInfo oldPathInfo( oldPath );
481 QSet< QString > sidecars = sidecarFilesForPath( oldPath );
483 {
484 const QString qmdPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + u".qmd"_s );
485 if ( QFile::exists( qmdPath ) )
486 sidecars.insert( qmdPath );
487 }
489 {
490 const QString qmlPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + u".qml"_s );
491 if ( QFile::exists( qmlPath ) )
492 sidecars.insert( qmlPath );
493 }
494
495 const QFileInfo newPathInfo( newPath );
496
497 bool res = true;
498 QStringList errors;
499 errors.reserve( sidecars.size() );
500 // first check if all sidecars CAN be renamed -- we don't want to get partly through the rename and then find a clash
501 for ( const QString &sidecar : std::as_const( sidecars ) )
502 {
503 const QFileInfo sidecarInfo( sidecar );
504 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + '.' + sidecarInfo.suffix() );
505 if ( newSidecarName != sidecar && QFile::exists( newSidecarName ) )
506 {
507 res = false;
508 errors.append( QDir::toNativeSeparators( newSidecarName ) );
509 }
510 }
511 if ( !res )
512 {
513 error = QObject::tr( "Destination files already exist %1" ).arg( errors.join( ", "_L1 ) );
514 return false;
515 }
516
517 if ( !QFile::rename( oldPath, newPath ) )
518 {
519 error = QObject::tr( "Could not rename %1" ).arg( QDir::toNativeSeparators( oldPath ) );
520 return false;
521 }
522
523 for ( const QString &sidecar : std::as_const( sidecars ) )
524 {
525 const QFileInfo sidecarInfo( sidecar );
526 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + '.' + sidecarInfo.suffix() );
527 if ( newSidecarName == sidecar )
528 continue;
529
530 if ( !QFile::rename( sidecar, newSidecarName ) )
531 {
532 errors.append( QDir::toNativeSeparators( sidecar ) );
533 res = false;
534 }
535 }
536 if ( !res )
537 {
538 error = QObject::tr( "Could not rename %1" ).arg( errors.join( ", "_L1 ) );
539 }
540
541 return res;
542}
543
545{
546#ifdef Q_OS_UNIX
547 struct rlimit rescLimit;
548 if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
549 {
550 return rescLimit.rlim_cur;
551 }
552#endif
553 return -1;
554}
555
557{
558#ifdef Q_OS_LINUX
559 int fileCount = 0;
560
561 DIR *dirp = opendir( "/proc/self/fd" );
562 if ( !dirp )
563 return -1;
564
565 while ( struct dirent *entry = readdir( dirp ) )
566 {
567 if ( entry->d_type == DT_REG )
568 {
569 fileCount++;
570 }
571 }
572 closedir( dirp );
573 return fileCount;
574#else
575 return -1;
576#endif
577}
578
580{
581 const int nFileLimit = QgsFileUtils::openedFileLimit();
582 const int nFileCount = QgsFileUtils::openedFileCount();
583 // We need some margin as Qt will crash if it cannot create some file descriptors
584 constexpr int SOME_MARGIN = 20;
585 return nFileCount > 0 && nFileLimit > 0 && nFileCount + filesToBeOpened > nFileLimit - SOME_MARGIN;
586}
587
588QStringList QgsFileUtils::splitPathToComponents( const QString &input )
589{
590 QStringList result;
591 QString path = QDir::cleanPath( input );
592 if ( path.isEmpty() )
593 return result;
594
595 const QString fileName = QFileInfo( path ).fileName();
596 if ( !fileName.isEmpty() )
597 result << fileName;
598 else if ( QFileInfo( path ).path() == path )
599 result << path;
600
601 QString prevPath = path;
602 while ( ( path = QFileInfo( path ).path() ).length() < prevPath.length() )
603 {
604 const QString dirName = QDir( path ).dirName();
605 if ( dirName == "."_L1 )
606 break;
607
608 result << ( !dirName.isEmpty() ? dirName : path );
609 prevPath = path;
610 }
611
612 std::reverse( result.begin(), result.end() );
613 return result;
614}
615
616QString QgsFileUtils::uniquePath( const QString &path )
617{
618 if ( !QFileInfo::exists( path ) )
619 {
620 return path;
621 }
622
623 QFileInfo info { path };
624 const QString suffix { info.completeSuffix() };
625 const QString pathPattern { QString( suffix.isEmpty() ? path : path.chopped( suffix.length() + 1 ) ).append( suffix.isEmpty() ? u"_%1"_s : u"_%1."_s ).append( suffix ) };
626 int i { 2 };
627 QString uniquePath { pathPattern.arg( i ) };
628 while ( QFileInfo::exists( uniquePath ) )
629 {
630 ++i;
631 uniquePath = pathPattern.arg( i );
632 }
633 return uniquePath;
634}
635
636bool QgsFileUtils::copyDirectory( const QString &source, const QString &destination )
637{
638 QDir sourceDir( source );
639 if ( !sourceDir.exists() )
640 {
641 QgsDebugError( u"Cannot copy %1 to %2, source directory does not exist"_s.arg( source, destination ) );
642 return false;
643 }
644
645 QDir destDir( destination );
646 if ( !destDir.exists() )
647 {
648 if ( !destDir.mkdir( destination ) )
649 {
650 QgsDebugError( u"Cannot copy %1 to %2, could not make target directory"_s.arg( source, destination ) );
651 return false;
652 }
653 }
654
655 bool copiedAll = true;
656 const QStringList files = sourceDir.entryList( QDir::Files );
657 for ( const QString &file : files )
658 {
659 const QString srcFileName = sourceDir.filePath( file );
660 const QString destFileName = destDir.filePath( file );
661 if ( !QFile::copy( srcFileName, destFileName ) )
662 {
663 QgsDebugError( u"Cannot copy %1 to %2"_s.arg( srcFileName, destFileName ) );
664 copiedAll = false;
665 }
666 }
667 const QStringList dirs = sourceDir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot );
668 for ( const QString &dir : dirs )
669 {
670 const QString srcDirName = sourceDir.filePath( dir );
671 const QString destDirName = destDir.filePath( dir );
672 if ( !copyDirectory( srcDirName, destDirName ) )
673 {
674 copiedAll = false;
675 }
676 }
677 return copiedAll;
678}
679
680bool QgsFileUtils::replaceTextInFile( const QString &path, const QString &searchString, const QString &replacement )
681{
682 QFile file( path );
683 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
684 {
685 QgsDebugError( u"Could not open file for reading: %1"_s.arg( file.errorString() ) );
686 return false;
687 }
688
689 QTextStream in( &file );
690 const QString originalFileContent = in.readAll();
691 file.close();
692
693 QString fileContent = originalFileContent;
694 fileContent.replace( searchString, replacement );
695 if ( fileContent == originalFileContent )
696 return true;
697
698 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
699 {
700 QgsDebugError( u"Could not open file for writing: %1"_s.arg( file.errorString() ) );
701 return false;
702 }
703
704 QTextStream out( &file );
705 out << fileContent;
706 file.close();
707
708 return true;
709}
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.
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 copyDirectory(const QString &source, const QString &destination)
Creates a unique file path name from a desired path by appending _<n> (where <n> is an integer number...
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.
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