2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
34 #include "juce_File.h"
35 #include "juce_FileInputStream.h"
36 #include "juce_FileOutputStream.h"
37 #include "juce_DirectoryIterator.h"
38 #include "juce_TemporaryFile.h"
39 #include "../../core/juce_SystemStats.h"
40 #include "../../maths/juce_Random.h"
41 #include "../../core/juce_PlatformUtilities.h"
42 #include "../../memory/juce_ScopedPointer.h"
45 //==============================================================================
46 File::File (const String
& fullPathName
)
47 : fullPath (parseAbsolutePath (fullPathName
))
51 File::File (const String
& path
, int)
56 File
File::createFileWithoutCheckingPath (const String
& path
)
58 return File (path
, 0);
61 File::File (const File
& other
)
62 : fullPath (other
.fullPath
)
66 File
& File::operator= (const String
& newPath
)
68 fullPath
= parseAbsolutePath (newPath
);
72 File
& File::operator= (const File
& other
)
74 fullPath
= other
.fullPath
;
78 const File
File::nonexistent
;
81 //==============================================================================
82 String
File::parseAbsolutePath (const String
& p
)
89 String
path (p
.replaceCharacter ('/', '\\'));
91 if (path
.startsWithChar (File::separator
))
93 if (path
[1] != File::separator
)
95 /* When you supply a raw string to the File object constructor, it must be an absolute path.
96 If you're trying to parse a string that may be either a relative path or an absolute path,
97 you MUST provide a context against which the partial path can be evaluated - you can do
98 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
99 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
100 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
104 path
= File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path
;
107 else if (! path
.containsChar (':'))
109 /* When you supply a raw string to the File object constructor, it must be an absolute path.
110 If you're trying to parse a string that may be either a relative path or an absolute path,
111 you MUST provide a context against which the partial path can be evaluated - you can do
112 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
113 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
114 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
118 return File::getCurrentWorkingDirectory().getChildFile (path
).getFullPathName();
123 // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
124 // to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
125 // If that's why you've ended up here, use File::getChildFile() to build your paths instead.
126 jassert ((! p
.containsChar ('\\')) || (p
.indexOfChar ('/') >= 0 && p
.indexOfChar ('/') < p
.indexOfChar ('\\')));
130 if (path
.startsWithChar ('~'))
132 if (path
[1] == File::separator
|| path
[1] == 0)
134 // expand a name of the form "~/abc"
135 path
= File::getSpecialLocation (File::userHomeDirectory
).getFullPathName()
136 + path
.substring (1);
140 // expand a name of type "~dave/abc"
141 const String
userName (path
.substring (1).upToFirstOccurrenceOf ("/", false, false));
143 struct passwd
* const pw
= getpwnam (userName
.toUTF8());
145 path
= addTrailingSeparator (pw
->pw_dir
) + path
.fromFirstOccurrenceOf ("/", false, false);
148 else if (! path
.startsWithChar (File::separator
))
150 /* When you supply a raw string to the File object constructor, it must be an absolute path.
151 If you're trying to parse a string that may be either a relative path or an absolute path,
152 you MUST provide a context against which the partial path can be evaluated - you can do
153 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
154 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
155 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
157 jassert (path
.startsWith ("./") || path
.startsWith ("../")); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD)
159 return File::getCurrentWorkingDirectory().getChildFile (path
).getFullPathName();
163 while (path
.endsWithChar (separator
) && path
!= separatorString
) // careful not to turn a single "/" into an empty string.
164 path
= path
.dropLastCharacters (1);
169 String
File::addTrailingSeparator (const String
& path
)
171 return path
.endsWithChar (File::separator
) ? path
172 : path
+ File::separator
;
175 //==============================================================================
177 #define NAMES_ARE_CASE_SENSITIVE 1
180 bool File::areFileNamesCaseSensitive()
182 #if NAMES_ARE_CASE_SENSITIVE
189 bool File::operator== (const File
& other
) const
191 #if NAMES_ARE_CASE_SENSITIVE
192 return fullPath
== other
.fullPath
;
194 return fullPath
.equalsIgnoreCase (other
.fullPath
);
198 bool File::operator!= (const File
& other
) const
200 return ! operator== (other
);
203 bool File::operator< (const File
& other
) const
205 #if NAMES_ARE_CASE_SENSITIVE
206 return fullPath
< other
.fullPath
;
208 return fullPath
.compareIgnoreCase (other
.fullPath
) < 0;
212 bool File::operator> (const File
& other
) const
214 #if NAMES_ARE_CASE_SENSITIVE
215 return fullPath
> other
.fullPath
;
217 return fullPath
.compareIgnoreCase (other
.fullPath
) > 0;
221 //==============================================================================
222 bool File::setReadOnly (const bool shouldBeReadOnly
,
223 const bool applyRecursively
) const
227 if (applyRecursively
&& isDirectory())
229 Array
<File
> subFiles
;
230 findChildFiles (subFiles
, File::findFilesAndDirectories
, false);
232 for (int i
= subFiles
.size(); --i
>= 0;)
233 worked
= subFiles
.getReference(i
).setReadOnly (shouldBeReadOnly
, true) && worked
;
236 return setFileReadOnlyInternal (shouldBeReadOnly
) && worked
;
239 bool File::deleteRecursively() const
245 Array
<File
> subFiles
;
246 findChildFiles (subFiles
, File::findFilesAndDirectories
, false);
248 for (int i
= subFiles
.size(); --i
>= 0;)
249 worked
= subFiles
.getReference(i
).deleteRecursively() && worked
;
252 return deleteFile() && worked
;
255 bool File::moveFileTo (const File
& newFile
) const
257 if (newFile
.fullPath
== fullPath
)
260 #if ! NAMES_ARE_CASE_SENSITIVE
261 if (*this != newFile
)
263 if (! newFile
.deleteFile())
266 return moveInternal (newFile
);
269 bool File::copyFileTo (const File
& newFile
) const
271 return (*this == newFile
)
272 || (exists() && newFile
.deleteFile() && copyInternal (newFile
));
275 bool File::copyDirectoryTo (const File
& newDirectory
) const
277 if (isDirectory() && newDirectory
.createDirectory())
279 Array
<File
> subFiles
;
280 findChildFiles (subFiles
, File::findFiles
, false);
283 for (i
= 0; i
< subFiles
.size(); ++i
)
284 if (! subFiles
.getReference(i
).copyFileTo (newDirectory
.getChildFile (subFiles
.getReference(i
).getFileName())))
288 findChildFiles (subFiles
, File::findDirectories
, false);
290 for (i
= 0; i
< subFiles
.size(); ++i
)
291 if (! subFiles
.getReference(i
).copyDirectoryTo (newDirectory
.getChildFile (subFiles
.getReference(i
).getFileName())))
300 //==============================================================================
301 String
File::getPathUpToLastSlash() const
303 const int lastSlash
= fullPath
.lastIndexOfChar (separator
);
306 return fullPath
.substring (0, lastSlash
);
307 else if (lastSlash
== 0)
308 return separatorString
;
313 File
File::getParentDirectory() const
315 return File (getPathUpToLastSlash(), (int) 0);
318 //==============================================================================
319 String
File::getFileName() const
321 return fullPath
.substring (fullPath
.lastIndexOfChar (separator
) + 1);
324 int File::hashCode() const
326 return fullPath
.hashCode();
329 int64
File::hashCode64() const
331 return fullPath
.hashCode64();
334 String
File::getFileNameWithoutExtension() const
336 const int lastSlash
= fullPath
.lastIndexOfChar (separator
) + 1;
337 const int lastDot
= fullPath
.lastIndexOfChar ('.');
339 if (lastDot
> lastSlash
)
340 return fullPath
.substring (lastSlash
, lastDot
);
342 return fullPath
.substring (lastSlash
);
345 bool File::isAChildOf (const File
& potentialParent
) const
347 if (potentialParent
== File::nonexistent
)
350 const String
ourPath (getPathUpToLastSlash());
352 #if NAMES_ARE_CASE_SENSITIVE
353 if (potentialParent
.fullPath
== ourPath
)
355 if (potentialParent
.fullPath
.equalsIgnoreCase (ourPath
))
360 else if (potentialParent
.fullPath
.length() >= ourPath
.length())
366 return getParentDirectory().isAChildOf (potentialParent
);
370 //==============================================================================
371 bool File::isAbsolutePath (const String
& path
)
373 return path
.startsWithChar (separator
)
375 || (path
.isNotEmpty() && path
[1] == ':');
377 || path
.startsWithChar ('~');
381 File
File::getChildFile (String relativePath
) const
383 if (isAbsolutePath (relativePath
))
384 return File (relativePath
);
386 String
path (fullPath
);
388 // It's relative, so remove any ../ or ./ bits at the start..
389 if (relativePath
[0] == '.')
392 relativePath
= relativePath
.replaceCharacter ('/', '\\').trimStart();
394 relativePath
= relativePath
.trimStart();
397 while (relativePath
[0] == '.')
399 if (relativePath
[1] == '.')
401 if (relativePath
[2] == 0 || relativePath
[2] == separator
)
403 const int lastSlash
= path
.lastIndexOfChar (separator
);
405 path
= path
.substring (0, lastSlash
);
407 relativePath
= relativePath
.substring (3);
414 else if (relativePath
[1] == separator
)
416 relativePath
= relativePath
.substring (2);
425 return File (addTrailingSeparator (path
) + relativePath
);
428 File
File::getSiblingFile (const String
& fileName
) const
430 return getParentDirectory().getChildFile (fileName
);
433 //==============================================================================
434 String
File::descriptionOfSizeInBytes (const int64 bytes
)
436 if (bytes
== 1) return "1 byte";
437 else if (bytes
< 1024) return String (bytes
) + " bytes";
438 else if (bytes
< 1024 * 1024) return String (bytes
/ 1024.0, 1) + " KB";
439 else if (bytes
< 1024 * 1024 * 1024) return String (bytes
/ (1024.0 * 1024.0), 1) + " MB";
440 else return String (bytes
/ (1024.0 * 1024.0 * 1024.0), 1) + " GB";
443 //==============================================================================
444 Result
File::create() const
449 const File
parentDir (getParentDirectory());
451 if (parentDir
== *this)
452 return Result::fail ("Cannot create parent directory");
454 Result
r (parentDir
.createDirectory());
458 FileOutputStream
fo (*this, 8);
466 Result
File::createDirectory() const
471 const File
parentDir (getParentDirectory());
473 if (parentDir
== *this)
474 return Result::fail ("Cannot create parent directory");
476 Result
r (parentDir
.createDirectory());
479 r
= createDirectoryInternal (fullPath
.trimCharactersAtEnd (separatorString
));
484 //==============================================================================
485 Time
File::getLastModificationTime() const { int64 m
, a
, c
; getFileTimesInternal (m
, a
, c
); return Time (m
); }
486 Time
File::getLastAccessTime() const { int64 m
, a
, c
; getFileTimesInternal (m
, a
, c
); return Time (a
); }
487 Time
File::getCreationTime() const { int64 m
, a
, c
; getFileTimesInternal (m
, a
, c
); return Time (c
); }
489 bool File::setLastModificationTime (const Time
& t
) const { return setFileTimesInternal (t
.toMilliseconds(), 0, 0); }
490 bool File::setLastAccessTime (const Time
& t
) const { return setFileTimesInternal (0, t
.toMilliseconds(), 0); }
491 bool File::setCreationTime (const Time
& t
) const { return setFileTimesInternal (0, 0, t
.toMilliseconds()); }
493 //==============================================================================
494 bool File::loadFileAsData (MemoryBlock
& destBlock
) const
496 if (! existsAsFile())
499 FileInputStream
in (*this);
500 return getSize() == in
.readIntoMemoryBlock (destBlock
);
503 String
File::loadFileAsString() const
505 if (! existsAsFile())
506 return String::empty
;
508 FileInputStream
in (*this);
509 return in
.readEntireStreamAsString();
512 //==============================================================================
513 int File::findChildFiles (Array
<File
>& results
,
514 const int whatToLookFor
,
515 const bool searchRecursively
,
516 const String
& wildCardPattern
) const
518 DirectoryIterator
di (*this, searchRecursively
, wildCardPattern
, whatToLookFor
);
523 results
.add (di
.getFile());
530 int File::getNumberOfChildFiles (const int whatToLookFor
, const String
& wildCardPattern
) const
532 DirectoryIterator
di (*this, false, wildCardPattern
, whatToLookFor
);
541 bool File::containsSubDirectories() const
545 DirectoryIterator
di (*this, false, "*", findDirectories
);
552 //==============================================================================
553 File
File::getNonexistentChildFile (const String
& prefix_
,
554 const String
& suffix
,
555 bool putNumbersInBrackets
) const
557 File
f (getChildFile (prefix_
+ suffix
));
562 String
prefix (prefix_
);
564 // remove any bracketed numbers that may already be on the end..
565 if (prefix
.trim().endsWithChar (')'))
567 putNumbersInBrackets
= true;
569 const int openBracks
= prefix
.lastIndexOfChar ('(');
570 const int closeBracks
= prefix
.lastIndexOfChar (')');
573 && closeBracks
> openBracks
574 && prefix
.substring (openBracks
+ 1, closeBracks
).containsOnly ("0123456789"))
576 num
= prefix
.substring (openBracks
+ 1, closeBracks
).getIntValue() + 1;
577 prefix
= prefix
.substring (0, openBracks
);
581 // also use brackets if it ends in a digit.
582 putNumbersInBrackets
= putNumbersInBrackets
583 || CharacterFunctions::isDigit (prefix
.getLastCharacter());
587 String
newName (prefix
);
589 if (putNumbersInBrackets
)
590 newName
<< '(' << num
++ << ')';
594 f
= getChildFile (newName
+ suffix
);
596 } while (f
.exists());
602 File
File::getNonexistentSibling (const bool putNumbersInBrackets
) const
605 return getParentDirectory()
606 .getNonexistentChildFile (getFileNameWithoutExtension(),
608 putNumbersInBrackets
);
612 //==============================================================================
613 String
File::getFileExtension() const
615 const int indexOfDot
= fullPath
.lastIndexOfChar ('.');
617 if (indexOfDot
> fullPath
.lastIndexOfChar (separator
))
618 return fullPath
.substring (indexOfDot
);
620 return String::empty
;
623 bool File::hasFileExtension (const String
& possibleSuffix
) const
625 if (possibleSuffix
.isEmpty())
626 return fullPath
.lastIndexOfChar ('.') <= fullPath
.lastIndexOfChar (separator
);
628 const int semicolon
= possibleSuffix
.indexOfChar (0, ';');
632 return hasFileExtension (possibleSuffix
.substring (0, semicolon
).trimEnd())
633 || hasFileExtension (possibleSuffix
.substring (semicolon
+ 1).trimStart());
637 if (fullPath
.endsWithIgnoreCase (possibleSuffix
))
639 if (possibleSuffix
.startsWithChar ('.'))
642 const int dotPos
= fullPath
.length() - possibleSuffix
.length() - 1;
645 return fullPath
[dotPos
] == '.';
652 File
File::withFileExtension (const String
& newExtension
) const
654 if (fullPath
.isEmpty())
655 return File::nonexistent
;
657 String
filePart (getFileName());
659 int i
= filePart
.lastIndexOfChar ('.');
661 filePart
= filePart
.substring (0, i
);
663 if (newExtension
.isNotEmpty() && ! newExtension
.startsWithChar ('.'))
666 return getSiblingFile (filePart
+ newExtension
);
669 //==============================================================================
670 bool File::startAsProcess (const String
& parameters
) const
672 return exists() && PlatformUtilities::openDocument (fullPath
, parameters
);
675 //==============================================================================
676 FileInputStream
* File::createInputStream() const
679 return new FileInputStream (*this);
684 FileOutputStream
* File::createOutputStream (const int bufferSize
) const
686 ScopedPointer
<FileOutputStream
> out (new FileOutputStream (*this, bufferSize
));
688 if (out
->failedToOpen())
691 return out
.release();
694 //==============================================================================
695 bool File::appendData (const void* const dataToAppend
,
696 const int numberOfBytes
) const
698 if (numberOfBytes
> 0)
700 const ScopedPointer
<FileOutputStream
> out (createOutputStream());
705 out
->write (dataToAppend
, numberOfBytes
);
711 bool File::replaceWithData (const void* const dataToWrite
,
712 const int numberOfBytes
) const
714 jassert (numberOfBytes
>= 0); // a negative number of bytes??
716 if (numberOfBytes
<= 0)
719 TemporaryFile
tempFile (*this, TemporaryFile::useHiddenFile
);
720 tempFile
.getFile().appendData (dataToWrite
, numberOfBytes
);
721 return tempFile
.overwriteTargetFileWithTemporary();
724 bool File::appendText (const String
& text
,
725 const bool asUnicode
,
726 const bool writeUnicodeHeaderBytes
) const
728 const ScopedPointer
<FileOutputStream
> out (createOutputStream());
732 out
->writeText (text
, asUnicode
, writeUnicodeHeaderBytes
);
739 bool File::replaceWithText (const String
& textToWrite
,
740 const bool asUnicode
,
741 const bool writeUnicodeHeaderBytes
) const
743 TemporaryFile
tempFile (*this, TemporaryFile::useHiddenFile
);
744 tempFile
.getFile().appendText (textToWrite
, asUnicode
, writeUnicodeHeaderBytes
);
745 return tempFile
.overwriteTargetFileWithTemporary();
748 bool File::hasIdenticalContentTo (const File
& other
) const
753 if (getSize() == other
.getSize() && existsAsFile() && other
.existsAsFile())
755 FileInputStream
in1 (*this), in2 (other
);
757 const int bufferSize
= 4096;
758 HeapBlock
<char> buffer1 (bufferSize
), buffer2 (bufferSize
);
762 const int num1
= in1
.read (buffer1
, bufferSize
);
763 const int num2
= in2
.read (buffer2
, bufferSize
);
771 if (memcmp (buffer1
, buffer2
, num1
) != 0)
779 //==============================================================================
780 String
File::createLegalPathName (const String
& original
)
787 start
= s
.substring (0, 2);
791 return start
+ s
.removeCharacters ("\"#@,;:<>*^|?")
792 .substring (0, 1024);
795 String
File::createLegalFileName (const String
& original
)
797 String
s (original
.removeCharacters ("\"#@,;:<>*^|?\\/"));
799 const int maxLength
= 128; // only the length of the filename, not the whole path
800 const int len
= s
.length();
804 const int lastDot
= s
.lastIndexOfChar ('.');
806 if (lastDot
> jmax (0, len
- 12))
808 s
= s
.substring (0, maxLength
- (len
- lastDot
))
809 + s
.substring (lastDot
);
813 s
= s
.substring (0, maxLength
);
820 //==============================================================================
821 String
File::getRelativePathFrom (const File
& dir
) const
823 String
thisPath (fullPath
);
825 while (thisPath
.endsWithChar (separator
))
826 thisPath
= thisPath
.dropLastCharacters (1);
828 String
dirPath (addTrailingSeparator (dir
.existsAsFile() ? dir
.getParentDirectory().getFullPathName()
831 const int len
= jmin (thisPath
.length(), dirPath
.length());
832 int commonBitLength
= 0;
835 String::CharPointerType
thisPathIter (thisPath
.getCharPointer());
836 String::CharPointerType
dirPathIter (dirPath
.getCharPointer());
838 for (int i
= 0; i
< len
; ++i
)
840 const juce_wchar c1
= thisPathIter
.getAndAdvance();
841 const juce_wchar c2
= dirPathIter
.getAndAdvance();
843 #if NAMES_ARE_CASE_SENSITIVE
846 if (c1
!= c2
&& CharacterFunctions::toLowerCase (c1
) != CharacterFunctions::toLowerCase (c2
))
854 while (commonBitLength
> 0 && thisPath
[commonBitLength
- 1] != File::separator
)
857 // if the only common bit is the root, then just return the full path..
858 if (commonBitLength
<= 0
859 || (commonBitLength
== 1 && thisPath
[1] == File::separator
))
862 thisPath
= thisPath
.substring (commonBitLength
);
863 dirPath
= dirPath
.substring (commonBitLength
);
865 while (dirPath
.isNotEmpty())
868 thisPath
= "..\\" + thisPath
;
870 thisPath
= "../" + thisPath
;
873 const int sep
= dirPath
.indexOfChar (separator
);
876 dirPath
= dirPath
.substring (sep
+ 1);
878 dirPath
= String::empty
;
884 //==============================================================================
885 File
File::createTempFile (const String
& fileNameEnding
)
887 const File
tempFile (getSpecialLocation (tempDirectory
)
888 .getChildFile ("temp_" + String (Random::getSystemRandom().nextInt()))
889 .withFileExtension (fileNameEnding
));
891 if (tempFile
.exists())
892 return createTempFile (fileNameEnding
);
898 //==============================================================================
901 #include "../../utilities/juce_UnitTest.h"
902 #include "../../maths/juce_Random.h"
903 #include "juce_MemoryMappedFile.h"
906 class FileTests
: public UnitTest
909 FileTests() : UnitTest ("Files") {}
913 beginTest ("Reading");
915 const File
home (File::getSpecialLocation (File::userHomeDirectory
));
916 const File
temp (File::getSpecialLocation (File::tempDirectory
));
918 expect (! File::nonexistent
.exists());
919 expect (home
.isDirectory());
920 expect (home
.exists());
921 expect (! home
.existsAsFile());
922 expect (File::getSpecialLocation (File::userDocumentsDirectory
).isDirectory());
923 expect (File::getSpecialLocation (File::userApplicationDataDirectory
).isDirectory());
924 expect (File::getSpecialLocation (File::currentExecutableFile
).exists());
925 expect (File::getSpecialLocation (File::currentApplicationFile
).exists());
926 expect (File::getSpecialLocation (File::invokedExecutableFile
).exists());
927 expect (home
.getVolumeTotalSize() > 1024 * 1024);
928 expect (home
.getBytesFreeOnVolume() > 0);
929 expect (! home
.isHidden());
930 expect (home
.isOnHardDisk());
931 expect (! home
.isOnCDRomDrive());
932 expect (File::getCurrentWorkingDirectory().exists());
933 expect (home
.setAsCurrentWorkingDirectory());
934 expect (File::getCurrentWorkingDirectory() == home
);
938 File::findFileSystemRoots (roots
);
939 expect (roots
.size() > 0);
941 int numRootsExisting
= 0;
942 for (int i
= 0; i
< roots
.size(); ++i
)
943 if (roots
[i
].exists())
946 // (on windows, some of the drives may not contain media, so as long as at least one is ok..)
947 expect (numRootsExisting
> 0);
950 beginTest ("Writing");
952 File
demoFolder (temp
.getChildFile ("Juce UnitTests Temp Folder.folder"));
953 expect (demoFolder
.deleteRecursively());
954 expect (demoFolder
.createDirectory());
955 expect (demoFolder
.isDirectory());
956 expect (demoFolder
.getParentDirectory() == temp
);
957 expect (temp
.isDirectory());
961 temp
.findChildFiles (files
, File::findFilesAndDirectories
, false, "*");
962 expect (files
.contains (demoFolder
));
967 temp
.findChildFiles (files
, File::findDirectories
, true, "*.folder");
968 expect (files
.contains (demoFolder
));
971 File
tempFile (demoFolder
.getNonexistentChildFile ("test", ".txt", false));
973 expect (tempFile
.getFileExtension() == ".txt");
974 expect (tempFile
.hasFileExtension (".txt"));
975 expect (tempFile
.hasFileExtension ("txt"));
976 expect (tempFile
.withFileExtension ("xyz").hasFileExtension (".xyz"));
977 expect (tempFile
.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
978 expect (tempFile
.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
979 expect (! tempFile
.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
980 expect (tempFile
.getSiblingFile ("foo").isAChildOf (temp
));
981 expect (tempFile
.hasWriteAccess());
984 FileOutputStream
fo (tempFile
);
985 fo
.write ("0123456789", 10);
988 expect (tempFile
.exists());
989 expect (tempFile
.getSize() == 10);
990 expect (std::abs ((int) (tempFile
.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
991 expectEquals (tempFile
.loadFileAsString(), String ("0123456789"));
992 expect (! demoFolder
.containsSubDirectories());
994 expectEquals (tempFile
.getRelativePathFrom (demoFolder
.getParentDirectory()), demoFolder
.getFileName() + File::separatorString
+ tempFile
.getFileName());
995 expectEquals (demoFolder
.getParentDirectory().getRelativePathFrom (tempFile
), ".." + File::separatorString
+ ".." + File::separatorString
+ demoFolder
.getParentDirectory().getFileName());
997 expect (demoFolder
.getNumberOfChildFiles (File::findFiles
) == 1);
998 expect (demoFolder
.getNumberOfChildFiles (File::findFilesAndDirectories
) == 1);
999 expect (demoFolder
.getNumberOfChildFiles (File::findDirectories
) == 0);
1000 demoFolder
.getNonexistentChildFile ("tempFolder", "", false).createDirectory();
1001 expect (demoFolder
.getNumberOfChildFiles (File::findDirectories
) == 1);
1002 expect (demoFolder
.getNumberOfChildFiles (File::findFilesAndDirectories
) == 2);
1003 expect (demoFolder
.containsSubDirectories());
1005 expect (tempFile
.hasWriteAccess());
1006 tempFile
.setReadOnly (true);
1007 expect (! tempFile
.hasWriteAccess());
1008 tempFile
.setReadOnly (false);
1009 expect (tempFile
.hasWriteAccess());
1011 Time
t (Time::getCurrentTime());
1012 tempFile
.setLastModificationTime (t
);
1013 Time t2
= tempFile
.getLastModificationTime();
1014 expect (std::abs ((int) (t2
.toMilliseconds() - t
.toMilliseconds())) <= 1000);
1018 tempFile
.loadFileAsData (mb
);
1019 expect (mb
.getSize() == 10);
1020 expect (mb
[0] == '0');
1023 beginTest ("Memory-mapped files");
1026 MemoryMappedFile
mmf (tempFile
, MemoryMappedFile::readOnly
);
1027 expect (mmf
.getSize() == 10);
1028 expect (mmf
.getData() != nullptr);
1029 expect (memcmp (mmf
.getData(), "0123456789", 10) == 0);
1033 const File
tempFile2 (tempFile
.getNonexistentSibling (false));
1034 expect (tempFile2
.create());
1035 expect (tempFile2
.appendData ("xxxxxxxxxx", 10));
1038 MemoryMappedFile
mmf (tempFile2
, MemoryMappedFile::readWrite
);
1039 expect (mmf
.getSize() == 10);
1040 expect (mmf
.getData() != nullptr);
1041 memcpy (mmf
.getData(), "abcdefghij", 10);
1045 MemoryMappedFile
mmf (tempFile2
, MemoryMappedFile::readWrite
);
1046 expect (mmf
.getSize() == 10);
1047 expect (mmf
.getData() != nullptr);
1048 expect (memcmp (mmf
.getData(), "abcdefghij", 10) == 0);
1051 expect (tempFile2
.deleteFile());
1054 beginTest ("More writing");
1056 expect (tempFile
.appendData ("abcdefghij", 10));
1057 expect (tempFile
.getSize() == 20);
1058 expect (tempFile
.replaceWithData ("abcdefghij", 10));
1059 expect (tempFile
.getSize() == 10);
1061 File
tempFile2 (tempFile
.getNonexistentSibling (false));
1062 expect (tempFile
.copyFileTo (tempFile2
));
1063 expect (tempFile2
.exists());
1064 expect (tempFile2
.hasIdenticalContentTo (tempFile
));
1065 expect (tempFile
.deleteFile());
1066 expect (! tempFile
.exists());
1067 expect (tempFile2
.moveFileTo (tempFile
));
1068 expect (tempFile
.exists());
1069 expect (! tempFile2
.exists());
1071 expect (demoFolder
.deleteRecursively());
1072 expect (! demoFolder
.exists());
1076 static FileTests fileUnitTests
;