zoukankan      html  css  js  c++  java
  • Step By Step(Lua输入输出库) Stephen_Liu 博客园

    Step By Step(Lua输入输出库) - Stephen_Liu - 博客园

    Step By Step(Lua输入输出库)

    Posted on 2012-07-13 09:12 Stephen_Liu 阅读(893) 评论(0) 编辑 收藏

        I/O库为文件操作提供了两种不同的模型,简单模型和完整模型。简单模型假设一个当前输入文件和一个当前输出文件,他的I/O操作均作用于这些文件。完整模型则使用显式的文件句柄,并将所有的操作定义为文件句柄上的方法。
        1. 简单模型:
        I/O库会将进程标准输入输出作为其缺省的输入文件和输出文件。我们可以通过io.input(filename)io.output(filename)这两个函数来改变当前的输入输出文件。
        1). io.write函数:
        函数原型为io.write(...)。该函数将所有参数顺序的写入到当前输出文件中。如:
        io.write("hello","world") --写出的内容为helloworld

        2). io.read函数:
        下表给出了该函数参数的定义和功能描述:

    参数字符串含义
    "*all"读取整个文件
    "*line"读取下一行
    "*number"读取一个数字
    <num>读取一个不超过<num>个字符的字符串

        调用io.read("*all")会读取当前输入文件的所有内容,以当前位置作为开始。如果当前位置处于文件的末尾,或者文件为空,那个该调用返回一个空字符串。由于Lua可以高效的处理长字符串,因此在Lua中可以先将数据从文件中完整读出,之后在通过Lua字符串库提供的函数进行各种处理。
        调用io.read("*line")会返回当前文件的下一行,但不包含换行符。当到达文件末尾时,该调用返回nil。如:

    复制代码
    1 for count = 1,math.huge do
    2     local line = io.read("*line")  --如果不传参数,缺省值也是"*line"
    3     if line == nil then 
    4         break
    5     end
    6     io.write(string.format("%6d  ",count),line,"\n")
    7 end
    复制代码

        如果只是为了迭代文件中的所有行,可以使用io.lines函数,以迭代器的形式访问文件中的每一行数据,如:

    复制代码
    1 local lines = {}
    2 for line in io.lines() do   --通过迭代器访问每一个数据
    3     lines[#lines + 1] = line
    4 end
    5 table.sort(lines)  --排序,Lua标准库的table库提供的函数。
    6 for _,l in ipairs(lines) do
    7     io.write(l,"\n")
    8 end
    复制代码

        调用io.read("*number")会从当前输入文件中读取一个数字。此时read将直接返回一个数字,而不是字符串。"*number"选项会忽略数字前面所有的空格,并且能处理像-3、+5.2这样的数字格式。如果当前读取的数据不是合法的数字,read返回nil。在调用read是可以指定多个选项,函数会根据每个选项参数返回相应的内容。如:

    复制代码
     1 --[[
     2     6.0  -3.23   1000
     3     ... ...
     4     下面的代码读取注释中的数字
     5 --]]
     6 while true do
     7     local n1,n2,n3 = io.read("*number","*number","*number")
     8     if not n1 then
     9         break
    10     end
    11     print(math.max(n1,n2,n3))
    12 end
    复制代码

        调用io.read(<num>)会从输入文件中最多读取n个字符,如果读不到任何字符,返回nil。否则返回读取到的字符串。如:

    复制代码
    1 while true do
    2     local block = io.read(2^13)
    3     if not block then
    4         break
    5     end
    6     io.write(block)
    7 end
    复制代码

        io.read(0)是一种特殊的情况,用于检查是否到达了文件的末尾。如果没有到达,返回空字符串,否则nil。

        2. 完整I/O模型:
        Lua中完整I/O模型的使用方式非常类似于C运行时库的文件操作函数,它们都是基于文件句柄的。
        1). 通过io.open函数打开指定的文件,并且在参数中给出对该文件的打开模式,其中"r"表示读取,"w"表示覆盖写入,即先删除文件原有的内容,"a"表示追加式写入,"b"表示以二进制的方式打开文件。在成功打开文件后,该函数将返回表示该文件的句柄,后面所有基于该文件的操作,都需要将该句柄作为参数传入。如果打开失败,返回nil。其中错误信息由该函数的第二个参数返回,如:
        assert(io.open(filename,mode))  --如果打开失败,assert将打印第二个参数给出的错误信息。
        
        2). 文件读写函数read/write。这里需要用到冒号语法,如:

    1 local f = assert(io.open(filename,"r"))
    2 local t = f:read("*all")  --对于read而言,其参数完全等同于简单模型下read的参数。
    3 f:close()

        此外,I/O库还提供了3个预定义的文件句柄,即io.stdin(标准输入)、io.stdout(标准输出)、io.stderr(标准错误输出)。如:
        io.stderr:write("This is an error message.")
        事实上,我们也可以混合使用简单模式和完整模式,如:

    1 local temp = io.input()   --将当前文件句柄保存
    2 io.input("newInputfile")  --打开新的输入文件
    3 io.input():close()        --关闭当前文件
    4 io.input(temp)            --恢复原来的输入文件


        3). 性能小技巧:
        由于一次性读取整个文件比逐行读取要快一些,但对于较大的文件,这样并不可行,因此Lua提供了一种折中的方式,即一次读取指定字节数量的数据,如果当前读取中的最后一行不是完整的一行,可通过该方式将该行的剩余部分也一并读入,从而保证本次读取的数据均为整行数据,以便于上层逻辑的处理。如:
        local lines,rest = f:read(BUFSIZE,"*line") --rest变量包含最后一行中没有读取的部分。
        下面是Shell中wc命令的一个简单实现。

    复制代码
     1 local BUFSIZE = 8192
     2 local f = io.input(arg[1])  --打开输入文件
     3 local cc, lc, wc, = 0, 0, 0  --分别计数字符、行和单词    
     4 while true do
     5     local lines,rest = f:read(BUFSIZE,"*line")
     6     if not lines then
     7         break
     8     end
     9     if rest then
    10         lines = lines .. rest .. "\n"
    11     end
    12     cc = cc + #lines
    13     --计算单词数量
    14     local _, t = string.gsub(lines."%S+","")
    15     wc = wc + t
    16     --计算行数
    17     _,t = string.gsub(line,"\n","\n")
    18     lc = lc + t
    19 end
    20 print(lc,wc,cc)
    复制代码


        4). 其它文件操作:
        如io.flush函数会将io缓存中的数据刷新到磁盘文件上。io.close函数将关闭当前打开的文件。io.seek函数用于设置或获取当前文件的读写位置,其函数原型为f:seek(whence,offset),如果whence的值为"set",offset的值则表示为相对于文件起始位置的偏移量。如为"cur"(默认值),offset则为相对于当前位置的偏移量,如为"end",则为相对于文件末尾的偏移量。函数的返回值与whence参数无关,总是返回文件的当前位置,即相对于文件起始处的偏移字节数。offset的默认值为0。如:

    1 function fsize(file)
    2     local current = file:seek()   --获取当前位置
    3     local size = file:seek("end") --获取文件大小
    4     file:seek("set",current)      --恢复原有的当前位置
    5     return size
    6 end

        最后需要指出的是,如果发生错误,所有这些函数均返回nil和一条错误信息。

  • 相关阅读:
    MIPS笔记
    花生壳动态域名解析工具原理
    SEE MIPS RUN 第六章 内存管理与TLB
    C/C++动态内存创建与内存管理
    ngclass 用法
    看了一个烟花的html作品 引用:http://www.w3cfuns.com/blog54440495404365.html
    ngclip angualr 的copy功能
    学习技术的方法
    restful restAPI 的定义方式
    我与计算机
  • 原文地址:https://www.cnblogs.com/lexus/p/2592037.html
Copyright © 2011-2022 走看看