From 1bbc51725e2a3e0979f63a7c4821523b884c1236 Mon Sep 17 00:00:00 2001 From: Daniil Medvedev <medvdanil@gmail.com> Date: Mon, 20 Jul 2015 12:22:09 +0300 Subject: [PATCH] csv skipping rows and documentation --- csv.documentation | 35 +++++++++++++++++++++++++++++------ src/lua/csv.lua | 13 +++++++++++-- test/app/csv.result | 4 +--- test/app/csv.test.lua | 16 +++++++--------- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/csv.documentation b/csv.documentation index 3c96cd7ab1..912f78b48d 100644 --- a/csv.documentation +++ b/csv.documentation @@ -6,11 +6,14 @@ fio,pathjoin,string csv,load,table none,",comma in field", and ""quote"" -Commas in fields must be in quotes -If there are quotes in a field, it must be double-quotes. +Commas an linebreaks in fields must be in quotes +Quotes in fields is repeated two times quote character. You can set delimiter and quote character: csv.delimiter = ',' csv.quote = '"' +Input/output works through readable/writable objects, for example files or sockets. +Readable object has method read(N), which returns N or less bytes as string. +Writable object has method write(string), which sends string to output. csv.iterate = function(readable[, csv_chunk_size]) --@brief parse csv string by string @@ -29,12 +32,32 @@ Output: csv load table none ,comma in field and "quote" -csv.load = function(readable, csv_chunk_size) +csv.load = function(readable[, skip_lines, csv_chunk_size]) --@brief parse csv and make table +--@param skip_lines is number of lines to skip. --@return table +If csv file has a header, it may be skipped. - -csv.dump = function(t, writable) +csv.dump = function(t[, writable]) --@brief dumps tuple or table as csv +--@param t is table or tuple. Fields may be of any type, but it will be converted to string by method tostring(field). --@param writable must be object with method write(string) like file or socket ---@return there is no writable it returns csv as string \ No newline at end of file +--@return there is no writable it returns csv as string + +Example: + f = require("fio").open("dump.csv", { "O_WRONLY", "O_TRUNC" , "O_CREAT"}, 0x1FF) + multiline_header = {{'csv example'}, {'3 numbers per string:'}} + csv.dump(multiline_header, f) + for i=0,14,3 do + t = {i, i + 1, i + 2} + s = csv.dump(t, f) + end +dump.csv: + csv example + 3 numbers per string: + 0,1,2 + 3,4,5 + 6,7,8 + 9,10,11 + 12,13,14 + diff --git a/src/lua/csv.lua b/src/lua/csv.lua index 58b0783866..8c0183e7f7 100644 --- a/src/lua/csv.lua +++ b/src/lua/csv.lua @@ -69,6 +69,7 @@ local iter = function(csvstate) log.warn("CSV file has errors") break elseif st == ffi.C.CSV_IT_EOF then + ffi.C.csv_destroy(csv) break end st = ffi.C.csv_next(it) @@ -129,12 +130,19 @@ module.iterate = function(readable, csv_chunk_size) end --@brief parse csv and make table +--@param skip_lines is number of lines to skip. --@return table -module.load = function(readable, csv_chunk_size) +module.load = function(readable, skip_lines, csv_chunk_size) + skip_lines = skip_lines or 0 csv_chunk_size = csv_chunk_size or 4096 result = {} + i = 0 for tup in module.iterate(readable, csv_chunk_size) do - table.insert(result, tup) + if i < skip_lines then + i = i + 1 + else + table.insert(result, tup) + end end return result @@ -177,6 +185,7 @@ module.dump = function(t, writable) end writable:write('\n') end + ffi.C.csv_destroy(csv) csv[0].csv_realloc(buf, 0) if writable.returnstring then return writable.returnstring diff --git a/test/app/csv.result b/test/app/csv.result index fb51b0d409..73f58e2b21 100644 --- a/test/app/csv.result +++ b/test/app/csv.result @@ -20,7 +20,6 @@ fio test1: |ok| fio test2: -fio test3: |1| |23| |456| |abcac| |'multiword field 4'| |none| |none| |0| @@ -30,8 +29,7 @@ fio test3: |iflag = bit.bor(iflag| |fio.c.flag[ flag ])| || || || -fio test4: -|1| +fio test3: |23| |456| |abcac| |'multiword field 4'| |none| |none| |0| || || || diff --git a/test/app/csv.test.lua b/test/app/csv.test.lua index fbdb2bd466..3bb6a54bf4 100755 --- a/test/app/csv.test.lua +++ b/test/app/csv.test.lua @@ -29,12 +29,12 @@ print(table2str(csv.load(readable))) print("obj test2:") readable.v = ", ,\n , \n\n" readable.i = 0 -print(table2str(csv.load(readable, 1))) +print(table2str(csv.load(readable, 0, 1))) print("obj test3:") readable.v = ", \r\nkp\"\"v" readable.i = 0 -print(table2str(csv.load(readable, 3))) +print(table2str(csv.load(readable, 0, 3))) tmpdir = fio.tempdir() file1 = fio.pathjoin(tmpdir, 'file.1') @@ -47,7 +47,7 @@ f:write("123 , 5 , 92 , 0, 0\n" .. "1, 12 34, 56, \"quote , \", 66\nok") f:close() f = fio.open(file1, {'O_RDONLY'}) -print(table2str(csv.load(f,10))) +print(table2str(csv.load(f,0,10))) f:close() @@ -62,15 +62,13 @@ f:write("1\n23,456,abcac,\'multiword field 4\'\n" .. ",," ) f:close() - -print("fio test3:") f = fio.open(file2, {'O_RDONLY'}) -print(table2str(csv.load(f, 1))) --symbol by symbol reading +print(table2str(csv.load(f, 0, 1))) --symbol by symbol reading f:close() -print("fio test4:") +print("fio test3:") f = fio.open(file2, {'O_RDONLY'}) -print(table2str(csv.load(f, 7))) --7 symbols per chunk +print(table2str(csv.load(f, 1, 7))) --7 symbols per chunk f:close() @@ -87,7 +85,7 @@ f = require("fio").open(file3, { "O_WRONLY", "O_TRUNC" , "O_CREAT"}, 0x1FF) csv.dump(t, f) f:close() f = fio.open(file3, {'O_RDONLY'}) -t2 = csv.load(f, 5) +t2 = csv.load(f, 0, 5) f:close() print("test roundtrip: ") -- GitLab