Home > other >  find specific Byte in File and read until specific byte in Lua
find specific Byte in File and read until specific byte in Lua

Time:02-10

Is it possible to search at first inside the file after an specific byte and find the position and read just the bytes from the file in until that specific byte?

At the moment it is just possible for me to read some bytes or the whole file in and afterwards search for that specific byte. like this:

local function read_file(path)
  local file = open(path, "r") -- r read mode and b binary mode
  if not file then return nil end
  local content = file:read(64) -- reading 64 bytes
  file:close()
  return content
end

local fileContent = read_file("../test/l_0.dat");
print(fileContent)

function parse(line)
   if line then
     len = 1
     a = line:find("V", len  1) --find V in content 
     return a
   else
     return false
   end
end

a = parse(fileContent) --position of V in content 
print(a)
print(string.sub(fileContent, a)) -- content until first found V 

In this example i find at position 21 the first V. So it would be cool to read in only 21 bytes except of 64 bytes or the whole file. But then i need to find the position before reading something in. Is this possible ? (The 21byte are variable, it could be 20 or 50 or so on)

CodePudding user response:

You can specify a file position using file:seek and read a certain number of characters (bytes) by providing an integer to file:read

local file = file:open(somePath)
if file then
  -- set cursor to -5 bytes from the file's end
  file:seek("end", -5)
  -- read 3 bytes
  print(file:read(3))
  file:close()
end

You cannot search in a file without reading it. If you don't want to read the entire file you can read it in chunks either by reading it linewise (if there are lines in your file) or by reading a specific number of bytes each time until you find something. Of course you can also read it byte-wise.

You can argue if it makes more sense to read a 64 byte file as a whole or in chunks. I mean in most scenarios you won't notice any difference.

So you could file:read(1) in a loop that terminates once you found a V or reach the end of the file.

local file = io.open(somePath)
if file then
  local data = ""
  for i = 1, 64 do
    local b = file:read(1) 
    if not b then print("no V in file") data = nil break end
    data = data .. b
    if b == "V" then print(data) break end
  end
  file:close()
end

vs

local file = io.open("d:/test.txt", "r")
if file then  
  local data = file:read("a")
  local pos = data:find("V")
  if pos then
      print(data:sub(1, pos))
  end
  file:close()
end

CodePudding user response:

(Or) Correct your code to...

local function read_file(path)
  local file = io.open(path, "r") -- r read mode and b binary mode
  if not file then return nil end
  local content = file:read(64) -- reading 64 bytes
  file:close()
  return content
end

local fileContent = read_file("test/l_0.dat") -- '../' causing error
print(fileContent)

local function parse(line)
   if line then
     local len = 1
     local a = line:find("V", len  1) --find V in content 
     return a
   else
     return false
   end
end

print(fileContent:sub(1, parse(fileContent))) -- content until first found V

That puts out...

0123456789VabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

0123456789V

If you want that V is a (single) delimiter you probably dont want to put it out.
Meet the strength of string.sub(text, start, stop)...

print(fileContent:sub(1, parse(fileContent) - 1))  -- before V                             
-- 0123456789
print(fileContent:sub(parse(fileContent)   1, -1)) -- after V
-- abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
  • Related