Download file by url in lua - lua

Lua beginner here. :)
I am trying to load a file by url and somehow I am just too stupid to get all the code samples here on SO to work for me.
How to download a file in Lua, but write to a local file as it works
downloading and storing files from given url to given path in lua
socket = require("socket")
http = require("socket.http")
ltn12 = require("ltn12")
local file = ltn12.sink.file(io.open('test.jpg', 'w'))
http.request {
url = 'http://pbs.twimg.com/media/CCROQ8vUEAEgFke.jpg',
sink = file,
}
my program runs for 20 - 30s and afterwards nothing is saved. There is a created test.jpg but it is empty.
I also tried to add w+b to the io.open() second parameter but did not work.

The following works:
-- retrieve the content of a URL
local http = require("socket.http")
local body, code = http.request("http://pbs.twimg.com/media/CCROQ8vUEAEgFke.jpg")
if not body then error(code) end
-- save the content to a file
local f = assert(io.open('test.jpg', 'wb')) -- open in "binary" mode
f:write(body)
f:close()
The script you have works for me as well; the file may be empty if the URL can't be accessed (the script I posted will return an error in this case).

Related

Lua - Download via http and https (Lua 5.1 embedded)

I’m sure this is not a unique question about Lua 5.1 (especially an embedded instance, where you can’t install modules, your only options is pure Lua files/reference, therefore I can’t install something like luacurl ). I’ve seen this matter referred to in various SO places, and tried them, but I can’t seem to find a fix to make an https file download request work in this particular Lua environment..
To give you an example, the code below aims to download 2 different files, the http call works fine, returning a 200 code, but the https one doesn’t, it doesn’t return anything ?
Both targets can be access directly via the browser..
Please could some highlight what I’m missing in the https call to make it work?
print("--------DOWNLOAD http---------")
local http = require("socket.http")
local body, code = http.request("http://pbs.twimg.com/media/CCROQ8vUEAEgFke.jpg")
print(code)
if not body then error(code) end
local f = assert(io.open('mnt/nas/webtest1.jpg', 'wb')) -- open in "binary" mode
f:write(body)
f:close()
print("--------DOWNLOAD https---------")
local https = require "ssl.https" --luasec
local body, code = https.request("https://u.cubeupload.com/jbcooper/16146313918060.jpg")
print(code)
if not body then error(code) end
local f = assert(io.open('mnt/nas/webtest2.jpg', 'wb')) -- open in "binary" mode
f:write(body)
f:close()
As requested, the following returns nothing at all..
local https = require "ssl.https" --luasec
print(https.request("https://u.cubeupload.com/jbcooper/16146313918060.jpg"))
If it helps, if I run the following it returns 0.4
local https = require("ssl.https")
local httpsVersion = string.sub(https._VERSION,1,3)
print (httpsVersion)

Using io.tmpfile() with shell command, ran via io.popen, in Lua?

I'm using Lua in Scite on Windows, but hopefully this is a general Lua question.
Let's say I want to write a temporary string content to a temporary file in Lua - which I want to be eventually read by another program, - and I tried using io.tmpfile():
mytmpfile = assert( io.tmpfile() )
mytmpfile:write( MYTMPTEXT )
mytmpfile:seek("set", 0) -- back to start
print("mytmpfile" .. mytmpfile .. "<<<")
mytmpfile:close()
I like io.tmpfile() because it is noted in https://www.lua.org/pil/21.3.html :
The tmpfile function returns a handle for a temporary file, open in read/write mode. That file is automatically removed (deleted) when your program ends.
However, when I try to print mytmpfile, I get:
C:\Users\ME/sciteLuaFunctions.lua:956: attempt to concatenate a FILE* value (global 'mytmpfile')
>Lua: error occurred while processing command
I got the explanation for that here Re: path for io.tmpfile() ?:
how do I get the path used to generate the temp file created by io.tmpfile()
You can't. The whole point of tmpfile is to give you a file handle without
giving you the file name to avoid race conditions.
And indeed, on some OSes, the file has no name.
So, it will not be possible for me to use the filename of the tmpfile in a command line that should be ran by the OS, as in:
f = io.popen("python myprog.py " .. mytmpfile)
So my questions are:
Would it be somehow possible to specify this tmpfile file handle as the input argument for the externally ran program/script, say in io.popen - instead of using the (non-existing) tmpfile filename?
If above is not possible, what is the next best option (in terms of not having to maintain it, i.e. not having to remember to delete the file) for opening a temporary file in Lua?
You can get a temp filename with os.tmpname.
local n = os.tmpname()
local f = io.open(n, 'w+b')
f:write(....)
f:close()
os.remove(n)
If your purpose is sending some data to a python script, you can also use 'w' mode in popen.
--lua
local f = io.popen(prog, 'w')
f:write(....)
#python
import sys
data = sys.stdin.readline()

