Как записать / прочитать массив строк в .bin с хорошей производительностью - PullRequest
0 голосов
/ 20 сентября 2018

Запись массива строк в формат .bin выполняется следующим образом

out =  open("string_array.bin","w")
a = ["first string","second string","third string"]
write(out,a)
close(out)

Но когда дело доходит до чтения массива a, все начинает усложняться.

out =  open("string_array.bin","r")
a = read(out)
close(out)
typeof(a) # returns Array{UInt8,1}

Как преобразовать Array {UInt8,1} обратно в исходный массив типа Array {String, 1}?

Он также должен работать, когда массив строк содержит более 300 миллионов элементов, т.е.решение должно быть эффективным.

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Итак, Богумил прав, это немного глупо, но если вы заинтересованы в записи и чтении в двоичные файлы, то здесь есть реализация для чтения и записи Vector{String}, которая работает путем преобразования каждого String в * 1003.*, затем записывает каждый Vector{UInt8} в файл, используя начальные значения Int64 для каждого Vector{UInt8}, чтобы сохранить его длину.Файл также начинается с дополнительного Int64, в котором хранится длина Vector{String}.Затем процедуры чтения используют эту информацию, чтобы вернуть все обратно и преобразовать обратно в Vector{String}:

my_write(fid1::IOStream, x::Vector{UInt8}) = begin ; write(fid1, Int64(length(x))) ; write(fid1, x) ; end
my_write(fid1::IOStream, x::Vector{Vector{UInt8}}) = begin ; write(fid1, Int64(length(x))) ; [ my_write(fid1, y) for y in x ] ; end
my_read(fid1::IOStream, ::Type{Vector{UInt8}})::Vector{UInt8} = begin i = read(fid1, Int64) ; [ read(fid1, UInt8) for a = 1:i ] ; end
my_read(fid1::IOStream, ::Type{Vector{Vector{UInt8}}})::Vector{Vector{UInt8}} = begin i = read(fid1, Int64) ; [ my_read(fid1, Vector{UInt8}) for a = 1:i ] ; end
my_write(myfilepath::String, x::Vector{String}) = open(fid1 -> my_write(fid1, [ Vector{UInt8}(codeunits(y)) for y in x ]), myfilepath, "w")
function my_read(myfilepath::String, ::Type{Vector{String}})::Vector{String}
    x = open(fid1 -> my_read(fid1, Vector{Vector{UInt8}}), myfilepath, "r")
    return [ String(y) for y in x ]
end

Возможно, я включил немного больше информации о типе, чем необходимо, но это может привести кнемного более очевидным для вас.Кроме того, извините, у меня есть плохая привычка делать подобные вещи с однострочником, но вы можете легко распаковать их при необходимости.Вот некоторый тестовый код (просто измените путь к файлу):

myfilepath = "/home/colin/Temp/test_file.bin"
x = ["abc", "de", "f", "", "ghij"]
my_write(myfilepath, x)
my_read(myfilepath, Vector{String})

Обратите внимание, что с небольшим усилием этот код можно сделать более общим, так что он будет работать практически для любого Vector{Vector{T}} до тех пор, покакак T доступно для записи.На самом деле, если вы действительно умны, его можно обобщить на любой Vector{Vector{Vector{...{T}}}}, если вы можете правильно понять рекурсию.

0 голосов
/ 20 сентября 2018

Вот несколько вариантов:

  • сериализация , его ограничение заключается в том, что он предназначен для кратковременного хранения (для этого требуется, чтобы Юлия считывала и записывала файл в одной системеimage).
  • JLD2.jl , предостережение состоит в том, что на момент написания статьи есть некоторые нерешенные проблемы с пакетом на Julia 1.0 (они должны быть исправлены в ближайшее время - вы можете проверить проблемы, еслиони влияют на вас - главное - это обработка missing; учитывая то, что вы пишете, они не должны вас затрагивать)
  • наконец, вы можете использовать устройства чтения / записи, предназначенные для обработки табличных данных, например CSV.jl или Feather.jl , поскольку ваши данные можно рассматривать как таблицу из одного столбца
...