我有一个程序,该程序读写可执行文件所在目录中的文本文件。要访问该文件,我调用readFile "./file.txt"
当我从可执行文件所在的目录中运行可执行文件时,此方法有效。但是,如果我cd
到另一个目录并运行可执行文件(在我的路径上),Haskell会尝试从终端的工作目录中获取file.txt
。如何使Haskell从可执行文件而不是我的工作目录的位置访问file.txt
。我不想对绝对路径进行硬编码,因为我希望可执行文件具有一定的可移植性。
为什么不将文件存储在正式的应用程序目录中?然后,当前目录是什么都没有关系。 (请参阅getAppUserDataDirectory。)
System.Directory中还有其他有用的目录和方便的文件系统实用程序。从某种意义上讲,它是跨平台的,它知道应该根据您的操作系统将内容放到哪里。
理由:如果将工作数据与可执行文件存储在同一目录中,则只有该目录中具有写许可权的人才能正确运行您的程序。只有超级用户可以在/usr/local/bin
之类的目录中写入,只有管理员可以在C:\Program Files\
的目录中写入。使用用户应用程序目录,任何人都可以运行该应用程序,因为应用程序数据目录是特定于用户的,并且可由他们写,因此这是一个好习惯。
个人而言,我不喜欢应用程序使用配置数据来弄乱我的主要用户区域,但是do想要应用程序,因此建议我的用户区域作为保存我自己的某些内容(getHomeDirectory)的第一个猜测。我建议用户应用程序数据目录,因为您建议了可执行文件的目录,所以听起来像是配置数据。
正确的方法是在file.txt
文件的data-files
字段中列出.cabal
,然后使用getDataFileName
进行检索。有关前缀独立性,请参见cabal documentation。
功能getExecutablePath
执行您所要求的。不幸的是,它仅被添加到刚刚发布的GHC 7.6.1中的System.Environment
中,尚未集成到Haskell平台中。
编辑:具有此功能的较新Haskell平台已发布。
#!/usr/bin/env stack
{- stack
script
--nix
--nix-packages zlib
--resolver lts-14.17
--package turtle
--package protolude
--package directory
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
module Playground where
import Protolude hiding (find)
import Turtle
import System.Directory
import Data.String
main :: IO ()
main = do
let thisScriptAbsFilePath :: String = __FILE__
let thisScriptAbsFilePath' :: Turtle.FilePath = decodeString thisScriptAbsFilePath
let projectRoot :: Turtle.FilePath = directory thisScriptAbsFilePath'
print projectRoot
return ()