Перейти к содержимому
  • 0
Teen_Romance

Запись таблицы в файл и чтение

Вопрос

Мне нужно, чтобы моя программа записывала результат своей работы(таблицу) в отдельный файл. И уже основная программа брала нужную таблицу из этого файла и работала с ней. Как это лучше реализовать? file:write() принимает только string, к тому же он, насколько я понял, переписывает файл всегда заново.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Рекомендуемые сообщения

Файл — последовательность байтов. Кроме них ничего записать в него невозможно. Осмысленность этой последовательности придаёт формат — соглашённость о том, как представлять некий вид информации в байтах и как оттуда его считывать. В данном случае нужно подобрать формат для таблицы и записывать в нём. Так как в вопросе не дана структура этой таблицы, то могу только перечислить инструменты, которыми можно воспользоваться.

  • Либа serialization (OpenOS). Сериализует таблицу и десериализует в таблицу назад.
  • Функции string.pack и string.unpack. Первая по строке-формату пакует данные в строку, вторая их извлекает.
  • Функции string.char и string.byte. Первая создаёт строку с байтом, значение которого равно переданному; вторая возвращает значения байтов, из которых состоит строка.
  • Функции string.gsub, string.gmatch, string.find, string.match. Для поиска по шаблону.

Прошу описать структуру содержимого таблицы, чтобы помочь подобрать правильный инструмент.

 

Кроме того, чтобы файл не переписывать с нуля, а дописывать с конца, нужно использовать io.open(path, "a") (от append).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да, в данном случае проще всего будет использовать serialization. Только вот использование некорректное.

local srl = require("serialization")

local solar = {
  craft = {id = "IC2:blockGenerator", dmg = 3};
  {id = "minecraft:cobblestone", dmg = 0, qty = 11},
  {id="IC2:itemIngot", dmg = 1, qty = 3},
  {id="minecraft:coal", dmg = 0, qty = 3},
  {id="minecraft:redstone", dmg = 0, qty = 6},
  {id="IC2:itemRubber", dmg = 0, qty = 13},
  {id="IC2:itemIngot", dmg = 0, qty = 4},
  {id="minecraft:iron_ingot", dmg = 0, qty = 10}
}

-- Запись
local f = io.open("/tmp/recipe.tbl", "w")
f:write(srl.serialize(solar))
f:close()

-- Чтение
local f = io.open("/tmp/recipe.tbl", "r")
local tbl = srl.unserialize(f:read("*a"))
f:close()

print(tbl.craft.id, tbl.craft.dmg)
print(tbl[2].id, tbl[2].dmg, tbl[2].qty)

Как видно, спокойно можно сериализовать вложенные таблицы и затем к ним обращаться после десериализации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Fingercomp 

Скрытый текст

local solar = {craft ={id = "IC2:blockGenerator",dmg = 3},{id = "minecraft:cobblestone",dmg = 0,qty = 11},
				{id="IC2:itemIngot",dmg = 1,qty = 3},
				{id="minecraft:coal",dmg = 0,qty = 3},
				{id="minecraft:redstone",dmg = 0,qty = 6},
				{id="IC2:itemRubber",dmg = 0,qty = 13},
				{id="IC2:itemIngot",dmg = 0,qty = 4},
				{id="minecraft:iron_ingot",dmg = 0,qty = 10}}

В таблице может быть больше или меньше таблиц, в зависимости от создаваемого предмета. 

У меня вроде получилось записать таблицу в файл:

Скрытый текст

V2VYWlnhdN7QVm.png

Но теперь не знаю как сделать ее обратно таблицей при считывании из файла.

+

Сразу возникла проблема. У меня в файле будет допустим 20+ таблиц. И когда я захочу обратится к конкретной, нужной мне таблице, как это сделать? В file:write() нужно указывать количество байт для считывания. Как мне узнать в каком промежутке байт находится нужная мне таблица?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Если объемы таблиц не сильно большие, то рекомендую вообще использовать файл как файл подгрузки таблицы. Тоесть при старте программы прогружать таблицу в оперативку и там с ней работать. Постоянно обращаться на диск за таблицей не стоит, так как во первых это довольно долго, а если таблица разрастется до хороших таких объемов то еще и невыгодно будет по памяти.

Еще вариант - придумать собственный вариант хранения данных в файле. Я например часто использую хранение как в csv таблицах, тоесть данные пишу все через; . Но это уже каждому свое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Fingercomp сказал:

