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);
66 JUCE_DECLARE_DEPRECATED_STATIC (
const File File::nonexistent{};)
81 bool anythingChanged =
false;
83 for (
int i = 1; i < toks.
size(); ++i)
87 if (t ==
".." && toks[i - 1] !=
"..")
89 anythingChanged =
true;
95 anythingChanged =
true;
109 auto normalisedPath = path;
112 String doubleSeparator (separator + separator);
114 auto uncPath = normalisedPath.startsWith (doubleSeparator)
115 && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator,
false,
false).startsWith (separator);
118 normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator,
false,
false);
120 while (normalisedPath.contains (doubleSeparator))
121 normalisedPath = normalisedPath.replace (doubleSeparator, separator);
123 return uncPath ? doubleSeparator + normalisedPath
139 auto path = normaliseSeparators (removeEllipsis (p.
replaceCharacter (
'/',
'\\')));
178 auto path = normaliseSeparators (removeEllipsis (p));
193 if (
auto* pw = getpwnam (userName.toUTF8()))
199 #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS 211 #if JUCE_LOG_ASSERTIONS 235 #define NAMES_ARE_CASE_SENSITIVE 1 240 #if NAMES_ARE_CASE_SENSITIVE 247 static int compareFilenames (
const String& name1,
const String& name2) noexcept
249 #if NAMES_ARE_CASE_SENSITIVE 258 bool File::operator< (
const File& other)
const {
return compareFilenames (fullPath, other.fullPath) < 0; }
259 bool File::operator> (
const File& other)
const {
return compareFilenames (fullPath, other.fullPath) > 0; }
263 const bool applyRecursively)
const 269 worked = f.setReadOnly (shouldBeReadOnly,
true) && worked;
271 return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
276 return setFileExecutableInternal (shouldBeExecutable);
285 worked = f.deleteRecursively (followSymlinks) && worked;
292 if (newFile.fullPath == fullPath)
298 #if ! NAMES_ARE_CASE_SENSITIVE 299 if (*
this != newFile)
304 return moveInternal (newFile);
309 return (*
this == newFile)
315 if (newFile.fullPath == fullPath)
321 if (! replaceInternal (newFile))
333 if (! f.copyFileTo (newDirectory.
getChildFile (f.getFileName())))
337 if (! f.copyDirectoryTo (newDirectory.
getChildFile (f.getFileName())))
347 String File::getPathUpToLastSlash()
const 352 return fullPath.
substring (0, lastSlash);
376 if (lastDot > lastSlash)
377 return fullPath.
substring (lastSlash, lastDot);
384 if (potentialParent.fullPath.
isEmpty())
387 auto ourPath = getPathUpToLastSlash();
389 if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
392 if (potentialParent.fullPath.
length() >= ourPath.length())
404 auto firstChar = *(path.
text);
408 || (firstChar != 0 && path.
text[1] ==
':');
416 auto r = relativePath.
text;
422 if (r.indexOf ((juce_wchar)
'/') >= 0)
426 auto path = fullPath;
432 auto secondChar = *++r;
434 if (secondChar ==
'.')
436 auto thirdChar = *++r;
438 if (thirdChar == separatorChar || thirdChar == 0)
445 while (*r == separatorChar)
454 else if (secondChar == separatorChar || secondChar == 0)
456 while (*r == separatorChar)
482 if (bytes == 1) { suffix =
" byte"; }
483 else if (bytes < 1024) { suffix =
" bytes"; }
484 else if (bytes < 1024 * 1024) { suffix =
" KB"; divisor = 1024.0; }
485 else if (bytes < 1024 * 1024 * 1024) { suffix =
" MB"; divisor = 1024.0 * 1024.0; }
486 else { suffix =
" GB"; divisor = 1024.0 * 1024.0 * 1024.0; }
488 return (divisor > 0 ?
String (bytes / divisor, 1) :
String (bytes)) + suffix;
499 if (parentDir == *
this)
502 auto r = parentDir.createDirectory();
520 if (parentDir == *
this)
523 auto r = parentDir.createDirectory();
569 findChildFiles (results, whatToLookFor, searchRecursively, wildcard);
579 results.
add (di.getFile());
608 bool putNumbersInBrackets)
const 615 auto prefix = suggestedPrefix;
618 if (prefix.trim().endsWithChar (
')'))
620 putNumbersInBrackets =
true;
623 auto closeBracks = prefix.lastIndexOfChar (
')');
626 && closeBracks > openBracks
627 && prefix.substring (openBracks + 1, closeBracks).containsOnly (
"0123456789"))
629 number = prefix.substring (openBracks + 1, closeBracks).getIntValue();
630 prefix = prefix.substring (0, openBracks);
636 auto newName = prefix;
638 if (putNumbersInBrackets)
640 newName <<
'(' << ++number <<
')';
652 }
while (f.exists());
665 putNumbersInBrackets);
684 auto semicolon = possibleSuffix.
text.indexOf ((juce_wchar)
';');
692 if (possibleSuffix.
text[0] ==
'.')
695 auto dotPos = fullPath.
length() - possibleSuffix.
length() - 1;
698 return fullPath[dotPos] ==
'.';
711 auto lastDot = filePart.lastIndexOfChar (
'.');
714 filePart = filePart.substring (0, lastDot);
734 return fin.release();
741 std::unique_ptr<FileOutputStream> out (
new FileOutputStream (*
this, bufferSize));
743 return out->failedToOpen() ? nullptr
749 const size_t numberOfBytes)
const 751 jassert (((ssize_t) numberOfBytes) >= 0);
753 if (numberOfBytes == 0)
757 return out.
openedOk() && out.
write (dataToAppend, numberOfBytes);
761 const size_t numberOfBytes)
const 763 if (numberOfBytes == 0)
778 return out.
writeText (text, asUnicode, writeHeaderBytes, lineFeed);
784 tempFile.
getFile().
appendText (textToWrite, asUnicode, writeHeaderBytes, lineFeed);
797 if (in1.openedOk() && in2.
openedOk())
799 const int bufferSize = 4096;
804 auto num1 = in1.read (buffer1, bufferSize);
805 auto num2 = in2.
read (buffer2, bufferSize);
813 if (memcmp (buffer1, buffer2, (
size_t) num1) != 0)
828 if (s.isNotEmpty() && s[1] ==
':')
842 const int maxLength = 128;
847 auto lastDot = s.lastIndexOfChar (
'.');
849 if (lastDot > jmax (0, len - 12))
851 s = s.substring (0, maxLength - (len - lastDot))
852 + s.substring (lastDot);
856 s = s.substring (0, maxLength);
864 static int countNumberOfSeparators (String::CharPointerType s)
870 auto c = s.getAndAdvance();
887 auto thisPath = fullPath;
895 int commonBitLength = 0;
897 auto dirPathAfterCommon = dirPath.getCharPointer();
900 auto thisPathIter = thisPath.getCharPointer();
901 auto dirPathIter = dirPath.getCharPointer();
905 auto c1 = thisPathIter.getAndAdvance();
906 auto c2 = dirPathIter.getAndAdvance();
908 #if NAMES_ARE_CASE_SENSITIVE 920 thisPathAfterCommon = thisPathIter;
921 dirPathAfterCommon = dirPathIter;
928 if (commonBitLength == 0 || (commonBitLength == 1 && thisPath[1] ==
getSeparatorChar()))
931 auto numUpDirectoriesNeeded = countNumberOfSeparators (dirPathAfterCommon);
933 if (numUpDirectoriesNeeded == 0)
934 return thisPathAfterCommon;
941 s.appendCharPointer (thisPathAfterCommon);
952 if (tempFile.exists())
959 const String& nativePathOfTarget,
960 bool overwriteExisting)
962 if (linkFileToCreate.
exists())
972 if (overwriteExisting)
976 #if JUCE_MAC || JUCE_LINUX 990 targetFile.isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != FALSE;
992 ignoreUnused (nativePathOfTarget);
1017 openInternal (file, mode, exclusive);
1021 : range (fileRange.getIntersectionWith (
Range<int64> (0, file.
getSize())))
1023 openInternal (file, mode, exclusive);
1035 :
UnitTest (
"Files", UnitTestCategories::files)
1038 void runTest()
override 1040 beginTest (
"Reading");
1045 expect (!
File().exists());
1046 expect (!
File().existsAsFile());
1047 expect (!
File().isDirectory());
1049 expect (
File(
"/").isDirectory());
1070 expect (roots.
size() > 0);
1072 int numRootsExisting = 0;
1073 for (
int i = 0; i < roots.
size(); ++i)
1074 if (roots[i].exists())
1078 expect (numRootsExisting > 0);
1081 beginTest (
"Writing");
1084 expect (demoFolder.deleteRecursively());
1085 expect (demoFolder.createDirectory());
1086 expect (demoFolder.isDirectory());
1087 expect (demoFolder.getParentDirectory() == temp);
1092 File tempFile (demoFolder.getNonexistentChildFile (
"test",
".txt",
false));
1094 expect (tempFile.getFileExtension() ==
".txt");
1095 expect (tempFile.hasFileExtension (
".txt"));
1096 expect (tempFile.hasFileExtension (
"txt"));
1097 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
".xyz"));
1098 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
"abc;xyz;foo"));
1099 expect (tempFile.withFileExtension (
"xyz").hasFileExtension (
"xyz;foo"));
1100 expect (! tempFile.withFileExtension (
"h").hasFileExtension (
"bar;foo;xx"));
1101 expect (tempFile.getSiblingFile (
"foo").isAChildOf (temp));
1102 expect (tempFile.hasWriteAccess());
1119 fo.
write (
"0123456789", 10);
1122 expect (tempFile.exists());
1123 expect (tempFile.getSize() == 10);
1125 expectEquals (tempFile.loadFileAsString(),
String (
"0123456789"));
1126 expect (! demoFolder.containsSubDirectories());
1128 expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() +
File::getSeparatorString() + tempFile.getFileName());
1134 demoFolder.getNonexistentChildFile (
"tempFolder",
"",
false).createDirectory();
1137 expect (demoFolder.containsSubDirectories());
1139 expect (tempFile.hasWriteAccess());
1140 tempFile.setReadOnly (
true);
1141 expect (! tempFile.hasWriteAccess());
1142 tempFile.setReadOnly (
false);
1143 expect (tempFile.hasWriteAccess());
1146 tempFile.setLastModificationTime (t);
1147 Time t2 = tempFile.getLastModificationTime();
1148 expect (std::abs ((
int) (t2.
toMilliseconds() - t.toMilliseconds())) <= 1000);
1152 tempFile.loadFileAsData (mb);
1154 expect (mb[0] ==
'0');
1158 expect (tempFile.getSize() == 10);
1160 expect (fo.openedOk());
1162 expect (fo.setPosition (7));
1163 expect (fo.truncate().wasOk());
1164 expect (tempFile.getSize() == 7);
1165 fo.write (
"789", 3);
1167 expect (tempFile.getSize() == 10);
1170 beginTest (
"Memory-mapped files");
1175 expect (mmf.
getData() !=
nullptr);
1176 expect (memcmp (mmf.
getData(),
"0123456789", 10) == 0);
1180 const File tempFile2 (tempFile.getNonexistentSibling (
false));
1181 expect (tempFile2.create());
1182 expect (tempFile2.appendData (
"xxxxxxxxxx", 10));
1187 expect (mmf.
getData() !=
nullptr);
1188 memcpy (mmf.
getData(),
"abcdefghij", 10);
1194 expect (mmf.
getData() !=
nullptr);
1195 expect (memcmp (mmf.
getData(),
"abcdefghij", 10) == 0);
1198 expect (tempFile2.deleteFile());
1201 beginTest (
"More writing");
1203 expect (tempFile.appendData (
"abcdefghij", 10));
1204 expect (tempFile.getSize() == 20);
1205 expect (tempFile.replaceWithData (
"abcdefghij", 10));
1206 expect (tempFile.getSize() == 10);
1208 File tempFile2 (tempFile.getNonexistentSibling (
false));
1209 expect (tempFile.copyFileTo (tempFile2));
1210 expect (tempFile2.exists());
1211 expect (tempFile2.hasIdenticalContentTo (tempFile));
1212 expect (tempFile.deleteFile());
1213 expect (! tempFile.exists());
1214 expect (tempFile2.moveFileTo (tempFile));
1215 expect (tempFile.exists());
1216 expect (! tempFile2.exists());
1218 expect (demoFolder.deleteRecursively());
1219 expect (! demoFolder.exists());
1222 URL url (
"https://audio.dev/foo/bar/");
1223 expectEquals (url.
toString (
false),
String (
"https://audio.dev/foo/bar/"));
1233 URL url (
"https://audio.dev/foo/bar");
1234 expectEquals (url.
toString (
false),
String (
"https://audio.dev/foo/bar"));
1245 static FileTests fileUnitTests;
size_t getSize() const noexcept
bool copyFileTo(const File &targetLocation) const
String getFileName() const
bool setReadOnly(bool shouldBeReadOnly, bool applyRecursively=false) const
bool operator!=(const File &) const
static Random & getSystemRandom() noexcept
bool appendText(const String &textToAppend, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\") const
int64 hashCode64() const noexcept
bool hasIdenticalContentTo(const File &other) const
bool setCreationTime(Time newTime) const
File getSiblingFile(StringRef siblingFileName) const
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
static Result ok() noexcept
static bool isAbsolutePath(StringRef path)
const char * toRawUTF8() const
bool copyDirectoryTo(const File &newDirectory) const
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
bool appendData(const void *dataToAppend, size_t numberOfBytes) const
bool operator<(const File &) const
static String createLegalPathName(const String &pathNameToFix)
bool overwriteTargetFileWithTemporary() const
bool endsWithChar(juce_wchar character) const noexcept
bool isNotEmpty() const noexcept
const File & getFile() const noexcept
URL getChildURL(const String &subPath) const
const Result & getStatus() const noexcept
bool isAChildOf(const File &potentialParentDirectory) const
bool setLastAccessTime(Time newTime) const
int length() const noexcept
File getParentDirectory() const
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
void add(const ElementType &newElement)
Time getLastModificationTime() const
Result createDirectory() const
bool isNotEmpty() const noexcept
String trimCharactersAtEnd(StringRef charactersToTrim) const
bool containsChar(juce_wchar character) const noexcept
bool endsWithIgnoreCase(StringRef text) const noexcept
bool replaceWithText(const String &textToWrite, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\") const
String toString(bool includeGetParameters) const
void * getData() const noexcept
static bool isDigit(char character) noexcept
CharPointerType getCharPointer() const noexcept
String dropLastCharacters(int numberToDrop) const
int addLines(StringRef stringToBreakUp)
bool operator==(const File &) const
bool containsSubDirectories() const
int64 toMilliseconds() const noexcept
bool isSymbolicLink() const
File getChildFile(StringRef relativeOrAbsolutePath) const
FileInputStream * createInputStream() const
bool write(const void *, size_t) override
static Time JUCE_CALLTYPE getCurrentTime() noexcept
File & operator=(const String &newAbsolutePath)
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String ¶meters)
const wchar_t * toWideCharPointer() const
bool setLastModificationTime(Time newTime) const
Time getLastAccessTime() const
bool replaceFileIn(const File &targetLocation) const
static void findFileSystemRoots(Array< File > &results)
static String createLegalFileName(const String &fileNameToFix)
void readLines(StringArray &destLines) const
static Result fail(const String &errorMessage) noexcept
virtual bool writeText(const String &text, bool asUTF16, bool writeUTF16ByteOrderMark, const char *lineEndings)
String removeCharacters(StringRef charactersToRemove) const
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
String substring(int startIndex, int endIndex) const
static String descriptionOfSizeInBytes(int64 bytes)
File withFileExtension(StringRef newExtension) const
String loadFileAsString() const
bool contains(StringRef text) const noexcept
int compareIgnoreCase(const String &other) const noexcept
bool isEmpty() const noexcept
static String toHexString(IntegerType number)
bool loadFileAsData(MemoryBlock &result) const
bool replaceWithData(const void *dataToWrite, size_t numberOfBytes) const
Array< File > findChildFiles(int whatToLookFor, bool searchRecursively, const String &wildCardPattern="*") const
void removeRange(int startIndex, int numberToRemove)
bool existsAsFile() const
String getRelativePathFrom(const File &directoryToBeRelativeTo) const
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
bool moveFileTo(const File &targetLocation) const
bool hasFileExtension(StringRef extensionToTest) const
String getFileExtension() const
int size() const noexcept
FileOutputStream * createOutputStream(size_t bufferSize=0x8000) const
static juce_wchar toLowerCase(juce_wchar character) noexcept
bool isEmpty() const noexcept
String::CharPointerType text
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
bool setExecutePermission(bool shouldBeExecutable) const
File getNonexistentChildFile(const String &prefix, const String &suffix, bool putNumbersInBrackets=true) const
static String addTrailingSeparator(const String &path)
static void JUCE_CALLTYPE writeToLog(const String &message)
int64 getVolumeTotalSize() const
bool startsWithChar(juce_wchar character) const noexcept
Time getCreationTime() const
int64 getBytesFreeOnVolume() const
String getFileNameWithoutExtension() const
bool openedOk() const noexcept
static StringRef getSeparatorString()
int hashCode() const noexcept
bool isOnCDRomDrive() const
static File createTempFile(StringRef fileNameEnding)
static bool areFileNamesCaseSensitive()
int lastIndexOfChar(juce_wchar character) const noexcept
int size() const noexcept
bool startAsProcess(const String ¶meters=String()) const
bool operator>(const File &) const
String getNativeLinkedTarget() const
int indexOfChar(juce_wchar characterToLookFor) const noexcept
int compare(const String &other) const noexcept
static File getCurrentWorkingDirectory()
int length() const noexcept
bool failedToOpen() const noexcept
size_t getSize() const noexcept
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
MemoryMappedFile(const File &file, AccessMode mode, bool exclusive=false)
File getNonexistentSibling(bool putNumbersInBrackets=true) const
File getLinkedTarget() const
bool isOnHardDisk() const
const String & getFullPathName() const noexcept
int getNumberOfChildFiles(int whatToLookFor, const String &wildCardPattern="*") const
void appendCharPointer(CharPointerType startOfTextToAppend, CharPointerType endOfTextToAppend)
bool setAsCurrentWorkingDirectory() const
bool deleteRecursively(bool followSymlinks=false) const
bool startsWith(StringRef text) const noexcept
static juce_wchar getSeparatorChar()