24

I am trying to read a full mp3 file in order to read out the id3 tags. That's when I noticed that file:read("*a") apparently does not read the full file but rather a small part. So I tried to build some kind of workaround in order to get the content of the whole file:

function readAll(file)
    local f = io.open(file, "r")
    local content = ""
    local length = 0

    while f:read(0) ~= "" do
        local current = f:read("*all")

        print(#current, length)
        length = length + #current

        content = content .. current
    end

    return content
end

for my testfile, this shows that 256 reading operations are performed, reading a total of ~113kB (the whole file is ~7MB). Though this should be enough to read most id3 tags, I wonder why Lua behaves in this way (especially because it does not when reading large textbased files such as *.obj or *.ase). Is there any explanation for this behaviour or maybe a solution to reliably read the whole file?

Henrik Ilgen
  • 1,879
  • 1
  • 17
  • 35
  • 8
    Are you on windows? make sure you open the file in binary mode ("rb" to io.open) – daurnimator Apr 30 '12 at 16:01
  • 1
    Argh, that was the point. Never had to use binary mode before. Thank you a lot! – Henrik Ilgen Apr 30 '12 at 16:26
  • Could someone explain the format ***all** in function `f:read("*all")` ? It seems "*all" is equal to "*a" ? I could not find the document in lua manual https://www.lua.org/manual/5.1/manual.html#pdf-file:read – Liu Hao Nov 14 '17 at 02:45
  • 1
    @liuhao All characters after the first two (The `*a`) are ignored, according to this answer: https://stackoverflow.com/questions/47277203/what-is-the-all-format-in-lua-fileread-means I guess I got this from this chapter in pil back in the days: https://www.lua.org/pil/21.1.html, the advantage being (I guess) that you don't have to remember what `*a`, `*n` and `*l` stand for, because you can instead write it out. – Henrik Ilgen Nov 14 '17 at 10:55

1 Answers1

71

I must be missing something but I fail to see why a loop is needed. This should work (but you'd better add error handling in case the file cannot be opened):

function readAll(file)
    local f = assert(io.open(file, "rb"))
    local content = f:read("*all")
    f:close()
    return content
end
VasiliNovikov
  • 9,681
  • 4
  • 44
  • 62
lhf
  • 70,581
  • 9
  • 108
  • 149
  • 2
    as can be seen in the comments to my question, @daurnimator already figured out that the problem was the missing b, but thanks for your answer anyway :) edit: I marked your answer as accepted in order to show people my question has been solved. – Henrik Ilgen Apr 30 '12 at 19:43