Python long filename support broken in Windows - python

I write Python script to copy files; unfortunately it keeps failing because filename is too long(>256). Is there anyway to deal with that problem?
I'm using Python 2.5.4 and Windows XP.
Cheers,

Use paths beginning with the string \\?\.

In order to use the \\?\ prefix (as already proposed), you also need to make sure you use Unicode strings as filenames, not regular (byte) strings.

For anyone else looking for solution here:
You need to add prefix \\?\ as already stated, and make sure string is unicode;
If you are using shutil, especially something like shutil.rmtree with onerror method, you'll need to modify it too to add prefix as it gets stripped somewhere on the way.
You'll have to write something like:
def remove_dir(directory):
long_directory = '\\\\?\\' + directory
shutil.rmtree(long_directory, onerror=remove_readonly)
def remove_readonly(func, path, excinfo):
long_path = path
if os.sep == '\\' and '\\\\?\\' not in long_path:
long_path = '\\\\?\\' + long_path
os.chmod(long_path, stat.S_IWRITE)
func(long_path)
This is an example for Python 3.x so all strings are unicode.

This answer by uDev suggests to add
# Fix long path access:
import ntpath
ntpath.realpath = ntpath.abspath
It seems to work for me.

Another thing that works for me is to change directory into the place to which I want to copy:
import os
import shutil
def copyfile_long_path(src, dst):
src_abs = os.path.abspath(src)
dst_abs = os.path.abspath(dst)
cwd = os.getcwd()
os.chdir(os.path.dirname(dst))
shutil.copyfile(src_abs, os.path.filename(dst))
os.chdir(cwd)
if not os.path.isfile(dst_abs):
raise Exception("copying file failed")

Related

Altering Windows file paths so that they use '/' instead of '\' [duplicate]

