最近这段时间基本上已经将大部分数据下载的 python 代码迁移到了 julia. 由于数据下载实际速度主要取决于网速,所以 julia 的速度优势并没有太大的体现,主要原因是由于个人希望将整个日常使用程序尽量用同一语言实现,从而最大化集合效应.

由于所使用的数据源包括多个 ftp, http[s] 服务器, 主要的下载方式是 julia 调用外部命令 curl 的方式. 同时某些数据可能存在于多个源中,所以除了获取数据文件的名称,还需要文件大小,以及修改的时间戳以确定同名文件中哪个需要下载. 由于数据文件的数目可以达到每天近万个,所以一般直接 list 获取大致的时间戳 (即 ls -l 的时间戳,近期得是包括时分信息, 较为久远的即为只有日期), 之后比较文件大小只获取相同文件名中体积最大的几个文件的精确时间戳.

这里面由于本地可能也有一些历史文件,需要加入比较, 最开始为了统一时间戳的处理, 我是直接通过 julia 调用 ls -l 来获取相应文件夹的文件信息. 当然最好的方法是直接 glob 之后 mtimefilesize 获取最精确的信息, 这也是目前我的程序所使用的. 不过在修改为这样的方式之前, 还顺带了解了一个关于 julia 和系统交互的方式, 所以这里记录一下.

前面提到如果是远程 ftp, curl 可以list获取目录下文件信息, 这里的时间信息一般是世界时. 如果是浏览器打开,可以发现大部分文件修改时间都是某天然后 8:00. 实际是只获得了日期,而时间默认为 UT 00:00,然后转到本机时区 (CST +8) 就成了 8:00. 而 curl 获取的文件时间并不会时区转化, 当然这是较好的选择. 但是这和本地 ls -l 的结果就不符了. 虽然计算机系统内部都是 unixtime 不存在时区区别, 但是 ls -l 却是要转换的.

经过一番 搜索 发现 ls -l 的输出是一个系统环境变量的影响, 即 TZ. 通过运行 TZ=utc ls -l 就可以获取相应的UTC时间. 不过在 julia 中如果直接 run 以上语句就会报错:

ERROR: IOError: could not spawn `TZ=utc ls -l`: no such file or directory (ENOENT)
Stacktrace:
 [1] _spawn_primitive(::String, ::Cmd, ::Array{Any,1}) at ./process.jl:99
 [2] #550 at ./process.jl:112 [inlined]
 [3] setup_stdios(::Base.var"#550#551"{Cmd}, ::Array{Any,1}) at ./process.jl:196
 [4] _spawn at ./process.jl:111 [inlined]
 [5] run(::Cmd; wait::Bool) at ./process.jl:439
 [6] run(::Cmd) at ./process.jl:438
 [7] top-level scope at REPL[2]:1

这里面就涉及 julia 对内部调用系统命令的安全考虑了. 在经过一些尝试之后, 找到了一个算是解决方法的方法.

实现的核心是 julia 如何与环境变量交互. 前面提到 ls 的行为受到 TZ 环境变量的影响, 那么如何让 julia 意识到这个环境变量? 作为一门成熟的编程语言, julia 启动后一个专门的 Base.EnvDict 类型的变量 ENV 保存着启动时所有的环境变量. 而且这个变量是支持所有字典类的增删查改的操作的, 当然这个操作并不会反应到 julia 程序之外, 所以可以放心修改. 在思考了一些可能情况之后,在程序中加入 如下片段,就可以获得相应的效果,并在获取想要的信息后恢复到原来的情况:

hasTZ=false
TZ_before=""
if haskey(ENV,"TZ") 
	hasTZ=true
	TZ_before=ENV["TZ"]
end
ENV["TZ"]="utc"
files = split(read(`ls -l $dir`, String), '\n')

if hasTZ ENV["TZ"]=TZ_before
else delete!(ENV,"TZ") end

具体过程就是先判断有没有要修改的键,然后保存原始状态, 之后修改 TZ 获取想要的 ls -l 信息, 最后恢复到原来的 ENV.

可以看出 julia 作为一门成熟的编程语言,确实考虑了很多, 在我个人的学习使用中发现了很多这种 果然又有相应的操作 时刻. 希望 julia 越来越流行~

发表评论

电子邮件地址不会被公开。 必填项已用*标注