Python ArcPy – Preventing Deletion of Files in Output Folder

arcpycopypythonshapefile

I am trying to transfer shapefiles by the number of shapefiles from one folder to another, But I want to keep the already existing files in the output folder. Is there any way? I am using the following script:

import arcpy
import os
from os import listdir
from os.path import isfile, join, basename
arcpy.env.overwriteOutput = True
arcpy.env.workspace =arcpy.GetParameterAsText(0)
outfolder = arcpy.GetParameterAsText(1)
shpNumber=int(arcpy.GetParameterAsText(2))
files = arcpy.ListFeatureClasses("*.shp", "")
if not os.path.exists(outfolder):
    os.makedirs(outfolder)
n=0
nf=[]
for f in files:
    n+=1
    if n<=shpNumber:
        nf.append(f)
    # copy the file
for ff in nf:
    outpath=os.path.join (outfolder,'{ff}.shp'.format(ff=ff))

    arcpy.CopyFeatures_management(ff, outpath)
    arcpy.Delete_management(ff)

Best Answer

You need to check if the file already exists using arcpy.Exists(output_path) and ignore the shapefile:

if arcpy.Exists(output_path):
    continue

Alternatively, you could also use os.path.exists(output_path). There are some other things I would like to point out:

  • In your example, ff would be a file name including extension. Assuming ff is lakes.shp, then '{ff}.shp'.format(ff=ff) would evaluate to lakes.shp.shp.
  • Use arcpy.env.overwriteOutput = False to make sure that files are never overwritten. An error would occur in case there is a bug in the script to prevent accidental overwritten files.
  • Consider using enumerate (as you see in my examples) instead of two loops

Here is an example using arcpy.Exists(output_path) along with the other suggested changes:

import arcpy
import os

arcpy.env.overwriteOutput = False
arcpy.env.workspace = arcpy.GetParameterAsText(0)

output_folder = arcpy.GetParameterAsText(1)
max_number = int(arcpy.GetParameterAsText(2))

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

files = arcpy.ListFeatureClasses("*.shp")

for i, file in enumerate(files, 1):

    if i > max_number:
        break

    output_path = os.path.join(output_folder, file)

    if arcpy.Exists(output_path):
        continue

    arcpy.management.CopyFeatures(file, output_path)

Alternatively, you can also change the file name of the duplicate file:

import arcpy
import os
import time

arcpy.env.overwriteOutput = False
arcpy.env.workspace = arcpy.GetParameterAsText(0)

output_folder = arcpy.GetParameterAsText(1)
max_number = int(arcpy.GetParameterAsText(2))

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

files = arcpy.ListFeatureClasses("*.shp")

for i, file in enumerate(files, 1):

    if i > max_number:
        break

    output_path = os.path.join(output_folder, file)

    if arcpy.Exists(output_path):
        # replace with a better suffix... this is just an example
        timestamp = int(time.time()) 
        output_path = output_path.replace(".shp", f"_{timestamp}.shp")

    arcpy.management.CopyFeatures(file, output_path)

Note: Your solution, and both of my examples, takes the first n files (equals to max_number) from the result list of arcpy.ListFeatureClasses("*.shp").

Unfortunately, the documentation does not specify the order of the list. From all we know this could be completely random.

You could use following code instead of files = arcpy.ListFeatureClasses("*.shp") to ensure that the file order is always the same:

unsorted_files = Path(arcpy.env.workspace).glob("*.shp")

# sorts unsorted_files list by modification time 
files = sorted(unsorted_files, key=os.path.getmtime)

However, files' elements are Path objects. You can access the file name with file.name (assuming file is a Path object). Here an example:

import arcpy
import os
import time

arcpy.env.overwriteOutput = False
arcpy.env.workspace = arcpy.GetParameterAsText(0)

output_folder = arcpy.GetParameterAsText(1)
max_number = int(arcpy.GetParameterAsText(2))

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

unsorted_files = Path(arcpy.env.workspace).glob("*.shp")

# sorts unsorted_files list by modification time 
files = sorted(unsorted_files, key=os.path.getmtime)

for i, file in enumerate(files, 1):

    if i > max_number:
        break

    output_path = os.path.join(output_folder, file.name)
    
    if arcpy.Exists(output_path):
        continue

    arcpy.management.CopyFeatures(file.name, output_path)
Related Question