Read Text File In Current Directory

Discussion of Common Lisp
Post Reply
jhud
Posts: 3
Joined: Wed Dec 13, 2017 5:34 pm

Read Text File In Current Directory

Post by jhud » Wed Dec 13, 2017 6:05 pm

When reading from a text file in the same directory as the code doing the reading, most languages allow the user to simply put the name and extension of the file and assume the rest of the path is the same as that of the code. Lisp doesn't seem to have this feature, and half an hour of searching has not yielded a working alternative. As an example, the following code, whose intended function is to simply print the first line of a referenced text file, has the path C:/Users/Owner/Documents/Lisp/Read_Demo/reader.lisp and references a text file with the path C:/Users/Owner/Documents/Lisp/Read_Demo/input.txt:

Code: Select all

(let ((in (open "input.txt")))
  (read-line in))
Upon execution, the following error occurs:

Code: Select all

The file #P"C:/ProgramData/Microsoft/Windows/Start Menu/Programs/LispWorks 6.1 Personal/input.txt" does not exist.
Clearly, Lisp assumes the file I want is in that "LispWorks..." folder, rather than the current directory. Is there any way to achieve the desired functionality without hard-coding the entire path of the file I wish to read from and while still using the OPEN function?

pjstirling
Posts: 166
Joined: Sun Nov 28, 2010 4:21 pm

Re: Read Text File In Current Directory

Post by pjstirling » Sat Dec 16, 2017 1:53 am

All three major operating systems have a notion of the current directory, and this is where programs will attempt to open files that don't have an absolute prefix (e.g. C: on windows).

Lispworks is clearly (from your error message) using its own directory as its initial current directory.

You have two options:
  • You can change the current directory for your lisp process, or
  • You can provide an absolute path
I assume that you use the Start menu to launch Lispworks, this is why Windows picks the directory that it does, if you had opened a terminal (cmd.exe) and changed to your source directory and then launched Lispworks by its path then the initial current directory would be what you want. Alternatively Lispworks will have a function that you can call to change the current directory (sbcl has this as the function SB-POSIX:CHDIR). Common-Lisp doesn't provide a function to change the current directory because it's sooooooooooo old that it targeted some ancient operating systems that had no hierarchical filesystems, and as a result each implementation now has to provide its own. At this point some might point at MERGE-PATHNAMES, but they can go whistle, pathnames are a portability fuster-cluck (again, because long-dead OS had major weirdness, it was under-specified)

If you use ASDF for loading your systems, then having an absolute path is actually very easy:

Code: Select all

(asdf:system-relative-pathname "system" "filename")
You can also use *COMPILE-FILE-PATHNAME*, but I found that didn't work very well with C-c C-c in slime, so I always use the ASDF method.

jhud
Posts: 3
Joined: Wed Dec 13, 2017 5:34 pm

Re: Read Text File In Current Directory

Post by jhud » Sat Dec 16, 2017 2:40 pm

Thanks for the response! I'm asking about this for a school assignment, and in class it's a bit frowned upon to import external... uh... modules/libraries/whatever-they're-called-in-Lisp. Also the whole "system" thing is confusing me and seems to be more complicated than it's worth looking into. (Also, I may be wrong, but it seems like using this limits where you are allowed to put your files and still makes you explicitly tell Lisp where they are, both of which defeat its purpose.) The functionality I reference in this thread is not required for the assignment, but I just thought (coming from other languages which supported the functionality) that it had to exist in Lisp and surely the language didn't force its users to hard-code entire paths which may change. (Or, as it appears, put in serious effort trying to figure out how to manipulate facilities outside of pure CL.) The gist of your answer to me seems to be 'Lisp evolved weirdly and as a result this functionality just isn't a thing.' I'll just stick with hard-coding for now, but thanks for the help!

aidlt
Posts: 19
Joined: Thu May 16, 2013 1:42 pm

Re: Read Text File In Current Directory

Post by aidlt » Tue Dec 19, 2017 6:35 pm

In the Lisp universe, the counterpart of the current working directory is the *default-pathname-defaults* variable. It's similar, but better.

When Lisp starts, typically it bounds *default-pathname-defaults* to the current directory.

Suppose I've got directories ~/test/a & ~/test/b & a file ~/test/a/input.txt. If I change my directory to ~/test/a & start SBCL there, it can find input.txt using only the relative path. Now, if I change my directory to ~/test/b & start SBCL there, (open "input.txt") raises an error. Checking the value of *default-pathname-defaults*, I see that it is #P"/home/me/test/b/", as expected. (The leading #P means it's a pathname & not a string.) Now I change the value of this variable:

Code: Select all