local tbl = srl.unserialize(f:read("*a"))

Что такое "*a" и как оно рассчитывается? И подскажите пожалуйста, как мне из 20 таблиц определить нужную мне? Я писал выше, что насколько я понял, мне нужно знать промежуток байтов в которых записана таблица? Или как?

Изменено пользователем Teen_Romance

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Asior Я загружаю таблицу 1 раз за 1 цикл программы и работаю с ней. Насколько я понял, ваш метод подходит если мне нужно несколько разных таблиц в 1 программе? Или в моем случае это тоже будет выгодно? Если не сложно, можно какой то простенький пример вашего метода? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Teen_Romance сказал:

Что такое "*a" и как оно рассчитывается?

Это параметр, который говорит прочитать всё из файла.

1 час назад, Teen_Romance сказал:

И подскажите пожалуйста, как мне из 20 таблиц определить нужную мне? Я писал выше, что насколько я понял, мне нужно знать промежуток байтов в которых записана таблица? Или как?

Нет, зачем? Достаточно поместить все таблицы в одну и её уже сериализовать. А искать можно и линейным поиском.

local itemToCraft = {id = "IC2:blockGenerator", dmg = 3}
local tbls = srl.unserialize(f:read("*a"))
local recipe

for _, tbl in pairs(tbls) do
  if (tbl.craft.id == itemToCraft.id and
      tbl.craft.dmg == itemToCraft.dmg) then
    recipe = tbl
    break
  end
end

assert(recipe, "recipe not found")

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Fingercomp проблема в том, что каждый раз когда я буду запускать программу, я буду записывать только 1 таблицу в файл. Как мне все их поместить в 1 таблицу в файл в который я записываю ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Teen_Romance сказал:

@Fingercomp проблема в том, что каждый раз когда я буду запускать программу, я буду записывать только 1 таблицу в файл. Как мне все их поместить в 1 таблицу в файл в который я записываю ?

Прочесть весь файл, десериализовать всю таблицу, добавить новое значение, сериализовать обратно и перезаписать.

local srl = require("serialization")

local f = io.open(path, "r")
local tbls = srl.deserialize(f:read("*a"))
f:close()

table.insert(tbls, {...})

-- если внезапно вылетит ошибка здесь, файл не будет потёрт
local serialized = srl.serialize(tbls)

local f = io.open(path, "w")
f:write(serialized)
f:close()

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 часа назад, Teen_Romance сказал:

Если не сложно, можно какой то простенький пример вашего метода? 

local alf = {'a','b','c','d','e','f'}
local alf2 = {}

local function saveFile(pos1, pos2, pos3) --запись в файл
  local file = io.open('/home/test.csv', 'a')
  print(tostring(pos1)..';'..pos2..';'..pos3..';')
  file:write(pos1..';'..pos2..';'..pos3..';\n')
  file:close()
end

local function curPhrase(line) --вырезка фразы с разделителем
  local tbl = {}
  for part in line:gmatch("[^;]+") do
    table.insert(tbl, part) 
  end
  return tbl
end

local function readFile() --подкгрузка базы руды
  f = io.open('/home/test.csv')
  local line = f:read()
  while line ~= nil do
    if line ~= '/n' then
      local vr = curPhrase(line)
      alf2[#alf2+1] = {vr[1], tonumber(vr[2]), tonumber(vr[3])}
    end
    line = f:read()
  end
  f:close()
end

print('Генерация таблицы')
for i=1, 10 do
  saveFile(alf[math.random(#alf)], math.random(10), math.random(20))
end
print('Загрузка таблицы в ОЗУ')
readFile()
for i=1,#alf2 do
  print(alf2[i][1],alf2[i][2],alf2[i][3])
end
Скрытый текст

R6s7yr7.png

 

OZst4yI.png

Плюсы данного сохранения, данные для сохранения выбираешь сам.

Ну а минусы, приходится потом вручную настраивать типы считываемых данных.

Изменено пользователем Asior

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
51 минуту назад, NEO сказал:

@Fingercomp, как же размер озу?

От 20 таблиц даже планка T1 не закончится. Рациональный вариант надо подбирать исходя из требуемых задач. Например, самый простой в использовании и поддержке вариант — это сериализация. Самый эффективный по памяти и размеру БД — свой формат через string.pack. И т. д.

 

Вообще, это уже в оффтопик уходит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...