Lua is refusing to read from a file

I typed up my code not expecting it to work first try, and of course it didn't. I kept tweaking it for hours on end, but I kept getting the same result until I made as simple as possible.
local file = io.open("File_Name", "r")
io.output(file)
local test = io.read('*all')
io.close(file)
print(test)
After getting (no return) from this, I've decided to take a break and let someone else answer my question.
The problem with your code is that you're trying to read from whatever is defined as your input file. You only opened a file, but you didn't tell Lua to use it as the input file, so io.read won't read from the opened file, yet.
local file = io.open(filename, "r")
local test = file:read("a")
io.close(file)
print(test)
Alternatively:
local file = io.open(filename, "r")
io.input(file)
local test = io.read("a")
io.close(file)
print(test)
or
local file = io.open(filename, "r")
local test = io.input(file):read("a")
io.close(file)
print(test)
Of course you should check wether opening the file succeeded befor using the file handle.
Depending on your Lua version the read format is either *a or a. I cannot remember if both is ok in all versions. At least that's what the manual says.

How to insert file lines into table in lua

I'm trying to make a Discord bot with lua and its going well so far, but I'm having a couple problems with the IO portion of lua.
I'm trying to read a large list.txt file in lua and inserting each line into a table, but so far all of my attempts didn't work.
Any advice?
Attempt #1 spits out nil:
local open = io.open
local function read_file(path)
local file = open(path, "r") -- r read mode and b binary mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
local fileContent = read_file("list.txt")
local vga_files = {}
table.insert(vga_files, fileContent)
I was not able to replicate your error running your code. Your code is valid, and is likely doing what you asked it to do.
here you tell the read_file function to return nil:
if not file then return nil end
So if the file is not found you will get nil. A good step in debugging would be to add a print in the body of this if statement and see if it is getting entered.
When you call read_file:
local fileContent = read_file("list.txt")
you pass in only a file name, this means lua will look for that where ever the code is being executed, and this location maybe different from what you expect.
I validated your code works by pointing the read at itself, and printing the result.
local open = io.open
local function read_file(path)
local file = open(path, "r") -- r read mode and b binary mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
print(read_file("so_io_read_test.lua"))
Additionally to get the lines you should really used io.lines which creates an iterator that you can use in a for loop.
local vga_files = {}
for line in io.lines("list.txt") do
table.insert(vga_files, line)
end
Or alternatively you can read the file and then split the lines using gmatch.
local contents = read_file("so_io_read_test.lua")
for line in contents:gmatch("([^\n]+)") do
table.insert(vga_files, line)
end

How to copy latest file from a directory using lua

I am trying to copy only latest file from a directory using lua file.
Latest file means : depends on modified time/created time.
How can i do this?
Referring to this question: How can I get last modified timestamp in Lua
You might be able to leverage the io.popen function to execute a shell command to get the name of the file. It seems like there's no builtin function that exposes filesystem metadata or stats. Something like this might work:
local name_handle = io.popen("ls -t1 | head -n 1")
local filename = name_handle:read()
I'm not familiar with Lua, but perhaps this helps. I imagine that once you have the name of the newest file you can use the other IO functions to do the copying.
local function get_last_file_name(directory)
local command = 'dir /a-d /o-d /tw /b "'..directory..'" 2>nul:'
-- /tw for last modified file
-- /tc for last created file
local pipe = io.popen(command)
local file_name = pipe:read()
pipe:close()
return file_name
end
local directory = [[C:\path\to\your\directory\]]
local file_name = get_last_file_name(directory)
if file_name then
print(file_name)
-- read the last file
local file = io.open(directory..file_name)
local content = file:read"*a"
file:close()
-- print content of the last file
print(content)
else
print"Directory is empty"
end

Resources