2 ==============================================================================
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2024 Filipe Coelho <falktx@falktx.com>
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 ==============================================================================
26 #ifndef WATER_FILE_H_INCLUDED
27 #define WATER_FILE_H_INCLUDED
29 #include "../misc/Result.h"
30 #include "../text/String.h"
36 //==============================================================================
38 Represents a local file or directory.
40 This class encapsulates the absolute pathname of a file or directory, and
41 has methods for finding out about the file and changing its properties.
43 To read or write to the file, there are methods for returning an input or
46 @see FileInputStream, FileOutputStream
51 //==============================================================================
52 /** Creates an (invalid) file object.
54 The file is initially set to an empty path, so getFullPathName() will return
57 You can use its operator= method to point it at a proper file.
61 /** Creates a file from an absolute path.
63 If the path supplied is a relative path, it is taken to be relative
64 to the current working directory (see File::getCurrentWorkingDirectory()),
65 but this isn't a recommended way of creating a file, because you
66 never know what the CWD is going to be.
68 On the Mac/Linux, the path can include "~" notation for referring to
69 user home directories.
71 File (const char* absolutePath
);
73 /** Creates a copy of another file object. */
79 /** Sets the file based on an absolute pathname.
81 If the path supplied is a relative path, it is taken to be relative
82 to the current working directory (see File::getCurrentWorkingDirectory()),
83 but this isn't a recommended way of creating a file, because you
84 never know what the CWD is going to be.
86 On the Mac/Linux, the path can include "~" notation for referring to
87 user home directories.
89 File
& operator= (const char* newAbsolutePath
);
91 /** Copies from another file object. */
92 File
& operator= (const File
& otherFile
);
94 //==============================================================================
95 /** Checks whether the file actually exists.
97 @returns true if the file exists, either as a file or a directory.
98 @see existsAsFile, isDirectory
102 /** Checks whether the file exists and is a file rather than a directory.
104 @returns true only if this is a real file, false if it's a directory
106 @see exists, isDirectory
108 bool existsAsFile() const;
110 /** Checks whether the file is a directory that exists.
112 @returns true only if the file is a directory which actually exists, so
113 false if it's a file or doesn't exist at all
114 @see exists, existsAsFile
116 bool isDirectory() const;
118 /** Checks whether the file is invalid (empty path).
122 /** Checks whether the file is valid (non-empty path).
124 bool isNotNull() const;
126 /** Returns the size of the file in bytes.
128 @returns the number of bytes in the file, or 0 if it doesn't exist.
130 int64
getSize() const;
132 //==============================================================================
133 /** Returns the complete, absolute path of this file.
135 This includes the filename and all its parent folders. On Windows it'll
136 also include the drive letter prefix; on Mac or Linux it'll be a complete
137 path starting from the root folder.
139 If you just want the file's name, you should use getFileName() or
140 getFileNameWithoutExtension().
142 @see getFileName, getRelativePathFrom
144 const String
& getFullPathName() const noexcept
{ return fullPath
; }
146 /** Returns the last section of the pathname.
148 Returns just the final part of the path - e.g. if the whole path
149 is "/moose/fish/foo.txt" this will return "foo.txt".
151 For a directory, it returns the final part of the path - e.g. for the
152 directory "/moose/fish" it'll return "fish".
154 If the filename begins with a dot, it'll return the whole filename, e.g. for
155 "/moose/.fish", it'll return ".fish"
157 @see getFullPathName, getFileNameWithoutExtension
159 String
getFileName() const;
161 /** Creates a relative path that refers to a file relatively to a given directory.
163 e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
164 would return "../../foo.txt".
166 If it's not possible to navigate from one file to the other, an absolute
167 path is returned. If the paths are invalid, an empty string may also be
170 @param directoryToBeRelativeTo the directory which the resultant string will
171 be relative to. If this is actually a file rather than
172 a directory, its parent directory will be used instead.
173 If it doesn't exist, it's assumed to be a directory.
174 @see getChildFile, isAbsolutePath
176 String
getRelativePathFrom (const File
& directoryToBeRelativeTo
) const;
178 //==============================================================================
179 /** Returns the file's extension.
181 Returns the file extension of this file, also including the dot.
183 e.g. "/moose/fish/foo.txt" would return ".txt"
185 @see hasFileExtension, withFileExtension, getFileNameWithoutExtension
187 String
getFileExtension() const;
189 /** Checks whether the file has a given extension.
191 @param extensionToTest the extension to look for - it doesn't matter whether or
192 not this string has a dot at the start, so ".wav" and "wav"
193 will have the same effect. To compare with multiple extensions, this
194 parameter can contain multiple strings, separated by semi-colons -
195 so, for example: hasFileExtension (".jpeg;png;gif") would return
196 true if the file has any of those three extensions.
198 @see getFileExtension, withFileExtension, getFileNameWithoutExtension
200 bool hasFileExtension (const char* extensionToTest
) const;
202 /** Returns a version of this file with a different file extension.
204 e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
206 @param newExtension the new extension, either with or without a dot at the start (this
207 doesn't make any difference). To get remove a file's extension altogether,
208 pass an empty string into this function.
210 @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
212 File
withFileExtension (const char* newExtension
) const;
214 /** Returns the last part of the filename, without its file extension.
216 e.g. for "/moose/fish/foo.txt" this will return "foo".
218 @see getFileName, getFileExtension, hasFileExtension, withFileExtension
220 String
getFileNameWithoutExtension() const;
222 //==============================================================================
223 /** Returns a file that represents a relative (or absolute) sub-path of the current one.
225 This will find a child file or directory of the current object.
228 File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
229 File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
230 File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
232 If the string is actually an absolute path, it will be treated as such, e.g.
233 File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
235 @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
237 File
getChildFile (const char* relativeOrAbsolutePath
) const;
239 /** Returns a file which is in the same directory as this one.
241 This is equivalent to getParentDirectory().getChildFile (name).
243 @see getChildFile, getParentDirectory
245 File
getSiblingFile (const char* siblingFileName
) const;
247 //==============================================================================
248 /** Returns the directory that contains this file or directory.
250 e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
252 File
getParentDirectory() const;
254 /** Checks whether a file is somewhere inside a directory.
256 Returns true if this file is somewhere inside a subdirectory of the directory
257 that is passed in. Neither file actually has to exist, because the function
258 just checks the paths for similarities.
260 e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
261 File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
263 bool isAChildOf (const File
& potentialParentDirectory
) const;
265 //==============================================================================
266 /** Chooses a filename relative to this one that doesn't already exist.
268 If this file is a directory, this will return a child file of this
269 directory that doesn't exist, by adding numbers to a prefix and suffix until
270 it finds one that isn't already there.
272 If the prefix + the suffix doesn't exist, it won't bother adding a number.
274 e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
275 return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
277 @param prefix the string to use for the filename before the number
278 @param suffix the string to add to the filename after the number
279 @param putNumbersInBrackets if true, this will create filenames in the
280 format "prefix(number)suffix", if false, it will leave the
283 File
getNonexistentChildFile (const String
& prefix
,
284 const String
& suffix
,
285 bool putNumbersInBrackets
= true) const;
287 /** Chooses a filename for a sibling file to this one that doesn't already exist.
289 If this file doesn't exist, this will just return itself, otherwise it
290 will return an appropriate sibling that doesn't exist, e.g. if a file
291 "/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
293 @param putNumbersInBrackets whether to add brackets around the numbers that
294 get appended to the new filename.
296 File
getNonexistentSibling (bool putNumbersInBrackets
= true) const;
298 //==============================================================================
299 /** Compares the pathnames for two files. */
300 bool operator== (const File
&) const;
301 /** Compares the pathnames for two files. */
302 bool operator!= (const File
&) const;
303 /** Compares the pathnames for two files. */
304 bool operator< (const File
&) const;
305 /** Compares the pathnames for two files. */
306 bool operator> (const File
&) const;
308 //==============================================================================
309 /** Checks whether a file can be created or written to.
311 @returns true if it's possible to create and write to this file. If the file
312 doesn't already exist, this will check its parent directory to
313 see if writing is allowed.
316 bool hasWriteAccess() const;
318 /** Returns true if this file is a hidden or system file.
319 The criteria for deciding whether a file is hidden are platform-dependent.
321 bool isHidden() const;
323 //==============================================================================
324 /** Returns the last modification time of this file.
326 @returns the time, or an invalid time if the file doesn't exist.
327 @see getLastAccessTime, getCreationTime
329 int64
getLastModificationTime() const;
331 /** Returns the last time this file was accessed.
333 @returns the time, or an invalid time if the file doesn't exist.
334 @see getLastModificationTime, getCreationTime
336 int64
getLastAccessTime() const;
338 /** Returns the time that this file was created.
340 @returns the time, or an invalid time if the file doesn't exist.
341 @see getLastModificationTime, getLastAccessTime
343 int64
getCreationTime() const;
345 //==============================================================================
346 /** Creates an empty file if it doesn't already exist.
348 If the file that this object refers to doesn't exist, this will create a file
351 If it already exists or is a directory, this method will do nothing.
353 If the parent directories of the File do not exist then this method will
354 recursively create the parent directories.
356 @returns a result to indicate whether the file was created successfully,
357 or an error message if it failed.
360 Result
create() const;
362 /** Creates a new directory for this filename.
364 This will try to create the file as a directory, and will also create
365 any parent directories it needs in order to complete the operation.
367 @returns a result to indicate whether the directory was created successfully, or
368 an error message if it failed.
371 Result
createDirectory() const;
375 If this file is actually a directory, it may not be deleted correctly if it
376 contains files. See deleteRecursively() as a better way of deleting directories.
378 @returns true if the file has been successfully deleted (or if it didn't exist to
380 @see deleteRecursively
382 bool deleteFile() const;
384 /** Deletes a file or directory and all its subdirectories.
386 If this file is a directory, this will try to delete it and all its subfolders. If
387 it's just a file, it will just try to delete the file.
389 @returns true if the file and all its subfolders have been successfully deleted
390 (or if it didn't exist to begin with).
393 bool deleteRecursively() const;
395 /** Moves or renames a file.
397 Tries to move a file to a different location.
398 If the target file already exists, this will attempt to delete it first, and
399 will fail if this can't be done.
401 Note that the destination file isn't the directory to put it in, it's the actual
402 filename that you want the new file to have.
404 Also note that on some OSes (e.g. Windows), moving files between different
405 volumes may not be possible.
407 @returns true if the operation succeeds
409 bool moveFileTo (const File
& targetLocation
) const;
413 Tries to copy a file to a different location.
414 If the target file already exists, this will attempt to delete it first, and
415 will fail if this can't be done.
417 @returns true if the operation succeeds
419 bool copyFileTo (const File
& targetLocation
) const;
423 Replace the file in the given location, assuming the replaced files identity.
424 Depending on the file system this will preserve file attributes such as
425 creation date, short file name, etc.
427 If replacement succeeds the original file is deleted.
429 @returns true if the operation succeeds
431 bool replaceFileIn (const File
& targetLocation
) const;
433 /** Copies a directory.
435 Tries to copy an entire directory, recursively.
437 If this file isn't a directory or if any target files can't be created, this
440 @param newDirectory the directory that this one should be copied to. Note that this
441 is the name of the actual directory to create, not the directory
442 into which the new one should be placed, so there must be enough
443 write privileges to create it if it doesn't exist. Any files inside
444 it will be overwritten by similarly named ones that are copied.
446 bool copyDirectoryTo (const File
& newDirectory
) const;
448 //==============================================================================
449 /** Used in file searching, to specify whether to return files, directories, or both.
451 enum TypesOfFileToFind
453 findDirectories
= 1, /**< Use this flag to indicate that you want to find directories. */
454 findFiles
= 2, /**< Use this flag to indicate that you want to find files. */
455 findFilesAndDirectories
= 3, /**< Use this flag to indicate that you want to find both files and directories. */
456 ignoreHiddenFiles
= 4 /**< Add this flag to avoid returning any hidden files in the results. */
459 /** Searches inside a directory for files matching a wildcard pattern.
461 Assuming that this file is a directory, this method will search it
462 for either files or subdirectories whose names match a filename pattern.
464 @param results an vector to which File objects will be added for the
465 files that the search comes up with
466 @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
467 return files, directories, or both. If the ignoreHiddenFiles flag
468 is also added to this value, hidden files won't be returned
469 @param searchRecursively if true, all subdirectories will be recursed into to do
471 @param wildCardPattern the filename pattern to search for, e.g. "*.txt"
472 @returns the number of results that have been found
474 @see getNumberOfChildFiles, DirectoryIterator
476 uint
findChildFiles (std::vector
<File
>& results
,
478 bool searchRecursively
,
479 const char* wildCardPattern
= "*") const;
481 /** Searches inside a directory and counts how many files match a wildcard pattern.
483 Assuming that this file is a directory, this method will search it
484 for either files or subdirectories whose names match a filename pattern,
485 and will return the number of matches found.
487 This isn't a recursive call, and will only search this directory, not
490 @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
491 count files, directories, or both. If the ignoreHiddenFiles flag
492 is also added to this value, hidden files won't be counted
493 @param wildCardPattern the filename pattern to search for, e.g. "*.txt"
494 @returns the number of matches found
495 @see findChildFiles, DirectoryIterator
497 uint
getNumberOfChildFiles (int whatToLookFor
,
498 const char* wildCardPattern
= "*") const;
500 /** Returns true if this file is a directory that contains one or more subdirectories.
501 @see isDirectory, findChildFiles
503 bool containsSubDirectories() const;
505 //==============================================================================
506 /** Creates a stream to read from this file.
508 @returns a stream that will read from this file (initially positioned at the
509 start of the file), or nullptr if the file can't be opened for some reason
510 @see createOutputStream, loadFileAsData
512 FileInputStream
* createInputStream() const;
514 /** Creates a stream to write to this file.
516 If the file exists, the stream that is returned will be positioned ready for
517 writing at the end of the file, so you might want to use deleteFile() first
518 to write to an empty file.
520 @returns a stream that will write to this file (initially positioned at the
521 end of the file), or nullptr if the file can't be opened for some reason
522 @see createInputStream, appendData, appendText
524 FileOutputStream
* createOutputStream (size_t bufferSize
= 0x8000) const;
526 //==============================================================================
527 /** Loads a file's contents into memory as a block of binary data.
529 Of course, trying to load a very large file into memory will blow up, so
530 it's better to check first.
532 @param result the data block to which the file's contents should be appended - note
533 that if the memory block might already contain some data, you
534 might want to clear it first
535 @returns true if the file could all be read into memory
537 bool loadFileAsData (MemoryBlock
& result
) const;
539 /** Reads a file into memory as a string.
541 Attempts to load the entire file as a zero-terminated string.
543 This makes use of InputStream::readEntireStreamAsString, which can
544 read either UTF-16 or UTF-8 file formats.
546 String
loadFileAsString() const;
548 //==============================================================================
549 /** Appends a block of binary data to the end of the file.
551 This will try to write the given buffer to the end of the file.
553 @returns false if it can't write to the file for some reason
555 bool appendData (const void* dataToAppend
,
556 size_t numberOfBytes
) const;
558 /** Replaces this file's contents with a given block of data.
560 This will delete the file and replace it with the given data.
562 A nice feature of this method is that it's safe - instead of deleting
563 the file first and then re-writing it, it creates a new temporary file,
564 writes the data to that, and then moves the new file to replace the existing
565 file. This means that if the power gets pulled out or something crashes,
566 you're a lot less likely to end up with a corrupted or unfinished file..
568 Returns true if the operation succeeds, or false if it fails.
572 bool replaceWithData (const void* dataToWrite
,
573 size_t numberOfBytes
) const;
575 /** Appends a string to the end of the file.
577 This will try to append a text string to the file, as either 16-bit unicode
578 or 8-bit characters in the default system encoding.
580 It can also write the 'ff fe' unicode header bytes before the text to indicate
581 the endianness of the file.
583 Any single \\n characters in the string are replaced with \\r\\n before it is written.
587 bool appendText (const String
& textToAppend
,
588 bool asUnicode
= false,
589 bool writeUnicodeHeaderBytes
= false) const;
591 /** Replaces this file's contents with a given text string.
593 This will delete the file and replace it with the given text.
595 A nice feature of this method is that it's safe - instead of deleting
596 the file first and then re-writing it, it creates a new temporary file,
597 writes the text to that, and then moves the new file to replace the existing
598 file. This means that if the power gets pulled out or something crashes,
599 you're a lot less likely to end up with an empty file..
601 For an explanation of the parameters here, see the appendText() method.
603 Returns true if the operation succeeds, or false if it fails.
607 bool replaceWithText (const String
& textToWrite
,
608 bool asUnicode
= false,
609 bool writeUnicodeHeaderBytes
= false) const;
611 /** Attempts to scan the contents of this file and compare it to another file, returning
612 true if this is possible and they match byte-for-byte.
614 bool hasIdenticalContentTo (const File
& other
) const;
616 //==============================================================================
617 /** A set of types of location that can be passed to the getSpecialLocation() method.
619 enum SpecialLocationType
621 /** The user's home folder. This is the same as using File ("~"). */
624 /** The folder that should be used for temporary files.
625 Always delete them when you're finished, to keep the user's computer tidy!
629 /** Returns this application's executable file.
631 If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
634 On the mac this will return the unix binary, not the package folder.
636 currentExecutableFile
,
638 /** In a plugin, this will return the path of the host executable. */
641 /** Windows specific paths */
642 winAppData
, winProgramFiles
, winCommonProgramFiles
, winMyDocuments
645 /** Finds the location of a special type of file or directory, such as a home folder or
648 @see SpecialLocationType
650 static File
getSpecialLocation (const SpecialLocationType type
);
652 //==============================================================================
653 /** Returns a temporary file in the system's temp directory.
654 This will try to return the name of a non-existent temp file.
655 To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
657 static File
createTempFile (const char* fileNameEnding
);
659 //==============================================================================
660 /** Returns the current working directory.
661 @see setAsCurrentWorkingDirectory
663 static File
getCurrentWorkingDirectory();
665 /** Sets the current working directory to be this file.
667 For this to work the file must point to a valid directory.
669 @returns true if the current directory has been changed.
670 @see getCurrentWorkingDirectory
672 bool setAsCurrentWorkingDirectory() const;
674 //==============================================================================
675 /** Returns a version of a filename with any illegal characters removed.
677 This will return a copy of the given string after removing characters
678 that are not allowed in a legal filename, and possibly shortening the
679 string if it's too long.
681 Because this will remove slashes, don't use it on an absolute pathname - use
682 createLegalPathName() for that.
684 @see createLegalPathName
686 static String
createLegalFileName (const String
& fileNameToFix
);
688 /** Returns a version of a path with any illegal characters removed.
690 Similar to createLegalFileName(), but this won't remove slashes, so can
691 be used on a complete pathname.
693 @see createLegalFileName
695 static String
createLegalPathName (const String
& pathNameToFix
);
697 /** Indicates whether filenames are case-sensitive on the current operating system. */
698 static bool areFileNamesCaseSensitive();
700 /** Returns true if the string seems to be a fully-specified absolute path. */
701 static bool isAbsolutePath (const char* path
);
703 /** Creates a file that simply contains this string, without doing the sanity-checking
704 that the normal constructors do.
706 Best to avoid this unless you really know what you're doing.
708 static File
createFileWithoutCheckingPath (const String
& absolutePath
) noexcept
;
710 /** Adds a separator character to the end of a path if it doesn't already have one. */
711 static String
addTrailingSeparator (const String
& path
);
713 //==============================================================================
714 /** Tries to create a symbolic link and returns a boolean to indicate success */
715 bool createSymbolicLink (const File
& linkFileToCreate
, bool overwriteExisting
) const;
717 /** Returns true if this file is a link or alias that can be followed using getLinkedTarget(). */
718 bool isSymbolicLink() const;
720 /** If this file is a link or alias, this returns the file that it points to.
721 If the file isn't actually link, it'll just return itself.
723 File
getLinkedTarget() const;
725 //==============================================================================
726 struct NaturalFileComparator
728 NaturalFileComparator (bool shouldPutFoldersFirst
) noexcept
: foldersFirst (shouldPutFoldersFirst
) {}
730 int compareElements (const File
& firstFile
, const File
& secondFile
) const
732 if (foldersFirst
&& (firstFile
.isDirectory() != secondFile
.isDirectory()))
733 return firstFile
.isDirectory() ? -1 : 1;
735 return firstFile
.getFullPathName().compareNatural (secondFile
.getFullPathName(), File::areFileNamesCaseSensitive());
742 //==============================================================================
745 static String
parseAbsolutePath (const String
&);
746 String
getPathUpToLastSlash() const;
748 Result
createDirectoryInternal (const String
&) const;
749 bool copyInternal (const File
&) const;
750 bool moveInternal (const File
&) const;
751 bool replaceInternal (const File
&) const;
752 void getFileTimesInternal (int64
& m
, int64
& a
, int64
& c
) const;
753 bool setFileReadOnlyInternal (bool) const;
754 bool setFileExecutableInternal (bool) const;
759 #endif // WATER_FILE_H_INCLUDED