diff options
-rw-r--r-- | lualibs-io.lua | 120 |
1 files changed, 92 insertions, 28 deletions
diff --git a/lualibs-io.lua b/lualibs-io.lua index 657b755..06e1fb5 100644 --- a/lualibs-io.lua +++ b/lualibs-io.lua @@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['l-io'] = { local io = io local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format local concat = table.concat +local floor = math.floor local type = type if string.find(os.getenv("PATH"),";") then @@ -17,10 +18,49 @@ else io.fileseparator, io.pathseparator = "/" , ":" end +local function readall(f) + return f:read("*all") +end + +-- The next one is upto 50% faster on large files and less memory consumption due +-- to less intermediate large allocations. This phenomena was discussed on the +-- luatex dev list. + +local function readall(f) + local size = f:seek("end") + if size == 0 then + return "" + elseif size < 1024*1024 then + f:seek("set",0) + return f:read('*all') + else + local done = f:seek("set",0) + if size < 1024*1024 then + step = 1024 * 1024 + elseif size > 16*1024*1024 then + step = 16*1024*1024 + else + step = floor(size/(1024*1024)) * 1024 * 1024 / 8 + end + local data = { } + while true do + local r = f:read(step) + if not r then + return concat(data) + else + data[#data+1] = r + end + end + end +end + +io.readall = readall + function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then - local data = f:read('*all') +-- local data = f:read('*all') + local data = readall(f) f:close() if #data > 0 then return data @@ -46,31 +86,33 @@ function io.savedata(filename,data,joiner) end end +-- we can also chunk this one if needed: io.lines(filename,chunksize,"*l") + function io.loadlines(filename,n) -- return nil if empty local f = io.open(filename,'r') - if f then - if n then - local lines = { } - for i=1,n do - local line = f:read("*lines") - if line then - lines[#lines+1] = line - else - break - end - end - f:close() - lines = concat(lines,"\n") - if #lines > 0 then - return lines - end - else - local line = f:read("*line") or "" - assert(f:close()) - if #line > 0 then - return line + if not f then + -- no file + elseif n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break end end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + f:close() + if #line > 0 then + return line + end end end @@ -90,7 +132,7 @@ function io.exists(filename) if f == nil then return false else - assert(f:close()) + f:close() return true end end @@ -101,7 +143,7 @@ function io.size(filename) return 0 else local s = f:seek("end") - assert(f:close()) + f:close() return s end end @@ -109,9 +151,13 @@ end function io.noflines(f) if type(f) == "string" then local f = io.open(filename) - local n = f and io.noflines(f) or 0 - assert(f:close()) - return n + if f then + local n = f and io.noflines(f) or 0 + f:close() + return n + else + return 0 + end else local n = 0 for _ in f:lines() do @@ -288,7 +334,7 @@ function io.readstring(f,n,m) f:seek("set",n) n = m end - local str = gsub(f:read(n),"%z","") + local str = gsub(f:read(n),"\000","") return str end @@ -296,3 +342,21 @@ end if not io.i_limiter then function io.i_limiter() end end -- dummy so we can test safely if not io.o_limiter then function io.o_limiter() end end -- dummy so we can test safely + +-- This works quite ok: +-- +-- function io.piped(command,writer) +-- local pipe = io.popen(command) +-- -- for line in pipe:lines() do +-- -- print(line) +-- -- end +-- while true do +-- local line = pipe:read(1) +-- if not line then +-- break +-- elseif line ~= "\n" then +-- writer(line) +-- end +-- end +-- return pipe:close() -- ok, status, (error)code +-- end |