local lfs = require("lfs") local M = {} -- 创建目录 M.create_dir = function(dirpath) -- 检查操作系统类型 local os_type = package.config:sub(1,1) if os_type == "\\" then -- Windows 系统 os.execute("mkdir \"" .. dirpath:gsub("/", "\\") .. "\" /p") else -- Unix/Linux/Mac 系统 os.execute("mkdir -p \"" .. dirpath .. "\"") end end -- 转换为整数 M.tointeger = function(data) local num = tonumber(data) if num == nil then return nil end return math.floor(num) end -- 转为时间戳 M.to_timestamp = function(time_str,pattern) if pattern == nil then pattern = "(%d+)%-(%d+)%-(%d+)%s+(%d+):(%d+):(%d+)" end local y, m, d, h, min, s = time_str:match(pattern) local timestamp = os.time({ year = tonumber(y), month = tonumber(m), day = tonumber(d), hour = tonumber(h), min = tonumber(min), sec = tonumber(s) }) return timestamp end -- 取扩展名 M.ext = function(filepath) -- 取扩展名 return string.match(filepath,"%.([^.]+)$") end -- 复制文件 -- 增加第三个参数 replace,是否替换目标文件,默认为 false M.copy_file = function(src, dst, replace) replace = replace or false -- 检查目标文件是否存在 local dst_file = io.open(dst, "r") if dst_file ~= nil then dst_file:close() if not replace then return true end end -- 打开源文件 local file = io.open(src, "rb") if not file then print("ERR 2,src:",src) return false end local content = file:read("*all") file:close() -- 写入目标文件 local file = io.open(dst, "wb") if not file then print("ERR 3") return false end file:write(content) file:close() return true end -- 取路径文件名(带扩展名) M.filename = function(filepath, have_ext) local filename = string.match(filepath, "[^/]+$") if have_ext == false then local name = string.match(filename, "^(.*)%.") -- get name before last dot if name ~= nil then return name else return filename -- no extension end end return filename end -- 删除文件 M.delete_file = function(filepath) if os.remove(fw.website_dir()..filepath) ~= true then return false end return true end -- 读取文件内容 M.read_file = function(filepath) local file = io.open(filepath, "rb") if not file then return nil, "无法打开文件: " .. tostring(filepath) end local content = file:read("*all") file:close() return content end -- 保存内容到文件 M.save_file = function(filepath, content) local file = io.open(filepath, "wb") if not file then return false, "无法打开文件: " .. tostring(filepath) end file:write(content) file:close() return true end -- 是否存在文件 M.exists_file = function(filepath) local file = io.open(filepath, "rb") if file then file:close() return true else return false end end -- 取文件大小 M.file_size = function(filepath) local file = io.open(filepath, "rb") if not file then return nil end local size = file:seek("end") file:close() return size end -- 取近N个月时间 M.recent_months = function(n) local mons = {} local function format_time(y, m, d, h, i, s) return string.format("%04d-%02d-%02d %02d:%02d:%02d", y, m, d, h, i, s) end local now = os.time() local cur = os.date("*t", now) for i = n-1, 0, -1 do local year = cur.year local month = cur.month - i while month <= 0 do month = month + 12 year = year - 1 end -- 获取该月第一天与最后一天 local first_day = format_time(year, month, 1, 0, 0, 0) local next_month = month + 1 local next_year = year if next_month > 12 then next_month = 1 next_year = year + 1 end -- next_month 1号的前一天就是当前月最后一天 local last_day_ts = os.time{year=next_year, month=next_month, day=1, hour=0, min=0, sec=0} - 1 local last_day_tm = os.date("*t", last_day_ts) local last_day = format_time(last_day_tm.year, last_day_tm.month, last_day_tm.day, 23, 59, 59) local month_str = string.format("%04d-%02d", year, month) table.insert(mons, month_str) end return mons end M.recent_months2 = function(n) local mons = {} local function format_time(y, m, d, h, i, s) return string.format("%04d-%02d-%02d %02d:%02d:%02d", y, m, d, h, i, s) end local now = os.time() local cur = os.date("*t", now) for i = n-1, 0, -1 do local year = cur.year local month = cur.month - i while month <= 0 do month = month + 12 year = year - 1 end -- 获取该月第一天与最后一天 local first_day = format_time(year, month, 1, 0, 0, 0) local next_month = month + 1 local next_year = year if next_month > 12 then next_month = 1 next_year = year + 1 end -- next_month 1号的前一天就是当前月最后一天 local last_day_ts = os.time{year=next_year, month=next_month, day=1, hour=0, min=0, sec=0} - 1 local last_day_tm = os.date("*t", last_day_ts) local last_day = format_time(last_day_tm.year, last_day_tm.month, last_day_tm.day, 23, 59, 59) local month_str = string.format("%04d-%02d", year, month) table.insert(mons, { month = month_str, start_time = first_day, end_time = last_day }) end return mons end -- 十六进制转字节数组 M.hex_to_bytes = function(hex_str) -- 移除所有非十六进制字符 hex_str = hex_str:gsub("[^%x]", ""):upper() -- 补0使长度为偶数 if #hex_str % 2 == 1 then hex_str = "0" .. hex_str end -- 使用 gsub 一次性转换 return (hex_str:gsub("(%x%x)", function(hex) return string.char(tonumber(hex, 16)) end)) end --[[ 还原 Redis 字符串(去转义) @param value 被转义的字符串 @return 返回还原后的字符串 ]] M.unescape_value = function(value) if value == nil then return nil end local str = tostring(value) -- 如果是用双引号包住的,去掉包裹并恢复转义 if #str >= 2 and string.sub(str,1,1) == "\"" and string.sub(str,-1,-1) == "\"" then str = string.sub(str,2,-2) str = string.gsub(str, "\\\"", "\"") str = string.gsub(str, "\\\\", "\\") return str end return str end -- 是否为静态资源扩展名 M.is_static_ext_not_html = function(ext) local static_exts = { "jpg", "jpeg", "png", "gif", "bmp", "ico", "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "css", "js", "json", "xml", "yaml", "yml", "zip", "rar", "7z", "tar", "gz", "bz2", "xz", "mp3", "wav", "ogg", "aac", "m4a", "mp4", "avi", "mov", "wmv", "flv", "webm", "mkv", "avi", "mov", "wmv", "flv", "webm", "mkv", } for _, v in ipairs(static_exts) do if v == ext then return true end end return false end -- 遍历目录 M.traverse_dir = function(dirpath) local files = {} for file in lfs.dir(dirpath) do if file ~= "." and file ~= ".." then table.insert(files, file) end end return files end -- 数组是否一致(不考虑顺序) -- 只考虑 string 和 number/integer 类型,其它类型忽略 M.array_equal = function(a, b) -- 辅助函数:判断是否为有效类型(string 或 number) local function is_valid_type(v) return type(v) == "string" or type(v) == "number" end -- 统计数组中有效类型元素的值及其出现次数 local function count_values(arr) local counts = {} for _, v in ipairs(arr) do if is_valid_type(v) then local key = tostring(v) -- 统一转换为字符串作为key counts[key] = (counts[key] or 0) + 1 end end return counts end -- 统计两个数组的有效元素 local counts_a = count_values(a) local counts_b = count_values(b) -- 检查 counts_a 中的所有键值对是否在 counts_b 中匹配 for key, count in pairs(counts_a) do if counts_b[key] ~= count then return false end end -- 检查 counts_b 中的所有键值对是否在 counts_a 中匹配 for key, count in pairs(counts_b) do if counts_a[key] ~= count then return false end end return true end return M