I am working in python and I need to convert this:
C:\folderA\folderB to C:/folderA/folderB
I have three approaches:
dir = s.replace('\\','/')
dir = os.path.normpath(s)
dir = os.path.normcase(s)
In each scenario the output has been
C:folderAfolderB
I'm not sure what I am doing wrong, any suggestions?
I recently found this and thought worth sharing:
import os
path = "C:\\temp\myFolder\example\\"
newPath = path.replace(os.sep, '/')
print(newPath) # -> C:/temp/myFolder/example/
Your specific problem is the order and escaping of your replace arguments, should be
s.replace('\\', '/')
Then there's:
posixpath.join(*s.split('\\'))
Which on a *nix platform is equivalent to:
os.path.join(*s.split('\\'))
But don't rely on that on Windows because it will prefer the platform-specific separator. Also:
Note that on Windows, since there is a current directory for each
drive, os.path.join("c:", "foo") represents a path relative to the
current directory on drive C: (c:foo), not c:\foo.
Try
path = '/'.join(path.split('\\'))
Path names are formatted differently in Windows. the solution is simple, suppose you have a path string like this:
data_file = "/Users/username/Downloads/PMLSdata/series.csv"
simply you have to change it to this: (adding r front of the path)
data_file = r"/Users/username/Downloads/PMLSdata/series.csv"
The modifier r before the string tells Python that this is a raw string. In raw strings, the backslash is interpreted literally, not as an escape character.
Sorry for being late to the party, but I wonder no one has suggested the pathlib-library.
pathlib is a module for "Object-oriented filesystem paths"
To convert from windows-style (backslash)-paths to forward-slashes (as typically for Posix-Paths) you can do so in a very verbose (AND platform-independant) fashion with pathlib:
import pathlib
pathlib.PureWindowsPath(r"C:\folderA\folderB").as_posix()
>>> 'C:/folderA/folderB'
Be aware that the example uses the string-literal "r" (to avoid having "\" as escape-char)
In other cases the path should be quoted properly (with double backslashes) "C:\\folderA\\folderB"
To define the path's variable you have to add r initially, then add the replace statement .replace('\\', '/') at the end.
for example:
In>> path2 = r'C:\Users\User\Documents\Project\Em2Lph\'.replace('\\', '/')
In>> path2
Out>> 'C:/Users/User/Documents/Project/Em2Lph/'
This solution requires no additional libraries
How about :
import ntpath
import posixpath
.
.
.
dir = posixpath.join(*ntpath.split(s))
.
.
This can work also:
def slash_changer(directory):
if "\\" in directory:
return directory.replace(os.sep, '/')
else:
return directory
print(slash_changer(os.getcwd()))
this is the perfect solution put the letter 'r' before the string that you want to convert to avoid all special characters likes '\t' and '\f'...
like the example below:
str= r"\test\hhd"
print("windows path:",str.replace("\\","\\\\"))
print("Linux path:",str.replace("\\","/"))
result:
windows path: \\test\\hhd
Linux path: /test/hhd

Backslash vs forwardslash when moving files in python

To move some files i am using this code:
import glob
import os
import shutil
list_of_files = glob.glob('C:/Users/user/staff/*')
latest_file = max(list_of_files, key=os.path.getctime)
print(latest_file)
filename= os.path.basename(latest_file)
shutil.move(latest_file, f"C:\\Users\\user\\test folder\\{filename}"
The code works and the file has moved but i would like to know if this actually matters:
The file which was moved is this:
C:/Users/user/staff\Aug-2021.csv
Notice the slash is now backward instead of forward. Does the orientation of slash matter or would matter in future when my code becomes more complicated(for best practices) or is this how it is suppose to work?
Both will work, but mixing slash and backslash is at least ugly. If you want to do something os independent, you can use os.sep to get the seperation character of your os.
>>> import os
>>> os.sep
'\\'
With this you could do something like
>>> os.sep.join(['foo','bar'])
'foo\\bar'
But you can also use os.path.join to build the path and let python handle that problem for you.
>>> import os
>>> os.path.join(os.getcwd(),'foo.bar')
'C:\\Users\\Me\\foo.bar'
Both foward or backslash are perfectly valid path separators. Also, it is a good practice to include 'r' before a path string:
r'C:\Users\user\staff\Aug-2021.csv'
The means your string will be treated as a raw string. You can see string literals reference here
Both works same but try to use \ slash to avoid 0.1 chance of error.
And I also get error of encoding so add r before the path eg : r"C:\\Users\\user\\test folder\\{filename}" .
Hope that answers the question.

How to convert back-slashes to forward-slashes?

I am working in python and I need to convert this:
C:\folderA\folderB to C:/folderA/folderB
I have three approaches:
dir = s.replace('\\','/')
dir = os.path.normpath(s)
dir = os.path.normcase(s)
In each scenario the output has been
C:folderAfolderB
I'm not sure what I am doing wrong, any suggestions?
I recently found this and thought worth sharing:
import os
path = "C:\\temp\myFolder\example\\"
newPath = path.replace(os.sep, '/')
print(newPath) # -> C:/temp/myFolder/example/
Your specific problem is the order and escaping of your replace arguments, should be
s.replace('\\', '/')
Then there's:
posixpath.join(*s.split('\\'))
Which on a *nix platform is equivalent to:
os.path.join(*s.split('\\'))
But don't rely on that on Windows because it will prefer the platform-specific separator. Also:
Note that on Windows, since there is a current directory for each
drive, os.path.join("c:", "foo") represents a path relative to the
current directory on drive C: (c:foo), not c:\foo.
Try
path = '/'.join(path.split('\\'))
Path names are formatted differently in Windows. the solution is simple, suppose you have a path string like this:
data_file = "/Users/username/Downloads/PMLSdata/series.csv"
simply you have to change it to this: (adding r front of the path)
data_file = r"/Users/username/Downloads/PMLSdata/series.csv"
The modifier r before the string tells Python that this is a raw string. In raw strings, the backslash is interpreted literally, not as an escape character.
Sorry for being late to the party, but I wonder no one has suggested the pathlib-library.
pathlib is a module for "Object-oriented filesystem paths"
To convert from windows-style (backslash)-paths to forward-slashes (as typically for Posix-Paths) you can do so in a very verbose (AND platform-independant) fashion with pathlib:
import pathlib
pathlib.PureWindowsPath(r"C:\folderA\folderB").as_posix()
>>> 'C:/folderA/folderB'
Be aware that the example uses the string-literal "r" (to avoid having "\" as escape-char)
In other cases the path should be quoted properly (with double backslashes) "C:\\folderA\\folderB"
To define the path's variable you have to add r initially, then add the replace statement .replace('\\', '/') at the end.
for example:
In>> path2 = r'C:\Users\User\Documents\Project\Em2Lph\'.replace('\\', '/')
In>> path2
Out>> 'C:/Users/User/Documents/Project/Em2Lph/'
This solution requires no additional libraries
How about :
import ntpath
import posixpath
.
.
.
dir = posixpath.join(*ntpath.split(s))
.
.
This can work also:
def slash_changer(directory):
if "\\" in directory:
return directory.replace(os.sep, '/')
else:
return directory
print(slash_changer(os.getcwd()))
this is the perfect solution put the letter 'r' before the string that you want to convert to avoid all special characters likes '\t' and '\f'...
like the example below:
str= r"\test\hhd"
print("windows path:",str.replace("\\","\\\\"))
print("Linux path:",str.replace("\\","/"))
result:
windows path: \\test\\hhd
Linux path: /test/hhd

Python. Error when trying to create a new directory using the filename if it has a special character in it

My script searches the directory that it's in and will create new directories using the file names that it has found and moves them to that directory: John-doe-taxes.hrb -> John-doe/John-does-taxes.hrb. It works fine until it runs into an umlaut character then it will create the directory and return an "Error 2" saying that it cannot find the file. I'm fairly new to programming and the answers i've found have been to add a
coding: utf-8
line to the file which doesn't work I believe because i'm not using umlauts in my code i'm dealing with umlaut files. One thing I was curious about, does this problem just occur with umlauts or other special characters as well? This is the code i'm using, I appreciate any advice provided.
import os
import re
from os.path import dirname, abspath, join
dir = dirname(abspath(__file__))
(root, dirs, files) = os.walk(dir).next()
p = re.compile('(.*)-taxes-')
count = 0
for file in files:
match = p.search(file)
if match:
count = count + 1
print("Files processed: " + str(count))
dir_name = match.group(1)
full_dir = join(dir, dir_name)
if not os.access(full_dir, os.F_OK):
os.mkdir(full_dir)
os.rename(join(dir, file), join(full_dir, file))
raw_input()
I think your problem is passing strs to os.rename that aren't in the system encoding. As long as the filenames only use ascii characters this will work, however outside that range you're likely to run into problems.
The best solution is probably to work in unicode. The filesystem functions should return unicode strings if you give them unicode arguments. open should work fine on windows with unicode filenames.
If you do:
dir = dirname(abspath(unicode(__file__)))
Then you should be working with unicode strings the whole way.
One thing to consider would be to use Python 3. It has native support for unicode as the default. I'm not sure if you would have to do anything to change anything in the above code for it to work, but there is a python script in the examples to transition Python2 code to Python3.
Sorry I can't help you with Python2, I had a similar problem and just transitioned my project to Python3--ended up just being a bit easier for me!

Python os.getcwd() returns with tilde in the path. e.g. C:\MYFOLD~1\test

How can I get python to return the full pathname of C:\myfolderisafolder\test?
E:\dev>cd VARESE~1
E:\dev\VARESE~1>python
>>> import os
>>> os.getcwd()
'E:\\dev\\VARESE~1'
>>> exit()
E:\dev\VARESE~1>cd ..
E:\dev>cd VAResearchDemo
E:\dev\VAResearchDemo>python
>>> import os
>>> os.getcwd()
'E:\\dev\\VAResearchDemo'
>>> exit()
As you can see, if I run python in VARESE~1 directory, os.getcwd() returns short path. If I run python in same directory but with long path, it returns long path.
So, you should try to run python in C:\myfolderisafolder\test (check link's properties or how you run it).
But if you need to convert a short path to a long path, you have to call win32's GetLongPathName function
Perhaps this would help:
fullpath = os.path.expanduser('~/my/path')
Try to use os.path.realpath, os.path.normpath.
You could just split the string with .split() at the tilde and then rejoin the full filepath with the .join() methods.

Categories

Resources