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

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

Вопрос

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

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


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

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

  • 1

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

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

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

 

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

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


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

@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() нужно указывать количество байт для считывания. Как мне узнать в каком промежутке байт находится нужная мне таблица?

 

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


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

Да, в данном случае проще всего будет использовать 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)

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

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


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

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

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

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


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

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

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

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

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


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

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

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0
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")

 

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


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

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

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0
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()

 

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0
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

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


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

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

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

 

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

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


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

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

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

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

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

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

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

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

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


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