27 : fullPath (parseAbsolutePath (fullPathName))
39 : fullPath (other.fullPath)
45 fullPath = parseAbsolutePath (newPath);
51 fullPath = other.fullPath;
56 : fullPath (std::move (other.fullPath))
62 fullPath = std::move (other.fullPath);
79 bool anythingChanged =
false;
81 for (
int i = 1; i < toks.
size(); ++i)
85 if (t ==
".." && toks[i - 1] !=
"..")
87 anythingChanged =
true;
93 anythingChanged =
true;
105static String normaliseSeparators (
const String& path)
107 auto normalisedPath = path;
110 String doubleSeparator (separator + separator);
112 auto uncPath = normalisedPath.startsWith (doubleSeparator)
113 && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator,
false,
false).startsWith (separator);
116 normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator,
false,
false);
118 while (normalisedPath.contains (doubleSeparator))
119 normalisedPath = normalisedPath.replace (doubleSeparator, separator);
121 return uncPath ? doubleSeparator + normalisedPath
137 auto path = normaliseSeparators (removeEllipsis (p.
replaceCharacter (
'/',
'\\')));
155 else if (! path.containsChar (
':'))
176 auto path = normaliseSeparators (removeEllipsis (p));
178 if (path.startsWithChar (
'~'))
191 if (
auto* pw = getpwnam (userName.toUTF8()))
197 #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
198 if (! (path.startsWith (
"./") || path.startsWith (
"../")))
209 #if JUCE_LOG_ASSERTIONS
232#if JUCE_LINUX || JUCE_BSD
233 #define NAMES_ARE_CASE_SENSITIVE 1
238 #if NAMES_ARE_CASE_SENSITIVE
245static int compareFilenames (
const String& name1,
const String& name2)
noexcept
247 #if NAMES_ARE_CASE_SENSITIVE
248 return name1.compare (name2);
250 return name1.compareIgnoreCase (name2);
261 const bool applyRecursively)
const
267 worked = f.setReadOnly (shouldBeReadOnly,
true) && worked;
269 return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
274 return setFileExecutableInternal (shouldBeExecutable);
283 worked = f.deleteRecursively (followSymlinks) && worked;
290 if (newFile.fullPath == fullPath)
296 #if ! NAMES_ARE_CASE_SENSITIVE
297 if (*
this != newFile)
302 return moveInternal (newFile);
307 return (*
this == newFile)
313 if (newFile.fullPath == fullPath)
319 if (! replaceInternal (newFile))
331 if (! f.copyFileTo (newDirectory.
getChildFile (f.getFileName())))
335 if (! f.copyDirectoryTo (newDirectory.
getChildFile (f.getFileName())))
345String File::getPathUpToLastSlash()
const
350 return fullPath.
substring (0, lastSlash);
363bool File::isNonEmptyDirectory()
const
382 if (lastDot > lastSlash)
383 return fullPath.
substring (lastSlash, lastDot);
390 if (potentialParent.fullPath.
isEmpty())
393 auto ourPath = getPathUpToLastSlash();
395 if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
398 if (potentialParent.fullPath.
length() >= ourPath.length())
410 auto firstChar = *(path.
text);
414 || (firstChar != 0 && path.
text[1] ==
':');
422 auto r = relativePath.
text;
428 if (r.indexOf ((juce_wchar)
'/') >= 0)
432 auto path = fullPath;
438 auto secondChar = *++r;
440 if (secondChar ==
'.')
442 auto thirdChar = *++r;
444 if (thirdChar == separatorChar || thirdChar == 0)
446 auto lastSlash = path.lastIndexOfChar (separatorChar);
449 path = path.substring (0, lastSlash);
451 while (*r == separatorChar)
460 else if (secondChar == separatorChar || secondChar == 0)
462 while (*r == separatorChar)
473 path.appendCharPointer (r);
488 if (bytes == 1) { suffix =
" byte"; }
489 else if (bytes < 1024) { suffix =
" bytes"; }
490 else if (bytes < 1024 * 1024) { suffix =
" KB"; divisor = 1024.0; }
491 else if (bytes < 1024 * 1024 * 1024) { suffix =
" MB"; divisor = 1024.0 * 1024.0; }
492 else { suffix =
" GB"; divisor = 1024.0 * 1024.0 * 1024.0; }
494 return (divisor > 0 ?
String ((
double) bytes / divisor, 1) :
String (bytes)) + suffix;
505 if (parentDir == *
this)
508 auto r = parentDir.createDirectory();
526 if (parentDir == *
this)
529 auto r = parentDir.createDirectory();
575 findChildFiles (results, whatToLookFor, searchRecursively, wildcard, followSymlinks);
583 for (
const auto& di :
RangedDirectoryIterator (*
this, searchRecursively, wildcard, whatToLookFor, followSymlinks))
585 results.
add (di.getFile());
611 bool putNumbersInBrackets)
const
618 auto prefix = suggestedPrefix;
621 if (prefix.trim().endsWithChar (
')'))
623 putNumbersInBrackets =
true;
626 auto closeBracks = prefix.lastIndexOfChar (
')');
629 && closeBracks > openBracks
630 && prefix.substring (openBracks + 1, closeBracks).containsOnly (
"0123456789"))
632 number = prefix.substring (openBracks + 1, closeBracks).getIntValue();
633 prefix = prefix.substring (0, openBracks);
639 auto newName = prefix;
641 if (putNumbersInBrackets)
643 newName <<
'(' << ++number <<
')';
655 }
while (f.exists());
668 putNumbersInBrackets);
687 auto semicolon = possibleSuffix.
text.indexOf ((juce_wchar)
';');
695 if (possibleSuffix.
text[0] ==
'.')
698 auto dotPos = fullPath.
length() - possibleSuffix.
length() - 1;
701 return fullPath[dotPos] ==
'.';
714 auto lastDot = filePart.lastIndexOfChar (
'.');
717 filePart = filePart.substring (0, lastDot);
734 auto fin = std::make_unique<FileInputStream> (*
this);
744 auto fout = std::make_unique<FileOutputStream> (*
this, bufferSize);
746 if (fout->openedOk())
754 const size_t numberOfBytes)
const
756 jassert (((ssize_t) numberOfBytes) >= 0);
758 if (numberOfBytes == 0)
762 return fout.
openedOk() && fout.
write (dataToAppend, numberOfBytes);
766 const size_t numberOfBytes)
const
768 if (numberOfBytes == 0)
783 return fout.
writeText (text, asUnicode, writeHeaderBytes, lineFeed);
789 tempFile.
getFile().
appendText (textToWrite, asUnicode, writeHeaderBytes, lineFeed);
802 if (in1.openedOk() && in2.
openedOk())
804 const int bufferSize = 4096;
809 auto num1 = in1.read (buffer1, bufferSize);
810 auto num2 = in2.
read (buffer2, bufferSize);
818 if (memcmp (buffer1, buffer2, (
size_t) num1) != 0)
833 if (s.isNotEmpty() && s[1] ==
':')
847 const int maxLength = 128;
852 auto lastDot = s.lastIndexOfChar (
'.');
854 if (lastDot > jmax (0, len - 12))
856 s = s.substring (0, maxLength - (len - lastDot))
857 + s.substring (lastDot);
861 s = s.substring (0, maxLength);
869static int countNumberOfSeparators (String::CharPointerType s)
875 auto c = s.getAndAdvance();
892 auto thisPath = fullPath;
900 int commonBitLength = 0;
901 auto thisPathAfterCommon = thisPath.getCharPointer();
902 auto dirPathAfterCommon = dirPath.getCharPointer();
905 auto thisPathIter = thisPath.getCharPointer();
906 auto dirPathIter = dirPath.getCharPointer();
910 auto c1 = thisPathIter.getAndAdvance();
911 auto c2 = dirPathIter.getAndAdvance();
913 #if NAMES_ARE_CASE_SENSITIVE
925 thisPathAfterCommon = thisPathIter;
926 dirPathAfterCommon = dirPathIter;
933 if (commonBitLength == 0 || (commonBitLength == 1 && thisPath[1] ==
getSeparatorChar()))
936 auto numUpDirectoriesNeeded = countNumberOfSeparators (dirPathAfterCommon);
938 if (numUpDirectoriesNeeded == 0)
939 return thisPathAfterCommon;
946 s.appendCharPointer (thisPathAfterCommon);
957 if (tempFile.exists())
964 [[maybe_unused]]
const String& nativePathOfTarget,
965 bool overwriteExisting)
967 if (linkFileToCreate.
exists())
977 if (overwriteExisting)
981 #if JUCE_MAC || JUCE_LINUX || JUCE_BSD
994 nativePathOfTarget.toWideCharPointer(),
995 targetFile.
isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != FALSE;
1018#if JUCE_ALLOW_STATIC_NULL_VARIABLES
1020JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
1021JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1025JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1026JUCE_END_IGNORE_WARNINGS_MSVC
1032 : range (0, file.getSize())
1034 openInternal (file, mode, exclusive);
1038 : range (fileRange.getIntersectionWith (
Range<int64> (0, file.getSize())))
1040 openInternal (file, mode, exclusive);
1048class FileTests final :
public UnitTest
1052 :
UnitTest (
"Files", UnitTestCategories::files)
1055 void runTest()
override
1057 beginTest (
"Reading");
1062 expect (! File().exists());
1063 expect (! File().existsAsFile());
1064 expect (! File().isDirectory());
1066 expect (File (
"/").isDirectory());
1068 expect (home.isDirectory());
1069 expect (home.exists());
1070 expect (! home.existsAsFile());
1075 expect (home.getVolumeTotalSize() > 1024 * 1024);
1076 expect (home.getBytesFreeOnVolume() > 0);
1077 expect (! home.isHidden());
1078 expect (home.isOnHardDisk());
1079 expect (! home.isOnCDRomDrive());
1081 expect (home.setAsCurrentWorkingDirectory());
1084 auto homeParent = home;
1085 bool noSymlinks =
true;
1087 while (! homeParent.isRoot())
1089 if (homeParent.isSymbolicLink())
1095 homeParent = homeParent.getParentDirectory();
1105 expect (roots.size() > 0);
1107 int numRootsExisting = 0;
1108 for (
int i = 0; i < roots.size(); ++i)
1109 if (roots[i].exists())
1113 expect (numRootsExisting > 0);
1116 beginTest (
"Writing");
1118 auto random = getRandom();
1119 const auto tempFolderName =
"JUCE UnitTests Temp Folder "
1122 File demoFolder (temp.getChildFile (tempFolderName));
1123 expect (demoFolder.deleteRecursively());
1124 expect (demoFolder.createDirectory());
1125 expect (demoFolder.isDirectory());
1126 expect (demoFolder.getParentDirectory() == temp);
1127 expect (temp.isDirectory());
1131 File tempFile (demoFolder.getNonexistentChildFile (
"test",
".txt",
false));
1133 expect (tempFile.getFileExtension() ==
".txt");
1134 expect (tempFile.hasFileExtension (
".txt"));
1135 expect (tempFile.hasFileExtension (
"txt"));
1136 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
".xyz"));
1137 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
"abc;xyz;foo"));
1138 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
"xyz;foo"));
1139 expect (! tempFile.withFileExtension (
"h").hasFileExtension (
"bar;foo;xx"));
1140 expect (tempFile.getSiblingFile (
"foo").isAChildOf (temp));
1141 expect (tempFile.hasWriteAccess());
1143 expect (home.getChildFile (
".") == home);
1144 expect (home.getChildFile (
"..") == home.getParentDirectory());
1145 expect (home.getChildFile (
".xyz").getFileName() ==
".xyz");
1146 expect (home.getChildFile (
"..xyz").getFileName() ==
"..xyz");
1147 expect (home.getChildFile (
"...xyz").getFileName() ==
"...xyz");
1148 expect (home.getChildFile (
"./xyz") == home.getChildFile (
"xyz"));
1149 expect (home.getChildFile (
"././xyz") == home.getChildFile (
"xyz"));
1150 expect (home.getChildFile (
"../xyz") == home.getParentDirectory().getChildFile (
"xyz"));
1151 expect (home.getChildFile (
".././xyz") == home.getParentDirectory().getChildFile (
"xyz"));
1152 expect (home.getChildFile (
".././xyz/./abc") == home.getParentDirectory().getChildFile (
"xyz/abc"));
1153 expect (home.getChildFile (
"./../xyz") == home.getParentDirectory().getChildFile (
"xyz"));
1154 expect (home.getChildFile (
"a1/a2/a3/./../../a4") == home.getChildFile (
"a1/a4"));
1156 expect (! File().hasReadAccess());
1157 expect (! File().hasWriteAccess());
1159 expect (! tempFile.hasReadAccess());
1162 FileOutputStream fo (tempFile);
1163 fo.write (
"0123456789", 10);
1166 expect (tempFile.hasReadAccess());
1168 expect (tempFile.exists());
1169 expect (tempFile.getSize() == 10);
1171 expectEquals (tempFile.loadFileAsString(), String (
"0123456789"));
1172 expect (! demoFolder.containsSubDirectories());
1174 expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() +
File::getSeparatorString() + tempFile.getFileName());
1180 demoFolder.getNonexistentChildFile (
"tempFolder",
"",
false).createDirectory();
1183 expect (demoFolder.containsSubDirectories());
1185 expect (tempFile.hasWriteAccess());
1186 tempFile.setReadOnly (
true);
1187 expect (! tempFile.hasWriteAccess());
1188 tempFile.setReadOnly (
false);
1189 expect (tempFile.hasWriteAccess());
1192 tempFile.setLastModificationTime (t);
1193 Time t2 = tempFile.getLastModificationTime();
1194 expect (std::abs ((
int) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000);
1198 tempFile.loadFileAsData (mb);
1199 expect (mb.getSize() == 10);
1200 expect (mb[0] ==
'0');
1204 expect (tempFile.getSize() == 10);
1205 FileOutputStream fo (tempFile);
1206 expect (fo.openedOk());
1208 expect (fo.setPosition (7));
1209 expect (fo.truncate().wasOk());
1210 expect (tempFile.getSize() == 7);
1211 fo.write (
"789", 3);
1213 expect (tempFile.getSize() == 10);
1216 beginTest (
"Memory-mapped files");
1220 expect (mmf.getSize() == 10);
1221 expect (mmf.getData() !=
nullptr);
1222 expect (memcmp (mmf.getData(),
"0123456789", 10) == 0);
1226 const File tempFile2 (tempFile.getNonexistentSibling (
false));
1227 expect (tempFile2.create());
1228 expect (tempFile2.appendData (
"xxxxxxxxxx", 10));
1232 expect (mmf.getSize() == 10);
1233 expect (mmf.getData() !=
nullptr);
1234 memcpy (mmf.getData(),
"abcdefghij", 10);
1239 expect (mmf.getSize() == 10);
1240 expect (mmf.getData() !=
nullptr);
1241 expect (memcmp (mmf.getData(),
"abcdefghij", 10) == 0);
1244 expect (tempFile2.deleteFile());
1247 beginTest (
"More writing");
1249 expect (tempFile.appendData (
"abcdefghij", 10));
1250 expect (tempFile.getSize() == 20);
1251 expect (tempFile.replaceWithData (
"abcdefghij", 10));
1252 expect (tempFile.getSize() == 10);
1254 File tempFile2 (tempFile.getNonexistentSibling (
false));
1255 expect (tempFile.copyFileTo (tempFile2));
1256 expect (tempFile2.exists());
1257 expect (tempFile2.hasIdenticalContentTo (tempFile));
1258 expect (tempFile.deleteFile());
1259 expect (! tempFile.exists());
1260 expect (tempFile2.moveFileTo (tempFile));
1261 expect (tempFile.exists());
1262 expect (! tempFile2.exists());
1264 expect (demoFolder.deleteRecursively());
1265 expect (! demoFolder.exists());
1268 URL url (
"https://audio.dev/foo/bar/");
1269 expectEquals (url.toString (
false), String (
"https://audio.dev/foo/bar/"));
1270 expectEquals (url.getChildURL (
"x").toString (
false), String (
"https://audio.dev/foo/bar/x"));
1271 expectEquals (url.getParentURL().toString (
false), String (
"https://audio.dev/foo"));
1272 expectEquals (url.getParentURL().getParentURL().toString (
false), String (
"https://audio.dev/"));
1273 expectEquals (url.getParentURL().getParentURL().getParentURL().toString (
false), String (
"https://audio.dev/"));
1274 expectEquals (url.getParentURL().getChildURL (
"x").toString (
false), String (
"https://audio.dev/foo/x"));
1275 expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL (
"x").toString (
false), String (
"https://audio.dev/x"));
1279 URL url (
"https://audio.dev/foo/bar");
1280 expectEquals (url.toString (
false), String (
"https://audio.dev/foo/bar"));
1281 expectEquals (url.getChildURL (
"x").toString (
false), String (
"https://audio.dev/foo/bar/x"));
1282 expectEquals (url.getParentURL().toString (
false), String (
"https://audio.dev/foo"));
1283 expectEquals (url.getParentURL().getParentURL().toString (
false), String (
"https://audio.dev/"));
1284 expectEquals (url.getParentURL().getParentURL().getParentURL().toString (
false), String (
"https://audio.dev/"));
1285 expectEquals (url.getParentURL().getChildURL (
"x").toString (
false), String (
"https://audio.dev/foo/x"));
1286 expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL (
"x").toString (
false), String (
"https://audio.dev/x"));
1291static FileTests fileUnitTests;
void add(const ElementType &newElement)
static juce_wchar toLowerCase(juce_wchar character) noexcept
static bool isDigit(char character) noexcept
const Result & getStatus() const noexcept
bool write(const void *, size_t) override
bool failedToOpen() const noexcept
bool openedOk() const noexcept
std::unique_ptr< FileOutputStream > createOutputStream(size_t bufferSize=0x8000) const
bool replaceWithText(const String &textToWrite, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
bool isSymbolicLink() const
int getNumberOfChildFiles(int whatToLookFor, const String &wildCardPattern="*") const
bool moveFileTo(const File &targetLocation) const
bool operator==(const File &) const
bool containsSubDirectories() const
Array< File > findChildFiles(int whatToLookFor, bool searchRecursively, const String &wildCardPattern="*", FollowSymlinks followSymlinks=FollowSymlinks::yes) const
static void findFileSystemRoots(Array< File > &results)
bool hasIdenticalContentTo(const File &other) const
static String createLegalPathName(const String &pathNameToFix)
static String addTrailingSeparator(const String &path)
String getFileExtension() const
Time getLastModificationTime() const
bool existsAsFile() const
bool copyFileTo(const File &targetLocation) const
bool deleteRecursively(bool followSymlinks=false) const
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
const String & getFullPathName() const noexcept
String getFileName() const
bool replaceWithData(const void *dataToWrite, size_t numberOfBytes) const
bool setLastAccessTime(Time newTime) const
File getChildFile(StringRef relativeOrAbsolutePath) const
void readLines(StringArray &destLines) const
static bool isAbsolutePath(StringRef path)
File getSiblingFile(StringRef siblingFileName) const
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
String getFileNameWithoutExtension() const
File getNonexistentSibling(bool putNumbersInBrackets=true) const
@ userApplicationDataDirectory
String getRelativePathFrom(const File &directoryToBeRelativeTo) const
bool appendText(const String &textToAppend, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
@ findFilesAndDirectories
File getNonexistentChildFile(const String &prefix, const String &suffix, bool putNumbersInBrackets=true) const
bool operator!=(const File &) const
bool setCreationTime(Time newTime) const
static String descriptionOfSizeInBytes(int64 bytes)
bool setReadOnly(bool shouldBeReadOnly, bool applyRecursively=false) const
static File createTempFile(StringRef fileNameEnding)
static juce_wchar getSeparatorChar()
static bool areFileNamesCaseSensitive()
String loadFileAsString() const
bool operator>(const File &) const
File getLinkedTarget() const
File getParentDirectory() const
bool appendData(const void *dataToAppend, size_t numberOfBytes) const
std::unique_ptr< FileInputStream > createInputStream() const
bool operator<(const File &) const
Time getCreationTime() const
bool setExecutePermission(bool shouldBeExecutable) const
File withFileExtension(StringRef newExtension) const
static String createLegalFileName(const String &fileNameToFix)
bool replaceFileIn(const File &targetLocation) const
bool isAChildOf(const File &potentialParentDirectory) const
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
bool startAsProcess(const String ¶meters=String()) const
String getNativeLinkedTarget() const
bool hasFileExtension(StringRef extensionToTest) const
bool copyDirectoryTo(const File &newDirectory) const
bool loadFileAsData(MemoryBlock &result) const
bool setLastModificationTime(Time newTime) const
Time getLastAccessTime() const
Result createDirectory() const
static File getCurrentWorkingDirectory()
static StringRef getSeparatorString()
File & operator=(const String &newAbsolutePath)
static void JUCE_CALLTYPE writeToLog(const String &message)
MemoryMappedFile(const File &file, AccessMode mode, bool exclusive=false)
virtual bool writeText(const String &text, bool asUTF16, bool writeUTF16ByteOrderMark, const char *lineEndings)
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String ¶meters)
static Random & getSystemRandom() noexcept
static Result fail(const String &errorMessage) noexcept
static Result ok() noexcept
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
int size() const noexcept
int addLines(StringRef stringToBreakUp)
void removeRange(int startIndex, int numberToRemove)
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
bool isNotEmpty() const noexcept
int length() const noexcept
String::CharPointerType text
bool isEmpty() const noexcept
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
int indexOfChar(juce_wchar characterToLookFor) const noexcept
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
int length() const noexcept
bool endsWithChar(juce_wchar character) const noexcept
bool isEmpty() const noexcept
const char * toRawUTF8() const
int64 hashCode64() const noexcept
bool containsChar(juce_wchar character) const noexcept
String removeCharacters(StringRef charactersToRemove) const
bool endsWithIgnoreCase(StringRef text) const noexcept
String dropLastCharacters(int numberToDrop) const
bool contains(StringRef text) const noexcept
static String toHexString(IntegerType number)
int lastIndexOfChar(juce_wchar character) const noexcept
const wchar_t * toWideCharPointer() const
String trimCharactersAtEnd(StringRef charactersToTrim) const
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
String substring(int startIndex, int endIndex) const
int hashCode() const noexcept
bool isNotEmpty() const noexcept
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
bool overwriteTargetFileWithTemporary() const
const File & getFile() const noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
int64 toMilliseconds() const noexcept