سؤال

I have a program that reads and writes a text file that exists in the same directory as the executable. To access that file, I call readFile "./file.txt"

This works when I run the executable from within the directory where it lives. However if i cd to another directory and run the executable (it's on my path), Haskell tries to get the file.txt from the working directory in my terminal. How do I make Haskell access the file.txt from the location of the executable and not my working directory. I don't want to hardcode an absolute path because I want the executable to be somewhat portable.

هل كانت مفيدة؟

المحلول

Why not store your file in the official Application Directory? Then it won't matter what the current directory is. (See getAppUserDataDirectory.)

There are other useful directories and handy filesystem utilities in System.Directory. It's cross-platform in the sense that it knows where stuff ought to go according to your OS.

Reasoning:
If you store working data in the same directory as the executable, only someone with write permissions in that directory can correctly run your program. Only a superuser can write in directories like /usr/local/bin and only an administrator can write in C:\Program Files\. Using the User Application Directory, anyone can run the app, because the application data directory is specific to the user and writable by them, so that's why this is good practice.

Personally I don't like applications to clutter up my main user area with config data, but do want applications so suggest my user area as a first guess to save some of my own content (getHomeDirectory). I suggested the user application data directory because you suggested the executable's directory, so it sounded like config data.

نصائح أخرى

The correct way to do this is to list file.txt in the data-files field of your .cabal file and use getDataFileName to retrieve it. See the cabal documentation for prefix independence.

The function getExecutablePath does what you ask. Unfortunately it was only added to System.Environment in the just released GHC 7.6.1, which hasn't been incorporated into a Haskell Platform yet.

EDIT: Newer Haskell Platforms with this function have since been released.

#!/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 ()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top