5

If I use os.path.isfile("foo.txt") to check a file named Foo.txt, the function returns True on case-insensitive file systems and Windows. However, it returns False on case-sensitive file systems. Is there a way to force case-insensitive checking for isfile() even on case-sensitive file systems? I know there is a way to force case-sensitivity for this function on Windows, but what about the other way around?

Background

I'm working with DITA content. If you develop DITA content on Windows and deploy your content to a case-sensitive Linux server, you can end up with broken links between topics if your href attributes have characters with a different case than the actual target files. I'm trying to make a script that goes through every href attribute in our DITA source that is not an external link, and updates it to match the case of the actual file. I'm able to obtain the href attribute with the beautifulsoup module, but I'm having a hard time figuring out how to check and verify the actual file name so I can use that string to update the href attribute in my DITA source.

A more heavy-handed approach would be to just go through and convert every href and its target file to lower case, but that can cause different problems if external sites have links to your content and they already have the correct case working.

It's possible that the isfile() function isn't the right tool for this job, but it's a start. I guess I could always just run this script on Windows, but that's not very elegant. It would be best to have the script run properly on most systems.

dwightjl
  • 1,984
  • 2
  • 13
  • 13

2 Answers2

4

You can list all the files in the parent directory and check the filenames case-insensitively:

import os

def getfile_insensitive(path):
    directory, filename = os.path.split(path)
    directory, filename = (directory or '.'), filename.lower()
    for f in os.listdir(directory):
        newpath = os.path.join(directory, f)
        if os.path.isfile(newpath) and f.lower() == filename:
            return newpath

def isfile_insensitive(path):
    return getfile_insensitive(path) is not None

The function isfile_insensitive returns a boolean that specifies if there is a filename in the parent directory that matches the one you are looking for case-insensitively.

The function getfile_insensitive returns the path to the existing filename (with correct case), so you can use that filename safely in your system.

enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
  • Pay attention `directory` can be empty which will cause an error. And you'd better check if whether `f` is file type:) – WKPlus Sep 15 '14 at 08:20
  • @WKPlus Nice catches, check now ;) – enrico.bacis Sep 15 '14 at 08:26
  • This worked perfectly. It's a shame that there isn't a function already created for os.path.isfile() already to take care of this. Thank you for the answer! – dwightjl Sep 19 '14 at 05:18
  • After working on my script some more, I'm wondering if `if os.path.isfile(newpath)` is really necessary. `f` is a variable with a file name that was found with `os.listdir`, so we don't need to do a second check to see if the file exists. Is that correct? The last part of that if statement, `f.lower() == filename` is still necessary of course. – dwightjl Sep 24 '14 at 04:40
-5

In case you want the same result you would obtain in windows (insensitive os), it's simple,

bool_test = os.path.isfile(path.lower()) or os.path.isfile(path.upper())
  • This is wrong because if the file name is "aBc" it would not be detected – robertspierre Jan 12 '21 at 11:14
  • that's why I said "in windows", because internally it treats the paths in insensitive mode. So if you put in your file browser of windows "c:/.../myFile.txt", this is going to be the same than "c:/.../myfile.txt". Just check it to prove it's true. – José Crespo Barrios Aug 02 '21 at 18:07