(setf *default-pathname-defaults* #p"/home/me/test/a/")
& try

Code: Select all

(open "input.txt")
once again. This time it works.

I'm not sure which languages favour the source directory over the working directory. Let's check Python. I create the file ~/test/a/foo.py containing

Code: Select all

with open('input.txt', 'r') as f:
    print(f.readline())
Then, still being in the directory ~/test/a/, I call

Code: Select all

python foo.py
& it finds the file input.txt all right. Now I change my working directory to ~/test/b & call

Code: Select all

python ../a/foo.py
from there. This time the file input.txt is not found. Thus, on the surface SBCL behaves exactly as Python.

If for some reason you can't control the directory you start Lisp in, I'd suggest you set *default-pathname-defaults* at the beginning of your session like this

Code: Select all

(setf *default-pathname-defaults* #p"C:/Users/Owner/Documents/Lisp/Read_Demo/")
(mind the #p & the trailing slash). Then you should be able to e. g.

Code: Select all

(load "reader.lisp")
& read input.txt using relative pathnames. If you care to explain your setup, maybe we could think of a better solution.

As a side note, you shouldn't use the OPEN function, but rather the WITH-OPEN-FILE macro, which takes care of closing the file no matter what.

As another side note, nowadays the code is not organised as scattered .lisp files, but comes neatly packed in ASDF systems. So eventually you'll have to look into them if you want to write something more substantial than "hello world".

jhud
Posts: 3
Joined: Wed Dec 13, 2017 5:34 pm

Re: Read Text File In Current Directory

Post by jhud » Mon Dec 25, 2017 9:27 am

Thanks for the thorough reply!
About my setup... I work with Lisp both on my school's Macs using Clozure CL and on my PC at home using LispWorks, and I keep my files on a flash drive so I can go between the two.
I've tried using *default-pathname-defaults* before, but it always comes up as an empty string because it seems I'm not able to practically "control the directory I start Lisp in." At home, I don't have the option of right-click + Open With for Lisp files, so I just have to open LispWorks from the desktop and open the file from within the program. I believe it has been suggested in this forum that I open the Lisp file with the command prompt in some way, but I don't know how to do that and it seems more cumbersome than the problem it's solving. At school, I can right-click on a Lisp file and open with Clozure CL, but *default-pathname-defaults* is still empty. I don't have admin privileges at school, of course, so command prompt isn't really an option.
It seems like no matter what you do, some action has to be taken on the user's end which explicitly defines the directory you're working with. I remember when I took classes that used Java and Python, we'd have programs that referenced files like "input.txt" (without the path because they are in the same directory as the code accessing them), and even when we'd turn assignments in (the code and input are now in a different directory on the teacher's computer, but each are still in a folder together) the teacher would still be able to run the program. This doesn't seem like a thing you can do in Lisp with any of the solutions previously mentioned. If I'm wrong, I'd love to know.
(Thanks for the tip about WITH-OPEN-FILE by the way. Also this is just an intro course, so I probably won't be using ASDF systems, but thanks for the heads up.)

David Mullen
Posts: 78
Joined: Mon Dec 01, 2014 12:29 pm
Contact:

Re: Read Text File In Current Directory

Post by David Mullen » Tue Dec 26, 2017 2:20 pm

With Clozure CL, I can set *default-pathname-defaults* (or the working directory, via CCL:CURRENT-DIRECTORY) in the ccl-init.lisp file, which is in my home directory:

Code: Select all

? (probe-file "~/ccl-init.lisp")
#P"C:/Users/David Mullen/ccl-init.lisp"

aidlt
Posts: 19
Joined: Thu May 16, 2013 1:42 pm

Re: Read Text File In Current Directory

Post by aidlt » Tue Jan 02, 2018 11:20 am

jhud wrote:I've tried using *default-pathname-defaults* before, but it always comes up as an empty string because it seems I'm not able to practically "control the directory I start Lisp in."
It should be a pathname, actually, rather than a string. However, it's weird that it's empty. How do you access it?

Typically, in a running Lisp you've got a REPL. The thing you can type expressions in & see the answers. In LW it's built into the IDE, I think. Whatever Lisp IDE must have a REPL. It's in REPL that you can see the value of *default-pathname-defaults* as well as change it using setf.
jhud wrote:At home, I don't have the option of right-click + Open With for Lisp files, so I just have to open LispWorks from the desktop and open the file from within the program.
Launching LispWorks & subsequently opening a file from there isn't the same thing as running a Python script. How do you run Python at home and at school? Using a context menu?
jhud wrote: I don't have admin privileges at school, of course, so command prompt isn't really an option.
Come on, command line is cool. :) It has nothing to do with your priviledges.
jhud wrote:It seems like no matter what you do, some action has to be taken on the user's end which explicitly defines the directory you're working with.
Yes, in the same way as with Python. Right-clicking a file is an example of such an action. Running something in a terminal with a given working directory is another option.

BTW, are there any problems when you open the file in CCL through the context menu at school?

Your problems are understandable. The fact is that CL hasn't been designed as an educational tool neither with newbie friendliness in mind. Don't be discouraged.

Post Reply