tfcard_app.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. --[[
  2. @module tfcard_app
  3. @summary TF卡文件操作测试模块
  4. @version 1.0.0
  5. @date 2025.08.25
  6. @author 王棚嶙
  7. @usage
  8. 本文件为TF卡的文件操作测试流程:
  9. 1. 创建目录
  10. 2. 创建并写入文件
  11. 3. 检查文件是否存在
  12. 4. 获取文件大小
  13. 5. 读取文件内容
  14. 6. 启动计数文件操作
  15. 7. 文件追加测试
  16. 8. 按行读取测试
  17. 9. 读取后关闭文件
  18. 10. 文件重命名
  19. 11. 列举目录内容
  20. 12. 删除文件
  21. 13. 删除目录
  22. 本文件没有对外接口,直接在main.lua中require "tfcard_app"就可以加载运行
  23. ]]
  24. function tfcard_main_task() -- 开始进行主测试流程。
  25. -- ########## SPI初始化 ##########
  26. -- Air8000整机核心板上TF卡的的pin_cs为gpio20,spi_id为1.请根据实际硬件修改
  27. spi_id, pin_cs = 1, 12
  28. spi.setup(spi_id, nil, 0, 0, 400 * 1000)
  29. --设置片选引脚同一spi总线上的所有从设备在初始化时必须要先拉高CS脚,防止从设备之间互相干扰。
  30. gpio.setup(pin_cs, 1)
  31. -- ########## 开始进行tf卡挂载 ##########
  32. --挂载失败默认格式化,
  33. -- 如无需格式化应改为fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000, nil, 1, false),
  34. -- 一般是在测试硬件是否有问题的时候把格式化取消掉
  35. mount_ok, mount_err = fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000)
  36. if mount_ok then
  37. log.info("fatfs.mount", "挂载成功", mount_err)
  38. else
  39. log.error("fatfs.mount", "挂载失败", mount_err)
  40. goto resource_cleanup
  41. end
  42. -- ########## 获取SD卡的可用空间信息并打印。 ##########
  43. data, err = fatfs.getfree("/sd")
  44. if data then
  45. --打印SD卡的可用空间信息
  46. log.info("fatfs", "getfree", json.encode(data))
  47. else
  48. --打印错误信息
  49. log.info("fatfs", "getfree", "err", err)
  50. goto resource_cleanup
  51. end
  52. -- 列出所有挂载点,如不需要,可注释掉。
  53. data = io.lsmount()
  54. log.info("fs", "lsmount", json.encode(data))
  55. -- ########## 功能: 启用fatfs调试模式 ##########
  56. -- fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因.(设置调试模式)
  57. -- 执行tfcard文件操作演示
  58. log.info("文件操作", "===== 开始文件操作 =====")
  59. dir_path = "/sd/io_test"
  60. -- 1. 创建目录
  61. if io.mkdir(dir_path) then
  62. log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
  63. else
  64. -- 检查是否目录已存在
  65. if io.exists(dir_path) then
  66. log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
  67. else
  68. log.error("io.mkdir", "目录创建失败且目录不存在", "路径:" .. dir_path)
  69. goto resource_cleanup
  70. end
  71. end
  72. -- 2. 创建并写入文件
  73. file_path = dir_path .. "/boottime"
  74. file = io.open(file_path, "wb")
  75. if file then
  76. file:write("这是io库API文档示例的测试内容")
  77. file:close()
  78. --在LuatOS文件操作中,执行file:close()是必须且关键的操作,它用于关闭文件句柄,释放资源,并确保数据被正确写入磁盘。
  79. -- 如果不执行file:close(),可能会导致数据丢失、文件损坏或其他不可预测的问题。
  80. log.info("文件创建", "文件写入成功", "路径:" .. file_path)
  81. else
  82. log.error("文件创建", "文件创建失败", "路径:" .. file_path)
  83. goto resource_cleanup
  84. end
  85. -- 3. 检查文件是否存在
  86. if io.exists(file_path) then
  87. log.info("io.exists", "文件存在", "路径:" .. file_path)
  88. else
  89. log.error("io.exists", "文件不存在", "路径:" .. file_path)
  90. goto resource_cleanup
  91. end
  92. -- 4. 获取文件大小
  93. file_size = io.fileSize(file_path)
  94. if file_size then
  95. log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
  96. else
  97. log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
  98. goto resource_cleanup
  99. end
  100. -- 5. 读取文件内容
  101. file = io.open(file_path, "rb")
  102. if file then
  103. content = file:read("*a")
  104. log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
  105. file:close()
  106. else
  107. log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
  108. goto resource_cleanup
  109. end
  110. -- 6. 启动计数文件操作
  111. count = 0
  112. --以只读模式打开文件
  113. file = io.open(file_path, "rb")
  114. if file then
  115. data = file:read("*a")
  116. log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
  117. count = tonumber(data) or 0
  118. file:close()
  119. else
  120. log.warn("启动计数", "文件不存在或无法打开")
  121. end
  122. log.info("启动计数", "当前值:", count)
  123. count=count + 1
  124. log.info("启动计数", "更新值:", count)
  125. file = io.open(file_path, "wb")
  126. if file then
  127. file:write(tostring(count))
  128. file:close()
  129. log.info("文件写入", "路径:" .. file_path, "内容:", count)
  130. else
  131. log.error("文件写入", "无法打开文件", "路径:" .. file_path)
  132. goto resource_cleanup
  133. end
  134. -- 7. 文件追加测试
  135. append_file = dir_path .. "/test_a"
  136. -- 清理旧文件
  137. os.remove(append_file)
  138. -- 创建并写入初始内容
  139. file = io.open(append_file, "wb")
  140. if file then
  141. file:write("ABC")
  142. file:close()
  143. log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
  144. else
  145. log.error("文件创建", "无法创建文件", "路径:" .. append_file)
  146. goto resource_cleanup
  147. end
  148. -- 追加内容
  149. file = io.open(append_file, "a+")
  150. if file then
  151. file:write("def")
  152. file:close()
  153. log.info("文件追加", "路径:" .. append_file, "追加内容:def")
  154. else
  155. log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
  156. goto resource_cleanup
  157. end
  158. -- 验证追加结果
  159. file = io.open(append_file, "r")
  160. if file then
  161. data = file:read("*a")
  162. log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
  163. data == "ABCdef" and "成功" or "失败")
  164. file:close()
  165. else
  166. log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
  167. goto resource_cleanup
  168. end
  169. -- 8. 按行读取测试
  170. line_file = dir_path .. "/testline"
  171. file = io.open(line_file, "w")
  172. if file then
  173. file:write("abc\n")
  174. file:write("123\n")
  175. file:write("wendal\n")
  176. file:close()
  177. log.info("文件创建", "路径:" .. line_file, "写入3行文本")
  178. else
  179. log.error("文件创建", "无法创建文件", "路径:" .. line_file)
  180. goto resource_cleanup
  181. end
  182. -- 按行读取文件
  183. file = io.open(line_file, "r")
  184. if file then
  185. log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
  186. log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
  187. log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
  188. file:close()
  189. else
  190. log.error("按行读取", "无法打开文件", "路径:" .. line_file)
  191. goto resource_cleanup
  192. end
  193. -- 9. 文件重命名
  194. old_path = append_file
  195. new_path = dir_path .. "/renamed_file.txt"
  196. success, err = os.rename(old_path, new_path)
  197. if success then
  198. log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
  199. -- 验证重命名结果
  200. if io.exists(new_path) and not io.exists(old_path) then
  201. log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
  202. else
  203. log.error("验证结果", "重命名验证失败")
  204. end
  205. else
  206. log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
  207. goto resource_cleanup
  208. end
  209. -- 10. 列举目录内容
  210. log.info("目录操作", "===== 开始目录列举 =====")
  211. ret, data = io.lsdir(dir_path, 50, 0) -- 50表示最多返回50个文件,0表示从目录开头开始
  212. if ret then
  213. log.info("fs", "lsdir", json.encode(data))
  214. else
  215. log.info("fs", "lsdir", "fail", ret, data)
  216. goto resource_cleanup
  217. end
  218. -- 11. 删除文件测试
  219. -- 测试删除renamed_file.txt文件
  220. if os.remove(new_path) then
  221. log.info("os.remove", "文件删除成功", "路径:" .. new_path)
  222. -- 验证renamed_file.txt删除结果
  223. if not io.exists(new_path) then
  224. log.info("验证结果", "renamed_file.txt文件删除验证成功")
  225. else
  226. log.error("验证结果", "renamed_file.txt文件删除验证失败")
  227. end
  228. else
  229. log.error("io.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
  230. goto resource_cleanup
  231. end
  232. -- 测试删除testline文件
  233. if os.remove(line_file) then
  234. log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
  235. -- 验证删除结果
  236. if not io.exists(line_file) then
  237. log.info("验证结果", "testline文件删除验证成功")
  238. else
  239. log.error("验证结果", "testline文件删除验证失败")
  240. end
  241. else
  242. log.error("io.remove", "testline文件删除失败", "路径:" .. line_file)
  243. goto resource_cleanup
  244. end
  245. if os.remove(file_path) then
  246. log.info("os.remove", "文件删除成功", "路径:" .. file_path)
  247. -- 验证删除结果
  248. if not io.exists(file_path) then
  249. log.info("验证结果", "boottime文件删除验证成功")
  250. else
  251. log.error("验证结果", "boottime文件删除验证失败")
  252. end
  253. else
  254. log.error("io.remove", "boottime文件删除失败", "路径:" .. file_path)
  255. goto resource_cleanup
  256. end
  257. -- 12. 删除目录(不能删除非空目录,所以在删除目录前要确保目录内没有文件或子目录)
  258. if io.rmdir(dir_path) then
  259. log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
  260. -- 验证删除结果
  261. if not io.exists(dir_path) then
  262. log.info("验证结果", "目录删除验证成功")
  263. else
  264. log.error("验证结果", "目录删除验证失败")
  265. end
  266. else
  267. log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
  268. goto resource_cleanup
  269. end
  270. log.info("文件操作", "===== 文件操作完成 =====")
  271. -- ########## 功能: 收尾功能演示##########
  272. -- 卸载文件系统和关闭SPI
  273. ::resource_cleanup::
  274. log.info("结束", "开始执行关闭操作...")
  275. -- 如已挂载需先卸载文件系统,未挂载直接关闭SPI
  276. if mount_ok then
  277. if fatfs.unmount("/sd") then
  278. log.info("文件系统", "卸载成功")
  279. else
  280. log.error("文件系统", "卸载失败")
  281. end
  282. end
  283. -- 2. 关闭SPI接口
  284. spi.close(spi_id)
  285. log.info("SPI接口", "已关闭")
  286. end
  287. sys.taskInit(tfcard_main_task)