How to convert feature classes to shapefiles


Summary The article shows how to use the IFeatureDataConverter interface to create a shapefile based on an existing geodatabase feature class.

Development licensing Deployment licensing
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo
Engine Developer Kit Engine Runtime

Additional Requirements
  • The IFeatureDataConverter interface only loads simple feature data (point, line, polygons).
  • If working in ArcSDE, an ArcEditor or greater license will be needed for ArcGIS Desktop, and the Geodatabase Update extension will be required for ArcGIS Engine.

To use the code in this article, the following namespaces must be referenced via the using (C#) or Imports (VB.NET) statements. It is also necessary to add the corresponding references to the project in order to gain access to these APIs.
 
The following assembly does not require a using or imports statement, but must be referenced by the project:

In this topic


How to convert feature classes to shapefiles

This article shows how to create a new shapefile based on a feature class from a geodatabase.  The new shapefile should not be created beforehand; the following code will do that (and will fail if the feature class already exists).
 
The IFeatureDataConverter interface was designed to work with the ArcCatalog IGxDialog mini-browser. As this example does not use an ArcCatalog IGxDialog mini-browser, to convert a shapefile to a geodatabase feature class, the following objects must first be created:
 
 
Creating source and target names
Two name objects are required for the conversion: one for the source (the File GDB feature class) and one for the target (the new shapefile).  When creating a feature class name object, it's necessary to have a name object for the containing workspace, as well.  By connecting to the two workspaces - the shapefile folder and the File GDB - and casting to the IDataset interface, name objects can be retrieved.  For more information about connecting to workspaces, see How to connect to a geodatabase.
 
The following code example shows how to obtain these workspace names:

[C#]
// Open the source and target workspaces.
String sourceWorkspacePath = @
  "C:\Program Files\arcgis\DeveloperKit\SamplesNET\data\Atlanta.gdb";
String targetWorkspacePath = Environment.CurrentDirectory;
IWorkspaceFactory sourceWorkspaceFactory = new FileGDBWorkspaceFactoryClass();
IWorkspaceFactory targetWorkspaceFactory = new ShapefileWorkspaceFactoryClass();
IWorkspace sourceWorkspace = sourceWorkspaceFactory.OpenFromFile
  (sourceWorkspacePath, 0);
IWorkspace targetWorkspace = targetWorkspaceFactory.OpenFromFile
  (targetWorkspacePath, 0);

// Cast the workspaces to the IDataset interface and get name objects.
IDataset sourceWorkspaceDataset = (IDataset)sourceWorkspace;
IDataset targetWorkspaceDataset = (IDataset)targetWorkspace;
IName sourceWorkspaceDatasetName = sourceWorkspaceDataset.FullName;
IName targetWorkspaceDatasetName = targetWorkspaceDataset.FullName;
IWorkspaceName sourceWorkspaceName = (IWorkspaceName)sourceWorkspaceDatasetName;
IWorkspaceName targetWorkspaceName = (IWorkspaceName)targetWorkspaceDatasetName;

[VB.NET]
' Open the source and target workspaces.
Dim sourceWorkspacePath As String = "C:\arcgis\DeveloperKit\SamplesNET\data\Atlanta.gdb"
Dim targetWorkspacePath As String = Environment.CurrentDirectory
Dim sourceWorkspaceFactory As IWorkspaceFactory = New FileGDBWorkspaceFactoryClass()
Dim targetWorkspaceFactory As IWorkspaceFactory = New ShapefileWorkspaceFactoryClass()
Dim sourceWorkspace As IWorkspace = sourceWorkspaceFactory.OpenFromFile(sourceWorkspacePath, 0)
Dim targetWorkspace As IWorkspace = targetWorkspaceFactory.OpenFromFile(targetWorkspacePath, 0)

' Cast the workspaces to the IDataset interface and get name objects.
Dim sourceWorkspaceDataset As IDataset = CType(sourceWorkspace, IDataset)
Dim targetWorkspaceDataset As IDataset = CType(targetWorkspace, IDataset)
Dim sourceWorkspaceDatasetName As IName = sourceWorkspaceDataset.FullName
Dim targetWorkspaceDatasetName As IName = targetWorkspaceDataset.FullName
Dim sourceWorkspaceName As IWorkspaceName = CType(sourceWorkspaceDatasetName, IWorkspaceName)
Dim targetWorkspaceName As IWorkspaceName = CType(targetWorkspaceDatasetName, IWorkspaceName)
 
To build feature class name objects, two things are required:  name objects for the containing workspaces (which were just created), and the names of the source and target feature classes.  The feature class to be copied is named "streets", but the shapefile will be named "AtlantaStreets".  The following code example shows how to build these feature class name objects:
 

[C#]
// Create a name object for the shapefile and cast it to the IDatasetName interface.
IFeatureClassName sourceFeatureClassName = new FeatureClassNameClass();
IDatasetName sourceDatasetName = (IDatasetName)sourceFeatureClassName;
sourceDatasetName.Name = "streets";
sourceDatasetName.WorkspaceName = sourceWorkspaceName;

// Create a name object for the FGDB feature class and cast it to the IDatasetName interface.
IFeatureClassName targetFeatureClassName = new FeatureClassNameClass();
IDatasetName targetDatasetName = (IDatasetName)targetFeatureClassName;
targetDatasetName.Name = "AtlantaStreets";
targetDatasetName.WorkspaceName = targetWorkspaceName;

[VB.NET]
' Create a name object for the shapefile and cast it to the IDatasetName interface.
Dim sourceFeatureClassName As IFeatureClassName = New FeatureClassNameClass()
Dim sourceDatasetName As IDatasetName = CType(sourceFeatureClassName, IDatasetName)
sourceDatasetName.Name = "streets"
sourceDatasetName.WorkspaceName = sourceWorkspaceName

' Create a name object for the FGDB feature class and cast it to the IDatasetName interface.
Dim targetFeatureClassName As IFeatureClassName = New FeatureClassNameClass()
Dim targetDatasetName As IDatasetName = CType(targetFeatureClassName, IDatasetName)
targetDatasetName.Name = "AtlantaStreets"
targetDatasetName.WorkspaceName = targetWorkspaceName
When setting the IDatasetName.Name property, ensure that the formatting is appropriate for the data source.  For example, ArcSDE feature classes may require qualification, and Coverages also use a format different from other data sources.
 
Creating output feature class fields and geometry
Dataset name objects (including feature class name objects) can be cast to the IName interface, from where the IName.Open method can be called to open the actual dataset.  The IFieldChecker interface should then be used to convert the source's fields collection to a new collection that's compatible with the target workspace, as different data sources have different restrictions on field properties, such as the maximum length of a field name.  If an error is found, an enumerator of field errors (accessed through the IEnumFieldError interface) can be traversed and an error returned. Refer to IFieldChecker.Validate and IFieldError for details. See the following code:
 

[C#]
// Open source feature class to get field definitions.
IName sourceName = (IName)sourceFeatureClassName;
IFeatureClass sourceFeatureClass = (IFeatureClass)sourceName.Open();

// Create the objects and references necessary for field validation.
IFieldChecker fieldChecker = new FieldCheckerClass();
IFields sourceFields = sourceFeatureClass.Fields;
IFields targetFields = null;
IEnumFieldError enumFieldError = null;

// Set the required properties for the IFieldChecker interface.
fieldChecker.InputWorkspace = sourceWorkspace;
fieldChecker.ValidateWorkspace = targetWorkspace;

// Validate the fields and check for errors.
fieldChecker.Validate(sourceFields, out enumFieldError, out targetFields);
if (enumFieldError != null)
{
  // Handle the errors in a way appropriate to your application.
  Console.WriteLine("Errors were encountered during field validation.");
}

[VB.NET]
' Open source feature class to get field definitions.
Dim sourceName As IName = CType(sourceFeatureClassName, IName)
Dim sourceFeatureClass As IFeatureClass = CType(sourceName.Open(), IFeatureClass)

' Create the objects and references necessary for field validation.
Dim fieldChecker As IFieldChecker = New FieldCheckerClass()
Dim sourceFields As IFields = sourceFeatureClass.Fields
Dim targetFields As IFields = Nothing
Dim enumFieldError As IEnumFieldError = Nothing

' Set the required properties for the IFieldChecker interface.
fieldChecker.InputWorkspace = sourceWorkspace
fieldChecker.ValidateWorkspace = targetWorkspace

' Validate the fields and check for errors.
fieldChecker.Validate(sourceFields, enumFieldError, targetFields)
If Not enumFieldError Is Nothing Then
    ' Handle the errors in a way appropriate to your application.
    Console.WriteLine("Errors were encountered during field validation.")
End If
Do not add or remove fields from the target fields collection, as doing so will cause the conversion to fail.  To restrict the fields created in the target feature class, see the section below regarding the use of a query filter.
 
The geometry definition for the target feature class should be obtained by cloning the geometry definition from the source feature class.  The following code example shows how to do this:
 

[C#]
// Find the shape field.
String shapeFieldName = sourceFeatureClass.ShapeFieldName;
int shapeFieldIndex = sourceFeatureClass.FindField(shapeFieldName);
IField shapeField = sourceFields.get_Field(shapeFieldIndex);

// Get the geometry definition from the shape field and clone it.
IGeometryDef geometryDef = shapeField.GeometryDef;
IClone geometryDefClone = (IClone)geometryDef;
IClone targetGeometryDefClone = geometryDefClone.Clone();
IGeometryDef targetGeometryDef = (IGeometryDef)targetGeometryDefClone;

[VB.NET]
' Find the shape field.
Dim shapeFieldName As String = sourceFeatureClass.ShapeFieldName
Dim shapeFieldIndex As Integer = sourceFeatureClass.FindField(shapeFieldName)
Dim shapeField As IField = sourceFields.Field(shapeFieldIndex)

' Get the geometry definition from the shape field and clone it.
Dim geometryDef As IGeometryDef = shapeField.GeometryDef
Dim geometryDefClone As IClone = CType(geometryDef, IClone)
Dim targetGeometryDefClone As IClone = geometryDefClone.Clone()
Dim targetGeometryDef As IGeometryDef = CType(targetGeometryDefClone, IGeometryDef)
 
Executing the conversion
Two types of restrictions can be applied to the conversion: the number of features that accompany the conversion (through attribute constraints), and the number of fields that are created in the new feature class.  Both of these restrictions can be applied through using a query filter, specifically the IQueryFilter.WhereClause and IQueryFilter.SubFields properties.  If spatial constraints are also necessary, the ISpatialFilter interface can also be used.  Note that applying constraints is optional, and a null value can be passed to the conversion method in lieu of a query filter if they aren't applicable.
 
The following code example shows how to create a query filter resulting in the target shapefile only containing streets (and not interstates, highways and ramps):
 

[C#]
// Create a query filter to remove ramps, interstates and highways.
IQueryFilter queryFilter = new QueryFilterClass();
queryFilter.WhereClause = "NAME <> 'Ramp' AND PRE_TYPE NOT IN ('I', 'Hwy')";

[VB.NET]
' Create a query filter to remove ramps, interstates and highways.
Dim queryFilter As IQueryFilter = New QueryFilterClass()
queryFilter.WhereClause = "NAME <> 'Ramp' AND PRE_TYPE NOT IN ('I', 'Hwy')"
 
Convert the feature class by calling IFeatureDataConverter.ConvertFeatureClass. Though rarely needed, rejected features can be reported using the IEnumInvalidObject and IInvalidObjectInfo interfaces. See the following code:
 

[C#]
// Create the converter and run the conversion.
IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
IEnumInvalidObject enumInvalidObject = featureDataConverter.ConvertFeatureClass
  (sourceFeatureClassName, queryFilter, null, targetFeatureClassName,
  targetGeometryDef, targetFields, "", 1000, 0);

// Check for errors.
IInvalidObjectInfo invalidObjectInfo = null;
enumInvalidObject.Reset();
while ((invalidObjectInfo = enumInvalidObject.Next()) != null)
{
  // Handle the errors in a way appropriate to the application.
  Console.WriteLine("Errors occurred for the following feature: {0}",
    invalidObjectInfo.InvalidObjectID);
}

[VB.NET]
' Create the converter and run the conversion.
Dim featureDataConverter As IFeatureDataConverter = New FeatureDataConverterClass()
Dim enumInvalidObject As IEnumInvalidObject = featureDataConverter.ConvertFeatureClass(sourceFeatureClassName, queryFilter, Nothing, targetFeatureClassName, targetGeometryDef, targetFields, "", 1000, 0)

' Check for errors.
enumInvalidObject.Reset()
Dim invalidObjectInfo As IInvalidObjectInfo = enumInvalidObject.Next()
Do While Not invalidObjectInfo Is Nothing
    ' Handle the errors in a way appropriate to the application.
    Console.WriteLine("Errors occurred for the following feature: {0}", invalidObjectInfo.InvalidObjectID)
Loop
 

Complete code example

The following code is the concatenation of the previous examples:
 

[C#]
public void ConvertFeatureClassToShapefile()
{
  // Open the source and target workspaces.
  String sourceWorkspacePath = @
    "C:\arcgis\DeveloperKit\SamplesNET\data\Atlanta.gdb";
  String targetWorkspacePath = @"C:\Temp";
  IWorkspaceFactory sourceWorkspaceFactory = new FileGDBWorkspaceFactoryClass();
  IWorkspaceFactory targetWorkspaceFactory = new ShapefileWorkspaceFactoryClass
    ();
  IWorkspace sourceWorkspace = sourceWorkspaceFactory.OpenFromFile
    (sourceWorkspacePath, 0);
  IWorkspace targetWorkspace = targetWorkspaceFactory.OpenFromFile
    (targetWorkspacePath, 0);

  // Cast the workspaces to the IDataset interface and get name objects.
  IDataset sourceWorkspaceDataset = (IDataset)sourceWorkspace;
  IDataset targetWorkspaceDataset = (IDataset)targetWorkspace;
  IName sourceWorkspaceDatasetName = sourceWorkspaceDataset.FullName;
  IName targetWorkspaceDatasetName = targetWorkspaceDataset.FullName;
  IWorkspaceName sourceWorkspaceName = (IWorkspaceName)
    sourceWorkspaceDatasetName;
  IWorkspaceName targetWorkspaceName = (IWorkspaceName)
    targetWorkspaceDatasetName;

  // Create a name object for the shapefile and cast it to the IDatasetName interface.
  IFeatureClassName sourceFeatureClassName = new FeatureClassNameClass();
  IDatasetName sourceDatasetName = (IDatasetName)sourceFeatureClassName;
  sourceDatasetName.Name = "streets";
  sourceDatasetName.WorkspaceName = sourceWorkspaceName;

  // Create a name object for the FGDB feature class and cast it to the IDatasetName interface.
  IFeatureClassName targetFeatureClassName = new FeatureClassNameClass();
  IDatasetName targetDatasetName = (IDatasetName)targetFeatureClassName;
  targetDatasetName.Name = "AtlantaStreets";
  targetDatasetName.WorkspaceName = targetWorkspaceName;

  // Open source feature class to get field definitions.
  IName sourceName = (IName)sourceFeatureClassName;
  IFeatureClass sourceFeatureClass = (IFeatureClass)sourceName.Open();

  // Create the objects and references necessary for field validation.
  IFieldChecker fieldChecker = new FieldCheckerClass();
  IFields sourceFields = sourceFeatureClass.Fields;
  IFields targetFields = null;
  IEnumFieldError enumFieldError = null;

  // Set the required properties for the IFieldChecker interface.
  fieldChecker.InputWorkspace = sourceWorkspace;
  fieldChecker.ValidateWorkspace = targetWorkspace;

  // Validate the fields and check for errors.
  fieldChecker.Validate(sourceFields, out enumFieldError, out targetFields);
  if (enumFieldError != null)
  {
    // Handle the errors in a way appropriate to your application.
    Console.WriteLine("Errors were encountered during field validation.");
  }

  // Find the shape field.
  String shapeFieldName = sourceFeatureClass.ShapeFieldName;
  int shapeFieldIndex = sourceFeatureClass.FindField(shapeFieldName);
  IField shapeField = sourceFields.get_Field(shapeFieldIndex);

  // Get the geometry definition from the shape field and clone it.
  IGeometryDef geometryDef = shapeField.GeometryDef;
  IClone geometryDefClone = (IClone)geometryDef;
  IClone targetGeometryDefClone = geometryDefClone.Clone();
  IGeometryDef targetGeometryDef = (IGeometryDef)targetGeometryDefClone;

  // Create a query filter to remove ramps, interstates and highways.
  IQueryFilter queryFilter = new QueryFilterClass();
  queryFilter.WhereClause = "NAME <> 'Ramp' AND PRE_TYPE NOT IN ('I', 'Hwy')";

  // Create the converter and run the conversion.
  IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
  IEnumInvalidObject enumInvalidObject =
    featureDataConverter.ConvertFeatureClass(sourceFeatureClassName,
    queryFilter, null, targetFeatureClassName, targetGeometryDef, targetFields,
    "", 1000, 0);

  // Check for errors.
  IInvalidObjectInfo invalidObjectInfo = null;
  enumInvalidObject.Reset();
  while ((invalidObjectInfo = enumInvalidObject.Next()) != null)
  {
    // Handle the errors in a way appropriate to the application.
    Console.WriteLine("Errors occurred for the following feature: {0}",
      invalidObjectInfo.InvalidObjectID);
  }
}

[VB.NET]
Public Sub ConvertFeatureClassToShapefile()
    ' Open the source and target workspaces.
    Dim sourceWorkspacePath As String = "C:\arcgis\DeveloperKit\SamplesNET\data\Atlanta.gdb"
    Dim targetWorkspacePath As String = "C:\Temp"
    Dim sourceWorkspaceFactory As IWorkspaceFactory = New FileGDBWorkspaceFactoryClass()
    Dim targetWorkspaceFactory As IWorkspaceFactory = New ShapefileWorkspaceFactoryClass()
    Dim sourceWorkspace As IWorkspace = sourceWorkspaceFactory.OpenFromFile(sourceWorkspacePath, 0)
    Dim targetWorkspace As IWorkspace = targetWorkspaceFactory.OpenFromFile(targetWorkspacePath, 0)
    
    ' Cast the workspaces to the IDataset interface and get name objects.
    Dim sourceWorkspaceDataset As IDataset = CType(sourceWorkspace, IDataset)
    Dim targetWorkspaceDataset As IDataset = CType(targetWorkspace, IDataset)
    Dim sourceWorkspaceDatasetName As IName = sourceWorkspaceDataset.FullName
    Dim targetWorkspaceDatasetName As IName = targetWorkspaceDataset.FullName
    Dim sourceWorkspaceName As IWorkspaceName = CType(sourceWorkspaceDatasetName, IWorkspaceName)
    Dim targetWorkspaceName As IWorkspaceName = CType(targetWorkspaceDatasetName, IWorkspaceName)
    
    ' Create a name object for the shapefile and cast it to the IDatasetName interface.
    Dim sourceFeatureClassName As IFeatureClassName = New FeatureClassNameClass()
    Dim sourceDatasetName As IDatasetName = CType(sourceFeatureClassName, IDatasetName)
    sourceDatasetName.Name = "streets"
    sourceDatasetName.WorkspaceName = sourceWorkspaceName
    
    ' Create a name object for the FGDB feature class and cast it to the IDatasetName interface.
    Dim targetFeatureClassName As IFeatureClassName = New FeatureClassNameClass()
    Dim targetDatasetName As IDatasetName = CType(targetFeatureClassName, IDatasetName)
    targetDatasetName.Name = "AtlantaStreets"
    targetDatasetName.WorkspaceName = targetWorkspaceName
    
    ' Open source feature class to get field definitions.
    Dim sourceName As IName = CType(sourceFeatureClassName, IName)
    Dim sourceFeatureClass As IFeatureClass = CType(sourceName.Open(), IFeatureClass)
    
    ' Create the objects and references necessary for field validation.
    Dim fieldChecker As IFieldChecker = New FieldCheckerClass()
    Dim sourceFields As IFields = sourceFeatureClass.Fields
    Dim targetFields As IFields = Nothing
    Dim enumFieldError As IEnumFieldError = Nothing
    
    ' Set the required properties for the IFieldChecker interface.
    fieldChecker.InputWorkspace = sourceWorkspace
    fieldChecker.ValidateWorkspace = targetWorkspace
    
    ' Validate the fields and check for errors.
    fieldChecker.Validate(sourceFields, enumFieldError, targetFields)
    If Not enumFieldError Is Nothing Then
        ' Handle the errors in a way appropriate to your application.
        Console.WriteLine("Errors were encountered during field validation.")
    End If
    
    ' Find the shape field.
    Dim shapeFieldName As String = sourceFeatureClass.ShapeFieldName
    Dim shapeFieldIndex As Integer = sourceFeatureClass.FindField(shapeFieldName)
    Dim shapeField As IField = sourceFields.Field(shapeFieldIndex)
    
    ' Get the geometry definition from the shape field and clone it.
    Dim geometryDef As IGeometryDef = shapeField.GeometryDef
    Dim geometryDefClone As IClone = CType(geometryDef, IClone)
    Dim targetGeometryDefClone As IClone = geometryDefClone.Clone()
    Dim targetGeometryDef As IGeometryDef = CType(targetGeometryDefClone, IGeometryDef)
    
    ' Create a query filter to remove ramps, interstates and highways.
    Dim queryFilter As IQueryFilter = New QueryFilterClass()
    queryFilter.WhereClause = "NAME <> 'Ramp' AND PRE_TYPE NOT IN ('I', 'Hwy')"
    
    ' Create the converter and run the conversion.
    Dim featureDataConverter As IFeatureDataConverter = New FeatureDataConverterClass()
    Dim enumInvalidObject As IEnumInvalidObject = featureDataConverter.ConvertFeatureClass(sourceFeatureClassName, queryFilter, Nothing, targetFeatureClassName, targetGeometryDef, targetFields, "", 1000, 0)
    
    ' Check for errors.
    enumInvalidObject.Reset()
    Dim invalidObjectInfo As IInvalidObjectInfo = enumInvalidObject.Next()
    Do While Not invalidObjectInfo Is Nothing
        ' Handle the errors in a way appropriate to the application.
        Console.WriteLine("Errors occurred for the following feature: {0}", invalidObjectInfo.InvalidObjectID)
    Loop
End Sub