解析一个超过内存限制的JSON字符串

我在工作的平台上遇到了相当严格的内存限制,我正在寻找一种解决方法,以便在不超过几百字节的情况下解析大型的JSON字符串到内存中。JSON字符串存储在一个更大的芯片(闪存)上的文件中。

有两件事情我无法找到一个好的解决方案:

1.通过指定"路径"访问特定值,例如foo["bar"][2]

(如果这个值是一个数组/对象,那么我们应该只返回它是一个数组/对象的事实,也许还会告诉它是空的还是不空的)

2.遍历JSON中的任何对象/数组。

所以基本上我需要一些函数,当被调用时,一步一步地解析JSON并只保存我们实际需要继续解析的部分。

对于接口,我认为不可能像exampleJson["aa"].2.["gg]那样有一些东西,但我设法接近它:exampleJson["aa"].2.["gg"]()。这将导致调用一个函数,然后轻松地访问{'aa',2,'gg'}并从文件中读取/解析JSON。

这是到目前为止我的代码,但我真的不知道该怎么继续:

https://repl.it/HfwS/2

 - 看起来很复杂,但实际上很简单。使用元表我们创建了一个几乎可以像Lua表一样访问的JSON接口。
- 例如:example["aa"][2]["gg"]()我们只需要在末尾使用括号就可以了
- 问题的关键部分在它说`THIS IS WHERE THE JSON PARSING WOULD HAPPEN`
json = {}
setmetatable(json, {
    __call = function(path)
        local jsonFile = _file.open(filePath)
        local fileLen = jsonFile:stat().size

        local patternTable = {} -- Will store `{'aa',2,'gg'}` for `example.['aa'].[2]['gg']()`

        local fakeJson = {}
        setmetatable(fakeJson, {
            __index = function (t, k)
                patternTable[#patternTable+1] = k
                return fakeJson
            end;
            __call = function()

                -- THIS IS WHERE THE JSON PARSING WOULD HAPPEN --

                -- The patternTable contains {'aa',2,'gg'} at this point

                -- Loop through the json file char by char
                local valueToReturn = ''
                local filePos = 0
                for i=1, fileLen do
                    jsonFile:seek("set", filePos)
                    local currentChar = jsonFile:read(1) -- read character at current position
                    filePos = filePos + 1
                    -- print(currentChar)

                    -- Now the question is, how do we parse the json?
                    print('Magic to parse the json')
                    -- valueToReturn = ?
                end

                patternTable = {} -- Reset the patternTable
                return valueToReturn
            end;
        })
      return fakeJson
    end;
})

local fakeParsedJson = json('example.json')
local value = fakeParsedJson["aa"][2]["gg"]() -- 注意末尾的`()`

print(value)
点赞
用户1847592
用户1847592

如果您想要解码单个 JSON 元素(对象、数组等)而不是解码整个 JSON,则需要具有以下两个功能的 JSON 库:

  • “遍历”功能(无需创建 Lua 对象进行干行解码)
  • 能够将 JSON 作为小部分的序列传递(而不是将整个 JSON 预加载为巨大的 Lua 字符串)。

示例:

如何使用 此模块 部分解码 JSON:

- 这是 data.txt 文件的内容:
- {"aa":["qq",{"k1":23,"gg":"YAY","Fermat_primes":[3, 5, 17, 257, 65537]}]}
- 我们只想将 "Fermat_primes" 数组和 "gg" 字符串作为 Lua 值提取
local json = require('json')

-- 打开文件
local file = assert(io.open('data.txt', 'r'))

-- 定义加载函数,将以 64 字节的块读取文件
local function my_json_loader()
   return file:read(64)
end

local FP, gg
-- 准备部分解码的遍历回调函数
local function my_callback (path, json_type, value)
   path = table.concat(path, '/')
   if path == "aa/2/Fermat_primes" then
      FP = value
      return true  -- 我们要解码这个数组而不是遍历它
   elseif path == "aa/2/gg" then
      gg = value
   end
end

json.traverse(my_json_loader, my_callback)

-- 关闭文件
file:close()

-- 显示结果
print('aa.2.gg = '..gg)
print('aa.2.Fermat_primes:')
for k, v in ipairs(FP) do print(k, v) end

输出:

aa.2.gg = YAY
aa.2.Fermat_primes:
1  3
2  5
3  17
4  257
5  65537
2017-05-06 03:55:08