FsFile.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. /**
  2. * Copyright (c) 2011-2022 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef FsFile_h
  26. #define FsFile_h
  27. /**
  28. * \file
  29. * \brief FsBaseFile include file.
  30. */
  31. #include "FsNew.h"
  32. #include "FatLib/FatLib.h"
  33. #include "ExFatLib/ExFatLib.h"
  34. /**
  35. * \class FsBaseFile
  36. * \brief FsBaseFile class.
  37. */
  38. class FsBaseFile {
  39. public:
  40. /** Create an instance. */
  41. FsBaseFile() {}
  42. /** Create a file object and open it in the current working directory.
  43. *
  44. * \param[in] path A path for a file to be opened.
  45. *
  46. * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
  47. * OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
  48. */
  49. FsBaseFile(const char* path, oflag_t oflag) {
  50. open(path, oflag);
  51. }
  52. ~FsBaseFile() {close();}
  53. /** Copy constructor.
  54. *
  55. * \param[in] from Object used to initialize this instance.
  56. */
  57. FsBaseFile(const FsBaseFile& from);
  58. /** Copy assignment operator
  59. * \param[in] from Object used to initialize this instance.
  60. * \return assigned object.
  61. */
  62. FsBaseFile& operator=(const FsBaseFile& from);
  63. /** The parenthesis operator.
  64. *
  65. * \return true if a file is open.
  66. */
  67. operator bool() const {return isOpen();}
  68. /**
  69. * \return user settable file attributes for success else -1.
  70. */
  71. int attrib() {
  72. return m_fFile ? m_fFile->attrib() :
  73. m_xFile ? m_xFile->attrib() : -1;
  74. }
  75. /** Set file attributes
  76. *
  77. * \param[in] bits bit-wise or of selected attributes: FS_ATTRIB_READ_ONLY,
  78. * FS_ATTRIB_HIDDEN, FS_ATTRIB_SYSTEM, FS_ATTRIB_ARCHIVE.
  79. *
  80. * \note attrib() will fail for set read-only if the file is open for write.
  81. * \return true for success or false for failure.
  82. */
  83. bool attrib(uint8_t bits) {
  84. return m_fFile ? m_fFile->attrib(bits) :
  85. m_xFile ? m_xFile->attrib(bits) : false;
  86. }
  87. /** \return number of bytes available from the current position to EOF
  88. * or INT_MAX if more than INT_MAX bytes are available.
  89. */
  90. int available() const {
  91. return m_fFile ? m_fFile->available() :
  92. m_xFile ? m_xFile->available() : 0;
  93. }
  94. /** \return The number of bytes available from the current position
  95. * to EOF for normal files. Zero is returned for directory files.
  96. */
  97. uint64_t available64() const {
  98. return m_fFile ? m_fFile->available32() :
  99. m_xFile ? m_xFile->available64() : 0;
  100. }
  101. /** Clear writeError. */
  102. void clearWriteError() {
  103. if (m_fFile) m_fFile->clearWriteError();
  104. if (m_xFile) m_xFile->clearWriteError();
  105. }
  106. /** Close a file and force cached data and directory information
  107. * to be written to the storage device.
  108. *
  109. * \return true for success or false for failure.
  110. */
  111. bool close();
  112. /** Check for contiguous file and return its raw sector range.
  113. *
  114. * \param[out] bgnSector the first sector address for the file.
  115. * \param[out] endSector the last sector address for the file.
  116. *
  117. * Set contiguous flag for FAT16/FAT32 files.
  118. * Parameters may be nullptr.
  119. *
  120. * \return true for success or false for failure.
  121. */
  122. bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
  123. return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector) :
  124. m_xFile ? m_xFile->contiguousRange(bgnSector, endSector) : false;
  125. }
  126. /** \return The current cluster number for a file or directory. */
  127. uint32_t curCluster() const {
  128. return m_fFile ? m_fFile->curCluster() :
  129. m_xFile ? m_xFile->curCluster() : 0;
  130. }
  131. /** \return The current position for a file or directory. */
  132. uint64_t curPosition() const {
  133. return m_fFile ? m_fFile->curPosition() :
  134. m_xFile ? m_xFile->curPosition() : 0;
  135. }
  136. /** \return Directory entry index. */
  137. uint32_t dirIndex() const {
  138. return m_fFile ? m_fFile->dirIndex() :
  139. m_xFile ? m_xFile->dirIndex() : 0;
  140. }
  141. /** Test for the existence of a file in a directory
  142. *
  143. * \param[in] path Path of the file to be tested for.
  144. *
  145. * The calling instance must be an open directory file.
  146. *
  147. * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
  148. * dirFile.
  149. *
  150. * \return true if the file exists else false.
  151. */
  152. bool exists(const char* path) {
  153. return m_fFile ? m_fFile->exists(path) :
  154. m_xFile ? m_xFile->exists(path) : false;
  155. }
  156. /** get position for streams
  157. * \param[out] pos struct to receive position
  158. */
  159. void fgetpos(fspos_t* pos) const {
  160. if (m_fFile) m_fFile->fgetpos(pos);
  161. if (m_xFile) m_xFile->fgetpos(pos);
  162. }
  163. /**
  164. * Get a string from a file.
  165. *
  166. * fgets() reads bytes from a file into the array pointed to by \a str, until
  167. * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
  168. * or end-of-file is encountered. The string is then terminated
  169. * with a null byte.
  170. *
  171. * fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
  172. * terminates the string for Windows text files which use CRLF for newline.
  173. *
  174. * \param[out] str Pointer to the array where the string is stored.
  175. * \param[in] num Maximum number of characters to be read
  176. * (including the final null byte). Usually the length
  177. * of the array \a str is used.
  178. * \param[in] delim Optional set of delimiters. The default is "\n".
  179. *
  180. * \return For success fgets() returns the length of the string in \a str.
  181. * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
  182. */
  183. int fgets(char* str, int num, char* delim = nullptr) {
  184. return m_fFile ? m_fFile->fgets(str, num, delim) :
  185. m_xFile ? m_xFile->fgets(str, num, delim) : -1;
  186. }
  187. /** \return The total number of bytes in a file. */
  188. uint64_t fileSize() const {
  189. return m_fFile ? m_fFile->fileSize() :
  190. m_xFile ? m_xFile->fileSize() : 0;
  191. }
  192. /** \return Address of first sector or zero for empty file. */
  193. uint32_t firstSector() const {
  194. return m_fFile ? m_fFile->firstSector() :
  195. m_xFile ? m_xFile->firstSector() : 0;
  196. }
  197. /** Ensure that any bytes written to the file are saved to the SD card. */
  198. void flush() {sync();}
  199. /** set position for streams
  200. * \param[in] pos struct with value for new position
  201. */
  202. void fsetpos(const fspos_t* pos) {
  203. if (m_fFile) m_fFile->fsetpos(pos);
  204. if (m_xFile) m_xFile->fsetpos(pos);
  205. }
  206. /** Get a file's access date and time.
  207. *
  208. * \param[out] pdate Packed date for directory entry.
  209. * \param[out] ptime Packed time for directory entry.
  210. *
  211. * \return true for success or false for failure.
  212. */
  213. bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
  214. return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime) :
  215. m_xFile ? m_xFile->getAccessDateTime(pdate, ptime) : false;
  216. }
  217. /** Get a file's create date and time.
  218. *
  219. * \param[out] pdate Packed date for directory entry.
  220. * \param[out] ptime Packed time for directory entry.
  221. *
  222. * \return true for success or false for failure.
  223. */
  224. bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
  225. return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime) :
  226. m_xFile ? m_xFile->getCreateDateTime(pdate, ptime) : false;
  227. }
  228. /** \return All error bits. */
  229. uint8_t getError() const {
  230. return m_fFile ? m_fFile->getError() :
  231. m_xFile ? m_xFile->getError() : 0XFF;
  232. }
  233. /** Get a file's Modify date and time.
  234. *
  235. * \param[out] pdate Packed date for directory entry.
  236. * \param[out] ptime Packed time for directory entry.
  237. *
  238. * \return true for success or false for failure.
  239. */
  240. bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
  241. return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime) :
  242. m_xFile ? m_xFile->getModifyDateTime(pdate, ptime) : false;
  243. }
  244. /**
  245. * Get a file's name followed by a zero byte.
  246. *
  247. * \param[out] name An array of characters for the file's name.
  248. * \param[in] len The size of the array in bytes. The array
  249. * must be at least 13 bytes long. The file's name will be
  250. * truncated if the file's name is too long.
  251. * \return The length of the returned string.
  252. */
  253. size_t getName(char* name, size_t len) {
  254. *name = 0;
  255. return m_fFile ? m_fFile->getName(name, len) :
  256. m_xFile ? m_xFile->getName(name, len) : 0;
  257. }
  258. /** \return value of writeError */
  259. bool getWriteError() const {
  260. return m_fFile ? m_fFile->getWriteError() :
  261. m_xFile ? m_xFile->getWriteError() : true;
  262. }
  263. /**
  264. * Check for FsBlockDevice busy.
  265. *
  266. * \return true if busy else false.
  267. */
  268. bool isBusy() {
  269. return m_fFile ? m_fFile->isBusy() :
  270. m_xFile ? m_xFile->isBusy() : true;
  271. }
  272. /** \return True if the file is contiguous. */
  273. bool isContiguous() const {
  274. #if USE_FAT_FILE_FLAG_CONTIGUOUS
  275. return m_fFile ? m_fFile->isContiguous() :
  276. m_xFile ? m_xFile->isContiguous() : false;
  277. #else // USE_FAT_FILE_FLAG_CONTIGUOUS
  278. return m_xFile ? m_xFile->isContiguous() : false;
  279. #endif // USE_FAT_FILE_FLAG_CONTIGUOUS
  280. }
  281. /** \return True if this is a directory else false. */
  282. bool isDir() const {
  283. return m_fFile ? m_fFile->isDir() :
  284. m_xFile ? m_xFile->isDir() : false;
  285. }
  286. /** This function reports if the current file is a directory or not.
  287. * \return true if the file is a directory.
  288. */
  289. bool isDirectory() const {return isDir();}
  290. /** \return True if this is a normal file. */
  291. bool isFile() const {
  292. return m_fFile ? m_fFile->isFile() :
  293. m_xFile ? m_xFile->isFile() : false;
  294. }
  295. /** \return True if this is a normal file or sub-directory. */
  296. bool isFileOrSubDir() const {
  297. return m_fFile ? m_fFile->isFileOrSubDir() :
  298. m_xFile ? m_xFile->isFileOrSubDir() : false;
  299. }
  300. /** \return True if this is a hidden file else false. */
  301. bool isHidden() const {
  302. return m_fFile ? m_fFile->isHidden() :
  303. m_xFile ? m_xFile->isHidden() : false;
  304. }
  305. /** \return True if this is an open file/directory else false. */
  306. bool isOpen() const {return m_fFile || m_xFile;}
  307. /** \return True file is readable. */
  308. bool isReadable() const {
  309. return m_fFile ? m_fFile->isReadable() :
  310. m_xFile ? m_xFile->isReadable() : false;
  311. }
  312. /** \return True if file is read-only */
  313. bool isReadOnly() const {
  314. return m_fFile ? m_fFile->isReadOnly() :
  315. m_xFile ? m_xFile->isReadOnly() : false;
  316. }
  317. /** \return True if this is a sub-directory file else false. */
  318. bool isSubDir() const {
  319. return m_fFile ? m_fFile->isSubDir() :
  320. m_xFile ? m_xFile->isSubDir() : false;
  321. }
  322. /** \return True file is writable. */
  323. bool isWritable() const {
  324. return m_fFile ? m_fFile->isWritable() :
  325. m_xFile ? m_xFile->isWritable() : false;
  326. }
  327. #if ENABLE_ARDUINO_SERIAL
  328. /** List directory contents.
  329. *
  330. * \param[in] flags The inclusive OR of
  331. *
  332. * LS_DATE - %Print file modification date
  333. *
  334. * LS_SIZE - %Print file size.
  335. *
  336. * LS_R - Recursive list of subdirectories.
  337. */
  338. bool ls(uint8_t flags) {
  339. return ls(&Serial, flags);
  340. }
  341. /** List directory contents. */
  342. bool ls() {
  343. return ls(&Serial);
  344. }
  345. #endif // ENABLE_ARDUINO_SERIAL
  346. /** List directory contents.
  347. *
  348. * \param[in] pr Print object.
  349. *
  350. * \return true for success or false for failure.
  351. */
  352. bool ls(print_t* pr) {
  353. return m_fFile ? m_fFile->ls(pr) :
  354. m_xFile ? m_xFile->ls(pr) : false;
  355. }
  356. /** List directory contents.
  357. *
  358. * \param[in] pr Print object.
  359. * \param[in] flags The inclusive OR of
  360. *
  361. * LS_DATE - %Print file modification date
  362. *
  363. * LS_SIZE - %Print file size.
  364. *
  365. * LS_R - Recursive list of subdirectories.
  366. *
  367. * \return true for success or false for failure.
  368. */
  369. bool ls(print_t* pr, uint8_t flags) {
  370. return m_fFile ? m_fFile->ls(pr, flags) :
  371. m_xFile ? m_xFile->ls(pr, flags) : false;
  372. }
  373. /** Make a new directory.
  374. *
  375. * \param[in] dir An open FatFile instance for the directory that will
  376. * contain the new directory.
  377. *
  378. * \param[in] path A path with a valid 8.3 DOS name for the new directory.
  379. *
  380. * \param[in] pFlag Create missing parent directories if true.
  381. *
  382. * \return true for success or false for failure.
  383. */
  384. bool mkdir(FsBaseFile* dir, const char* path, bool pFlag = true);
  385. /** Open a file or directory by name.
  386. *
  387. * \param[in] dir An open file instance for the directory containing
  388. * the file to be opened.
  389. *
  390. * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
  391. *
  392. * \param[in] oflag Values for \a oflag are constructed by a
  393. * bitwise-inclusive OR of flags from the following list
  394. *
  395. * O_RDONLY - Open for reading only..
  396. *
  397. * O_READ - Same as O_RDONLY.
  398. *
  399. * O_WRONLY - Open for writing only.
  400. *
  401. * O_WRITE - Same as O_WRONLY.
  402. *
  403. * O_RDWR - Open for reading and writing.
  404. *
  405. * O_APPEND - If set, the file offset shall be set to the end of the
  406. * file prior to each write.
  407. *
  408. * O_AT_END - Set the initial position at the end of the file.
  409. *
  410. * O_CREAT - If the file exists, this flag has no effect except as noted
  411. * under O_EXCL below. Otherwise, the file shall be created
  412. *
  413. * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
  414. *
  415. * O_TRUNC - If the file exists and is a regular file, and the file is
  416. * successfully opened and is not read only, its length shall be truncated to 0.
  417. *
  418. * WARNING: A given file must not be opened by more than one file object
  419. * or file corruption may occur.
  420. *
  421. * \note Directory files must be opened read only. Write and truncation is
  422. * not allowed for directory files.
  423. *
  424. * \return true for success or false for failure.
  425. */
  426. bool open(FsBaseFile* dir, const char* path, oflag_t oflag = O_RDONLY);
  427. /** Open a file by index.
  428. *
  429. * \param[in] dir An open FsFile instance for the directory.
  430. *
  431. * \param[in] index The \a index of the directory entry for the file to be
  432. * opened. The value for \a index is (directory file position)/32.
  433. *
  434. * \param[in] oflag bitwise-inclusive OR of open flags.
  435. * See see FsFile::open(FsFile*, const char*, uint8_t).
  436. *
  437. * See open() by path for definition of flags.
  438. * \return true for success or false for failure.
  439. */
  440. bool open(FsBaseFile* dir, uint32_t index, oflag_t oflag = O_RDONLY);
  441. /** Open a file or directory by name.
  442. *
  443. * \param[in] vol Volume where the file is located.
  444. *
  445. * \param[in] path A path for a file to be opened.
  446. *
  447. * \param[in] oflag Values for \a oflag are constructed by a
  448. * bitwise-inclusive OR of open flags.
  449. *
  450. * \return true for success or false for failure.
  451. */
  452. bool open(FsVolume* vol, const char* path, oflag_t oflag = O_RDONLY);
  453. /** Open a file or directory by name.
  454. *
  455. * \param[in] path A path for a file to be opened.
  456. *
  457. * \param[in] oflag Values for \a oflag are constructed by a
  458. * bitwise-inclusive OR of open flags.
  459. *
  460. * \return true for success or false for failure.
  461. */
  462. bool open(const char* path, oflag_t oflag = O_RDONLY) {
  463. return FsVolume::m_cwv && open(FsVolume::m_cwv, path, oflag);
  464. }
  465. /** Open a file or directory by index in the current working directory.
  466. *
  467. * \param[in] index The \a index of the directory entry for the file to be
  468. * opened. The value for \a index is (directory file position)/32.
  469. *
  470. * \param[in] oflag Values for \a oflag are constructed by a
  471. * bitwise-inclusive OR of open flags.
  472. *
  473. * \return true for success or false for failure.
  474. */
  475. bool open(uint32_t index, oflag_t oflag = O_RDONLY) {
  476. FsBaseFile cwd;
  477. return cwd.openCwd() && open(&cwd, index, oflag);
  478. }
  479. /** Open the current working directory.
  480. *
  481. * \return true for success or false for failure.
  482. */
  483. bool openCwd();
  484. /** Opens the next file or folder in a directory.
  485. * \param[in] dir directory containing files.
  486. * \param[in] oflag open flags.
  487. * \return a file object.
  488. */
  489. bool openNext(FsBaseFile* dir, oflag_t oflag = O_RDONLY);
  490. /** Open a volume's root directory.
  491. *
  492. * \param[in] vol The SdFs volume containing the root directory to be opened.
  493. *
  494. * \return true for success or false for failure.
  495. */
  496. bool openRoot(FsVolume* vol);
  497. /** \return the current file position. */
  498. uint64_t position() const {return curPosition();}
  499. /** Return the next available byte without consuming it.
  500. *
  501. * \return The byte if no error and not at eof else -1;
  502. */
  503. int peek() {
  504. return m_fFile ? m_fFile->peek() :
  505. m_xFile ? m_xFile->peek() : -1;
  506. }
  507. /** Allocate contiguous clusters to an empty file.
  508. *
  509. * The file must be empty with no clusters allocated.
  510. *
  511. * The file will contain uninitialized data for FAT16/FAT32 files.
  512. * exFAT files will have zero validLength and dataLength will equal
  513. * the requested length.
  514. *
  515. * \param[in] length size of the file in bytes.
  516. * \return true for success or false for failure.
  517. */
  518. bool preAllocate(uint64_t length) {
  519. return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length) :
  520. m_xFile ? m_xFile->preAllocate(length) : false;
  521. }
  522. /** Print a file's access date and time
  523. *
  524. * \param[in] pr Print stream for output.
  525. *
  526. * \return true for success or false for failure.
  527. */
  528. size_t printAccessDateTime(print_t* pr) {
  529. return m_fFile ? m_fFile->printAccessDateTime(pr) :
  530. m_xFile ? m_xFile->printAccessDateTime(pr) : 0;
  531. }
  532. /** Print a file's creation date and time
  533. *
  534. * \param[in] pr Print stream for output.
  535. *
  536. * \return true for success or false for failure.
  537. */
  538. size_t printCreateDateTime(print_t* pr) {
  539. return m_fFile ? m_fFile->printCreateDateTime(pr) :
  540. m_xFile ? m_xFile->printCreateDateTime(pr) : 0;
  541. }
  542. /** Print a number followed by a field terminator.
  543. * \param[in] value The number to be printed.
  544. * \param[in] term The field terminator. Use '\\n' for CR LF.
  545. * \param[in] prec Number of digits after decimal point.
  546. * \return The number of bytes written or -1 if an error occurs.
  547. */
  548. size_t printField(double value, char term, uint8_t prec = 2) {
  549. return m_fFile ? m_fFile->printField(value, term, prec) :
  550. m_xFile ? m_xFile->printField(value, term, prec) : 0;
  551. }
  552. /** Print a number followed by a field terminator.
  553. * \param[in] value The number to be printed.
  554. * \param[in] term The field terminator. Use '\\n' for CR LF.
  555. * \param[in] prec Number of digits after decimal point.
  556. * \return The number of bytes written or -1 if an error occurs.
  557. */
  558. size_t printField(float value, char term, uint8_t prec = 2) {
  559. return printField(static_cast<double>(value), term, prec);
  560. }
  561. /** Print a number followed by a field terminator.
  562. * \param[in] value The number to be printed.
  563. * \param[in] term The field terminator. Use '\\n' for CR LF.
  564. * \return The number of bytes written or -1 if an error occurs.
  565. */
  566. template<typename Type>
  567. size_t printField(Type value, char term) {
  568. return m_fFile ? m_fFile->printField(value, term) :
  569. m_xFile ? m_xFile->printField(value, term) : 0;
  570. }
  571. /** Print a file's size.
  572. *
  573. * \param[in] pr Print stream for output.
  574. *
  575. * \return The number of characters printed is returned
  576. * for success and zero is returned for failure.
  577. */
  578. size_t printFileSize(print_t* pr) {
  579. return m_fFile ? m_fFile->printFileSize(pr) :
  580. m_xFile ? m_xFile->printFileSize(pr) : 0;
  581. }
  582. /** Print a file's modify date and time
  583. *
  584. * \param[in] pr Print stream for output.
  585. *
  586. * \return true for success or false for failure.
  587. */
  588. size_t printModifyDateTime(print_t* pr) {
  589. return m_fFile ? m_fFile->printModifyDateTime(pr) :
  590. m_xFile ? m_xFile->printModifyDateTime(pr) : 0;
  591. }
  592. /** Print a file's name
  593. *
  594. * \param[in] pr Print stream for output.
  595. *
  596. * \return true for success or false for failure.
  597. */
  598. size_t printName(print_t* pr) {
  599. return m_fFile ? m_fFile->printName(pr) :
  600. m_xFile ? m_xFile->printName(pr) : 0;
  601. }
  602. /** Read the next byte from a file.
  603. *
  604. * \return For success return the next byte in the file as an int.
  605. * If an error occurs or end of file is reached return -1.
  606. */
  607. int read() {
  608. uint8_t b;
  609. return read(&b, 1) == 1 ? b : -1;
  610. }
  611. /** Read data from a file starting at the current position.
  612. *
  613. * \param[out] buf Pointer to the location that will receive the data.
  614. *
  615. * \param[in] count Maximum number of bytes to read.
  616. *
  617. * \return For success read() returns the number of bytes read.
  618. * A value less than \a count, including zero, will be returned
  619. * if end of file is reached.
  620. * If an error occurs, read() returns -1. Possible errors include
  621. * read() called before a file has been opened, corrupt file system
  622. * or an I/O error occurred.
  623. */
  624. int read(void* buf, size_t count) {
  625. return m_fFile ? m_fFile->read(buf, count) :
  626. m_xFile ? m_xFile->read(buf, count) : -1;
  627. }
  628. /** Remove a file.
  629. *
  630. * The directory entry and all data for the file are deleted.
  631. *
  632. * \note This function should not be used to delete the 8.3 version of a
  633. * file that has a long name. For example if a file has the long name
  634. * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
  635. *
  636. * \return true for success or false for failure.
  637. */
  638. bool remove();
  639. /** Remove a file.
  640. *
  641. * The directory entry and all data for the file are deleted.
  642. *
  643. * \param[in] path Path for the file to be removed.
  644. *
  645. * Example use: dirFile.remove(filenameToRemove);
  646. *
  647. * \note This function should not be used to delete the 8.3 version of a
  648. * file that has a long name. For example if a file has the long name
  649. * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
  650. *
  651. * \return true for success or false for failure.
  652. */
  653. bool remove(const char* path) {
  654. return m_fFile ? m_fFile->remove(path) :
  655. m_xFile ? m_xFile->remove(path) : false;
  656. }
  657. /** Rename a file or subdirectory.
  658. *
  659. * \param[in] newPath New path name for the file/directory.
  660. *
  661. * \return true for success or false for failure.
  662. */
  663. bool rename(const char* newPath) {
  664. return m_fFile ? m_fFile->rename(newPath) :
  665. m_xFile ? m_xFile->rename(newPath) : false;
  666. }
  667. /** Rename a file or subdirectory.
  668. *
  669. * \param[in] dir Directory for the new path.
  670. * \param[in] newPath New path name for the file/directory.
  671. *
  672. * \return true for success or false for failure.
  673. */
  674. bool rename(FsBaseFile* dir, const char* newPath) {
  675. return m_fFile && dir->m_fFile ? m_fFile->rename(dir->m_fFile, newPath) :
  676. m_xFile && dir->m_xFile ? m_xFile->rename(dir->m_xFile, newPath) :
  677. false;
  678. }
  679. /** Set the file's current position to zero. */
  680. void rewind() {
  681. if (m_fFile) m_fFile->rewind();
  682. if (m_xFile) m_xFile->rewind();
  683. }
  684. /** Rewind a file if it is a directory */
  685. void rewindDirectory() {
  686. if (isDir()) rewind();
  687. }
  688. /** Remove a directory file.
  689. *
  690. * The directory file will be removed only if it is empty and is not the
  691. * root directory. rmdir() follows DOS and Windows and ignores the
  692. * read-only attribute for the directory.
  693. *
  694. * \note This function should not be used to delete the 8.3 version of a
  695. * directory that has a long name. For example if a directory has the
  696. * long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
  697. *
  698. * \return true for success or false for failure.
  699. */
  700. bool rmdir();
  701. /** Seek to a new position in the file, which must be between
  702. * 0 and the size of the file (inclusive).
  703. *
  704. * \param[in] pos the new file position.
  705. * \return true for success or false for failure.
  706. */
  707. bool seek(uint64_t pos) {return seekSet(pos);}
  708. /** Set the files position to current position + \a pos. See seekSet().
  709. * \param[in] offset The new position in bytes from the current position.
  710. * \return true for success or false for failure.
  711. */
  712. bool seekCur(int64_t offset) {
  713. return seekSet(curPosition() + offset);
  714. }
  715. /** Set the files position to end-of-file + \a offset. See seekSet().
  716. * Can't be used for directory files since file size is not defined.
  717. * \param[in] offset The new position in bytes from end-of-file.
  718. * \return true for success or false for failure.
  719. */
  720. bool seekEnd(int64_t offset = 0) {
  721. return seekSet(fileSize() + offset);
  722. }
  723. /** Sets a file's position.
  724. *
  725. * \param[in] pos The new position in bytes from the beginning of the file.
  726. *
  727. * \return true for success or false for failure.
  728. */
  729. bool seekSet(uint64_t pos) {
  730. return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos) :
  731. m_xFile ? m_xFile->seekSet(pos) : false;
  732. }
  733. /** \return the file's size. */
  734. uint64_t size() const {return fileSize();}
  735. /** The sync() call causes all modified data and directory fields
  736. * to be written to the storage device.
  737. *
  738. * \return true for success or false for failure.
  739. */
  740. bool sync() {
  741. return m_fFile ? m_fFile->sync() :
  742. m_xFile ? m_xFile->sync() : false;
  743. }
  744. /** Set a file's timestamps in its directory entry.
  745. *
  746. * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
  747. * OR of flags from the following list
  748. *
  749. * T_ACCESS - Set the file's last access date and time.
  750. *
  751. * T_CREATE - Set the file's creation date and time.
  752. *
  753. * T_WRITE - Set the file's last write/modification date and time.
  754. *
  755. * \param[in] year Valid range 1980 - 2107 inclusive.
  756. *
  757. * \param[in] month Valid range 1 - 12 inclusive.
  758. *
  759. * \param[in] day Valid range 1 - 31 inclusive.
  760. *
  761. * \param[in] hour Valid range 0 - 23 inclusive.
  762. *
  763. * \param[in] minute Valid range 0 - 59 inclusive.
  764. *
  765. * \param[in] second Valid range 0 - 59 inclusive
  766. *
  767. * \note It is possible to set an invalid date since there is no check for
  768. * the number of days in a month.
  769. *
  770. * \note
  771. * Modify and access timestamps may be overwritten if a date time callback
  772. * function has been set by dateTimeCallback().
  773. *
  774. * \return true for success or false for failure.
  775. */
  776. bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
  777. uint8_t hour, uint8_t minute, uint8_t second) {
  778. return m_fFile ?
  779. m_fFile->timestamp(flags, year, month, day, hour, minute, second) :
  780. m_xFile ?
  781. m_xFile->timestamp(flags, year, month, day, hour, minute, second) :
  782. false;
  783. }
  784. /** Truncate a file to the current position.
  785. *
  786. * \return true for success or false for failure.
  787. */
  788. bool truncate() {
  789. return m_fFile ? m_fFile->truncate() :
  790. m_xFile ? m_xFile->truncate() : false;
  791. }
  792. /** Truncate a file to a specified length.
  793. * The current file position will be set to end of file.
  794. *
  795. * \param[in] length The desired length for the file.
  796. *
  797. * \return true for success or false for failure.
  798. */
  799. bool truncate(uint64_t length) {
  800. return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length) :
  801. m_xFile ? m_xFile->truncate(length) : false;
  802. }
  803. /** Write a string to a file. Used by the Arduino Print class.
  804. * \param[in] str Pointer to the string.
  805. * Use getWriteError to check for errors.
  806. * \return count of characters written for success or -1 for failure.
  807. */
  808. size_t write(const char* str) {
  809. return write(str, strlen(str));
  810. }
  811. /** Write a byte to a file. Required by the Arduino Print class.
  812. * \param[in] b the byte to be written.
  813. * Use getWriteError to check for errors.
  814. * \return 1 for success and 0 for failure.
  815. */
  816. size_t write(uint8_t b) {return write(&b, 1);}
  817. /** Write data to an open file.
  818. *
  819. * \note Data is moved to the cache but may not be written to the
  820. * storage device until sync() is called.
  821. *
  822. * \param[in] buf Pointer to the location of the data to be written.
  823. *
  824. * \param[in] count Number of bytes to write.
  825. *
  826. * \return For success write() returns the number of bytes written, always
  827. * \a nbyte. If an error occurs, write() returns zero and writeError is set.
  828. */
  829. size_t write(const void* buf, size_t count) {
  830. return m_fFile ? m_fFile->write(buf, count) :
  831. m_xFile ? m_xFile->write(buf, count) : 0;
  832. }
  833. private:
  834. newalign_t m_fileMem[FS_ALIGN_DIM(ExFatFile, FatFile)];
  835. FatFile* m_fFile = nullptr;
  836. ExFatFile* m_xFile = nullptr;
  837. };
  838. /**
  839. * \class FsFile
  840. * \brief FsBaseFile file with Arduino Stream.
  841. */
  842. class FsFile : public StreamFile<FsBaseFile, uint64_t> {
  843. public:
  844. /** Opens the next file or folder in a directory.
  845. *
  846. * \param[in] oflag open flags.
  847. * \return a FatStream object.
  848. */
  849. FsFile openNextFile(oflag_t oflag = O_RDONLY) {
  850. FsFile tmpFile;
  851. tmpFile.openNext(this, oflag);
  852. return tmpFile;
  853. }
  854. };
  855. #endif // FsFile_h