Español · English
📖 Guía de bolsillo — todos los comandos en una página
CLI de .NET 10 para migrar y sincronizar DBF de Visual FoxPro hacia PostgreSQL, SQL Server o SQLite, sin apagar el ERP. El sistema Xbase++ continúa operando sobre sus DBF mientras otros servicios consumen una base relacional actualizada.
RECNO() conserva la identidad física del registro y SHA-256
decide si cambió; cada tabla se reconcilia en su propia transacción.
PeopleWorks DBFSync ofrece perfiles de conexión seguros, selección flexible con wildcards, detección de cambios por contenido, evolución controlada del esquema, ejecución desatendida y una terminal bilingüe basada en Spectre.Console.
Plataforma: Windows
win-x86. El proceso debe ser de 32 bits porque el Microsoft Visual FoxPro ODBC Driver es x86.
- Características
- Cómo funciona
- Requisitos e instalación
- Inicio rápido con SQLite
- Perfiles y seguridad
- Referencia de comandos
- Selección de DBF
- Migración y sincronización
- Evolución del esquema
- Mapeo de tipos
- Task Scheduler
- Logs y códigos de salida
- Troubleshooting
- Desarrollo y contribuciones
- Proyectos PeopleWorks relacionados
| Área | Capacidades |
|---|---|
| Destinos | PostgreSQL, SQL Server y SQLite |
| Selección | Nombre exacto, listas, *, ?, --all, exclusiones y opciones repetidas |
| Identidad | RECNO() conserva la identidad física de cada registro DBF |
| Cambios | SHA-256 detecta modificaciones aunque el RECNO() no cambie |
| Reconciliación | Inserta nuevos, actualiza modificados y elimina ausentes o marcados como borrados |
| Esquema | Agrega campos, amplía tipos seguros, bloquea cambios destructivos y permite reconstrucción explícita |
| Seguridad | Perfiles nombrados, contraseñas protegidas con DPAPI y transporte cifrado por defecto |
| Automatización | Sin credenciales en argumentos, logs por ejecución y bloqueo de trabajos simultáneos |
| Idiomas | Recursos extensibles en inglés y español |
| Experiencia CLI | Banner PeopleWorks, colores, tablas y contexto de conexión sin revelar secretos |
DBF de Visual FoxPro
│
▼
ODBC x86 ── RECNO() + normalización + SHA-256
│
▼
Tabla temporal de staging
│
▼
Transacción por tabla
│
├── INSERT de registros nuevos
├── UPDATE cuando cambia el hash
└── DELETE de registros ausentes
│
▼
PostgreSQL / SQL Server / SQLite
- El driver se abre con
Deleted=Yes; los registros marcados como borrados no se transfieren y desaparecen del destino durantesync. - Las fechas vacías de FoxPro (
1899-12-30) se normalizan comoNULL. - Los textos se normalizan antes de calcular el hash.
- Cada DBF tiene su propia transacción. Si se seleccionan varias tablas y una posterior falla, las anteriores ya confirmadas permanecen sincronizadas.
- Los nombres destino se normalizan a minúsculas y DBFSync agrega
_dbfsync_recno,_dbfsync_hashy_dbfsync_at.
- Windows con el runtime .NET 10 x86 o el SDK .NET 10.
- Microsoft Visual FoxPro ODBC Driver x86.
- Lectura sobre la carpeta que contiene los DBF.
- Para PostgreSQL o SQL Server: permiso para conectar, crear el esquema y crear o modificar tablas.
- Para SQLite: escritura sobre la carpeta del archivo
.db. - Para
--create-database: permiso para crear bases desdepostgresen PostgreSQL omasteren SQL Server.
dotnet restore .\DBFSync.slnx
dotnet build .\DBFSync.slnx --configuration Release
dotnet test .\DBFSync.slnx --configuration Release
dotnet publish .\src\DBFSync\DBFSync.csproj `
--configuration Release `
--runtime win-x86 `
--self-contained false `
--output .\dist\win-x86Verifique el ejecutable:
.\dist\win-x86\dbfsync.exe --version
.\dist\win-x86\dbfsync.exe --help --lang esPuede copiar todo el contenido de dist\win-x86 a una carpeta estable, por
ejemplo C:\Tools\PeopleWorks\DBFSync. No copie únicamente dbfsync.exe; las
DLL y los recursos publicados también son necesarios.
SQLite no requiere servidor ni credenciales y es el destino recomendado para la primera prueba desatendida.
# 1. Crear el perfil y el archivo SQLite
dbfsync profile set local `
--engine sqlite `
--file C:\DBFSync\erp.db
# 2. Revisar qué se leerá
dbfsync inspect `
--source C:\ERP\Datos `
--tables "clientes,articulos,fa*.dbf" `
--exclude "*hist*,*bak*"
# 3. Carga inicial
dbfsync migrate `
--profile local `
--source C:\ERP\Datos `
--tables "clientes,articulos,fa*.dbf"
# 4. Sincronizaciones posteriores
dbfsync sync `
--profile local `
--source C:\ERP\Datos `
--tables "clientes,articulos,fa*.dbf" `
--sync-schemaEl archivo y sus carpetas padre se crean automáticamente.
Los perfiles se guardan por nombre en:
C:\ProgramData\PeopleWorks\DBFSync\profiles.json
Los logs se escriben en:
C:\ProgramData\PeopleWorks\DBFSync\logs
DBFSYNC_HOME permite cambiar ambas ubicaciones:
$env:DBFSYNC_HOME = "D:\PeopleWorks\DBFSync"
dbfsync profile listLas contraseñas nunca se guardan en texto plano. DPAPI las protege con uno de estos ámbitos:
| Ámbito | Uso recomendado | Consideración |
|---|---|---|
--scope user |
Ejecución manual o tarea con la misma cuenta Windows | Solo esa cuenta puede descifrar la contraseña |
--scope machine |
Servicio o tarea con otra cuenta de la misma máquina | Proteja profiles.json con permisos NTFS restrictivos |
SQLite y la autenticación integrada de SQL Server no almacenan contraseña.
Para modificar un perfil, ejecute nuevamente profile set con el mismo nombre
y todas sus opciones.
El transporte cifrado está habilitado de forma predeterminada. En PostgreSQL se valida tanto el certificado como el nombre del servidor.
dbfsync profile set erp-pg `
--engine postgresql `
--server pg01.example.com `
--port 5432 `
--database erp `
--schema public `
--user dbfsync `
--scope user `
--create-databaseLa contraseña se solicita una sola vez y el perfil se prueba antes de guardarlo.
Algunas instalaciones locales no habilitan SSL. En un equipo de desarrollo
confiable use explícitamente --no-encrypt:
dbfsync profile set erp-pg `
--engine postgresql `
--server 127.0.0.1 `
--port 5432 `
--database pwerp `
--schema public `
--user postgres `
--scope user `
--no-encrypt `
--create-databaseDespués puede confirmar la conexión:
dbfsync profile test erp-pg
--trust-server-certificatemantiene SSL pero omite la validación del certificado. No resuelve un servidor que no ofrece SSL; para ese caso local se necesita--no-encrypt. No desactive el cifrado en redes no confiables o en producción.
dbfsync profile set erp-sql `
--engine sqlserver `
--server sql01 `
--port 1433 `
--database ERP `
--schema dbo `
--user dbfsync `
--scope machine `
--trust-server-certificate `
--create-databaseSQL Server también cifra de forma predeterminada. Use
--trust-server-certificate únicamente cuando el servidor use un certificado
confiable para la organización pero no validable por la máquina cliente.
dbfsync profile set erp-windows `
--engine sqlserver `
--server sql01 `
--database ERP `
--schema dbo `
--integrateddbfsync profile set local `
--engine sqlite `
--file C:\DBFSync\erp.dbSQLite usa WAL, espera ocupada y un archivo lateral .dbfsync.lock para impedir
dos escritores DBFSync simultáneos sobre la misma base. Los decimales se guardan
como texto canónico de cultura invariable para conservar precisión exacta; las
fechas y marcas de tiempo se guardan como texto ISO.
dbfsync profile list
dbfsync profile show erp-pg
dbfsync profile test erp-pg
dbfsync profile remove erp-pg--create-database crea la base si no existe antes de verificar y guardar el
perfil. También existe una operación idempotente para perfiles guardados:
dbfsync database create --profile erp-pg- PostgreSQL conecta a la base de mantenimiento
postgres. - SQL Server conecta a
master. - SQLite crea el archivo y sus carpetas padre.
- Si la base ya existe, el comando termina correctamente sin recrearla.
| Comando | Descripción |
|---|---|
dbfsync --help |
Muestra ayuda resumida |
dbfsync --version |
Muestra la versión |
dbfsync sample |
Muestra escenarios completos |
dbfsync profile set NAME |
Crea o reemplaza un perfil |
dbfsync profile list |
Lista perfiles |
dbfsync profile show NAME |
Muestra un perfil sin secretos |
dbfsync profile test NAME |
Prueba la conexión |
dbfsync profile remove NAME |
Elimina un perfil |
dbfsync database create --profile NAME |
Crea o verifica la base |
dbfsync inspect ... |
Inspecciona esquema, filas activas y muestra |
dbfsync migrate ... |
Reemplaza el contenido destino |
dbfsync sync ... |
Reconcilia inserciones, cambios y eliminaciones |
También se aceptan aliases en español como perfil, migrar, sincronizar,
inspeccionar, ejemplo y ayuda.
| Opción | Motores | Descripción |
|---|---|---|
--engine postgresql|sqlserver|sqlite |
Todos | Motor requerido |
--server HOST |
PostgreSQL, SQL Server | Servidor o dirección IP |
--port N |
PostgreSQL, SQL Server | Puerto; PostgreSQL usa 5432 si se omite |
--database NAME |
PostgreSQL, SQL Server | Base de datos |
--file PATH |
SQLite | Archivo de base SQLite |
--schema NAME |
PostgreSQL, SQL Server | Predeterminado: public o dbo |
--user NAME |
PostgreSQL, SQL Server | Usuario cuando no se usa autenticación integrada |
--integrated |
SQL Server | Usa la identidad Windows del proceso |
--scope user|machine |
PostgreSQL, SQL Server | Ámbito DPAPI; predeterminado: user |
--no-encrypt |
PostgreSQL, SQL Server | PostgreSQL desactiva SSL y SQL Server deja de exigir cifrado; solo desarrollo local confiable |
--trust-server-certificate |
PostgreSQL, SQL Server | Mantiene cifrado sin validar certificado |
--password-stdin |
PostgreSQL, SQL Server | Lee una línea desde stdin en vez de preguntar |
--create-database |
Todos | Crea la base o archivo si no existe |
| Opción | Descripción |
|---|---|
--profile NAME |
Perfil destino requerido |
--source PATH |
Carpeta DBF requerida |
--tables PATTERNS |
Lista de nombres o patrones separados por coma |
--table PATTERN |
Patrón individual; puede repetirse |
--all |
Selecciona todos los DBF de la carpeta |
--exclude PATTERNS |
Excluye nombres o patrones |
--batch-size N |
Filas por lote; predeterminado 5000, rango 1-100000 |
--sync-schema |
Aplica evolución estructural segura |
--allow-drop-columns |
Autoriza eliminar columnas; exige --sync-schema |
--recreate |
Reconstruye tablas; solo migrate |
--all y patrones de inclusión son mutuamente excluyentes.
--lang puede aparecer en cualquier posición:
dbfsync --help --lang es
dbfsync sample --lang en
dbfsync inspect --lang es --source C:\ERP\Datos --tables "fa*.dbf"Para una tarea programada también puede usar DBFSYNC_LANG:
$env:DBFSYNC_LANG = "es"La búsqueda se realiza sobre los archivos .dbf de la carpeta indicada, sin
recorrer subcarpetas.
| Necesidad | Ejemplo |
|---|---|
| Un DBF | --table clientes |
| Lista | --tables clientes,articulos |
| Opciones repetidas | --table clientes --table articulos |
| Prefijo | --tables "fa*.dbf" |
| Un carácter | --tables "cbmovf??" |
| Exclusión | --exclude "*hist*,*bak*" |
| Negación inline | --tables "fa*,!fahist*" |
| Todos salvo algunos | --all --exclude "temp*,*bak*,prueba*" |
Cada patrón de inclusión debe encontrar al menos un DBF y la selección final no puede quedar vacía. Esto evita que una tarea termine silenciosamente por un nombre mal escrito.
Antes de escribir, use inspect:
dbfsync inspect `
--source C:\ERP\Datos `
--tables "fa*.dbf,cbmovf??" `
--exclude "*hist*,*bak*"migrate reemplaza todo el contenido de las tablas seleccionadas:
dbfsync migrate `
--profile erp-pg `
--source C:\ERP\Datos `
--tables "clientes,articulos,fa*.dbf"dbfsync sync `
--profile erp-pg `
--source C:\ERP\Datos `
--tables "clientes,articulos,fa*.dbf" `
--exclude "*hist*"En cada tabla:
RECNO()identifica el registro físico.- SHA-256 representa todos los valores normalizados.
- Un
RECNO()nuevo produceINSERT. - El mismo
RECNO()con otro hash produceUPDATE. - Un
RECNO()ausente produceDELETE.
Así, cambiar cualquier campo se sincroniza aunque el RECNO() permanezca igual.
| Motor | Staging y reconciliación | Bloqueo |
|---|---|---|
| PostgreSQL | COPY binario y transacción |
Advisory lock por tabla |
| SQL Server | SqlBulkCopy y transacción |
sp_getapplock por tabla |
| SQLite | Tabla temporal y UPSERT transaccional | Archivo exclusivo por base |
Sin indicadores de esquema, una tabla existente debe coincidir exactamente con el DBF. Si cambió, DBFSync se detiene antes de reconciliar datos.
dbfsync sync `
--profile erp-pg `
--source C:\ERP\Datos `
--tables clientes,articulos `
--sync-schema--sync-schema:
- agrega campos nuevos como columnas anulables;
- amplía longitudes de texto compatibles;
- amplía precisión/escala decimal conservando capacidad;
- permite
datea fecha/hora cuando corresponde; - aplica estructura y datos en la misma transacción por tabla.
Los campos que desaparecieron del DBF se rechazan de forma predeterminada:
dbfsync sync `
--profile erp-pg `
--source C:\ERP\Datos `
--tables clientes `
--sync-schema `
--allow-drop-columns--allow-drop-columns es destructivo y exige --sync-schema.
Una reducción de longitud o precisión y cualquier conversión insegura requieren reconstrucción:
dbfsync migrate `
--profile erp-pg `
--source C:\ERP\Datos `
--tables clientes `
--recreate--recreate elimina y vuelve a crear la tabla dentro de una transacción. Solo
se admite con migrate y no se combina con --sync-schema.
| Tipo DBF | SQL Server | PostgreSQL | SQLite |
|---|---|---|---|
| Texto | nvarchar(n) / nvarchar(max) |
varchar(n) / text |
TEXT |
| Decimal | decimal(p,s) |
numeric(p,s) |
TEXT canónico exacto |
| Entero | bigint |
bigint |
INTEGER |
| Punto flotante | float(53) |
double precision |
REAL |
| Lógico | bit |
boolean |
INTEGER |
| Fecha | date |
date |
TEXT ISO |
| Fecha/hora | datetime2(3) |
timestamp without time zone |
TEXT ISO |
| Binario | varbinary(max) |
bytea |
BLOB |
SQLite no codifica longitud ni precisión en el tipo físico. Por eso
--sync-schema agrega o elimina columnas allí, pero no necesita ampliar esos
atributos.
La tarea solo recibe el nombre del perfil; nunca necesita la contraseña:
C:\Tools\PeopleWorks\DBFSync\dbfsync.exe sync --profile erp-pg --source C:\ERP\Datos --tables "fa*.dbf,cbmovf??" --exclude "*hist*" --lang es
Ejemplo de creación con PowerShell:
$action = New-ScheduledTaskAction `
-Execute "C:\Tools\PeopleWorks\DBFSync\dbfsync.exe" `
-Argument 'sync --profile erp-pg --source C:\ERP\Datos --tables "fa*.dbf,cbmovf??" --exclude "*hist*" --lang es'
$trigger = New-ScheduledTaskTrigger `
-Once `
-At (Get-Date).AddMinutes(1) `
-RepetitionInterval (New-TimeSpan -Minutes 5)
$settings = New-ScheduledTaskSettingsSet `
-MultipleInstances IgnoreNew `
-StartWhenAvailable
Register-ScheduledTask `
-TaskName "PeopleWorks DBFSync ERP" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Description "Sincroniza DBF del ERP con PostgreSQL"- Con
--scope user, la tarea debe ejecutarse con la misma cuenta que creó el perfil. - Con
--scope machine, limite el acceso NTFS a la carpeta de configuración. - Configure no iniciar una instancia nueva si la anterior sigue activa.
- Trate únicamente el código
0como éxito.
Cada migrate y sync crea un log UTF-8 con marcas UTC:
C:\ProgramData\PeopleWorks\DBFSync\logs\
yyyyMMdd-HHmmssfff-operacion-perfil-pid.log
| Código | Significado |
|---|---|
0 |
Ejecución correcta |
1 |
Argumentos inválidos, error de conexión o transferencia |
130 |
Cancelación con Ctrl+C |
Los logs contienen progreso, conteos y errores, pero no contraseñas.
El perfil solicita SSL y el PostgreSQL local no lo ofrece. Vuelva a guardar el
mismo perfil completo agregando --no-encrypt:
dbfsync profile set erp-pg `
--engine postgresql `
--server 127.0.0.1 `
--port 5432 `
--database pwerp `
--schema public `
--user postgres `
--scope user `
--no-encryptUse esta opción solo en desarrollo local confiable. Si el servidor ofrece SSL
con un certificado no validable, use --trust-server-certificate en lugar de
desactivar el cifrado.
La opción correcta lleva t final: --no-encrypt.
Confirme que:
- está instalado el Microsoft Visual FoxPro ODBC Driver x86;
- está ejecutando el artefacto
win-x86; - la cuenta tiene lectura sobre la carpeta;
- ningún proceso abrió el DBF de forma exclusiva.
--scope user: ejecute con la misma cuenta Windows que creó el perfil.--scope machine: el perfil debe haberse creado en esa misma máquina.- Si cambió de equipo o cuenta, vuelva a guardar el perfil.
El usuario necesita CREATEDB en PostgreSQL o permiso CREATE ANY DATABASE en
SQL Server. También puede crear la base manualmente y guardar el perfil sin
--create-database.
- Cambio compatible: repita con
--sync-schema. - Campo eliminado: agregue conscientemente
--allow-drop-columns. - Cambio incompatible: use
migrate --recreatedespués de confirmar que puede reconstruir la tabla.
Cada patrón de inclusión debe coincidir. Use inspect, verifique la carpeta y
recuerde que la búsqueda no recorre subdirectorios.
Espere a que termine la ejecución existente. Revise Task Scheduler para impedir instancias paralelas; no elimine el archivo de bloqueo SQLite mientras haya un proceso activo.
DBFSync.slnx
├── src
│ ├── DBFSync.Core Lectura DBF, perfiles y motores destino
│ └── DBFSync Aplicación CLI y presentación
├── tests
│ └── DBFSync.Core.Tests
├── .github
│ ├── workflows
│ │ ├── ci.yml Build, pruebas, auditoría y artefacto win-x86
│ │ └── release.yml Publica el release al empujar un tag vX.Y.Z
│ ├── ISSUE_TEMPLATE
│ └── PULL_REQUEST_TEMPLATE.md
├── assets
│ └── hero.svg Diagrama del flujo de sincronización
├── docs
│ └── index.html Guía de bolsillo publicada en GitHub Pages
├── README.md
├── README.en.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
└── LICENSE
Dependencias principales:
System.Data.Odbcpara Visual FoxPro;Npgsqlpara PostgreSQL;Microsoft.Data.SqlClientpara SQL Server;Microsoft.Data.Sqlitey SQLitePCLRaw para SQLite;Spectre.Consolepara la terminal.
dotnet test .\DBFSync.slnx --configuration Release
dotnet list .\DBFSync.slnx package --vulnerable --include-transitiveLas pruebas cubren hashing, perfiles, selección, localización, mapeo de tipos, compatibilidad estructural y el ciclo integral de SQLite.
El repositorio incluye .github/workflows/ci.yml,
que corre sobre windows-latest en cada push y cada pull request hacia main,
y también a demanda con workflow_dispatch:
| Paso | Qué hace |
|---|---|
dotnet restore y dotnet build |
Compila la solución completa en Release |
dotnet test |
Ejecuta la suite de pruebas |
dotnet list package --vulnerable |
Falla la ejecución si aparece una dependencia vulnerable |
dotnet publish |
Genera el binario win-x86 dependiente del framework |
actions/upload-artifact |
Publica dist/win-x86 como artefacto descargable |
El runner estándar no incluye el driver Visual FoxPro; las pruebas DBF end-to-end necesitan un runner Windows propio que lo tenga instalado. En los runners de GitHub, la superficie portable de validación son las pruebas unitarias y el ciclo integral de SQLite.
Copie:
src\DBFSync.Core\Resources\Strings.es.resx
como Strings.<cultura>.resx, por ejemplo Strings.pt.resx, y traduzca solo
los valores. Inglés es el recurso neutral.
Las contribuciones deben mantener los tres motores consistentes, incluir pruebas para cambios de comportamiento y no registrar secretos ni datos del ERP.
DBFSync es una de las tres herramientas de datos de PeopleWorks. Cada una resuelve una etapa distinta de una modernización y las tres son CLI de .NET publicadas bajo licencia MIT.
| DBFSync | SQLDiff | SyncJob | |
|---|---|---|---|
| Propósito | Migrar y sincronizar datos heredados | Comparar y alinear esquemas | Sincronizar datos relacionales de forma continua |
| Origen | DBF de Visual FoxPro vía ODBC x86 | Esquema de SQL Server | SQL Server |
| Destino | PostgreSQL, SQL Server o SQLite | Script ALTER que preserva los datos |
SQL Server |
| Modelo de seguridad | Transacción por tabla, cambios detectados por SHA-256 y cambios de esquema destructivos bloqueados | Aplicación transaccional y detección de drift con código de salida 2 para CI |
Ejecución desatendida como CLI o como servicio de Windows |
| Ejecución | CLI, Windows win-x86, .NET 10 |
CLI de binario único, .NET 9 | CLI y servicio de Windows, .NET |
Las tres se encadenan en una modernización gradual:
- SQLDiff deja el esquema relacional en el estado esperado y detecta el drift entre entornos antes de tocar los datos.
- DBFSync carga los DBF de Visual FoxPro sobre ese esquema y los mantiene sincronizados mientras el ERP heredado sigue en producción.
- SyncJob mueve esos datos ya relacionales hacia los demás sistemas de SQL Server que los consumen.
Creado por Pedro Hernández — PeopleWorks · GitHub · Microsoft MVP for .NET
Construido para las comunidades de .NET, Visual FoxPro y modernización de datos: por y para la comunidad de desarrolladores.
DBFSync forma parte de la práctica de datos de PeopleWorks Services, LLC & Xari Technologies, junto a DPO — Data Performance Optimizer, la plataforma de evaluación, optimización y gobierno multi-base.
| Repositorio | https://github.com/peopleworks/DBFSync |
| Reportes y propuestas | Issues |
| Contribuciones | Pull requests · Guía |
| Vulnerabilidades | Política de seguridad — no las reporte en un issue público |
| Historial de cambios | CHANGELOG |
Si DBFSync le sirvió en una migración real, abra un issue contando el escenario: los casos concretos de ERP son lo que hace avanzar los tres motores. Un pull request con pruebas, una traducción nueva o una estrella también ayudan.
Distribuido bajo la licencia MIT.
PeopleWorks DBFSync • Sincronización de datos Visual FoxPro para sistemas reales
PeopleWorks data tools —
DBFSync conecta DBF con bases modernas ·
SQLDiff alinea esquemas ·
SyncJob mueve datos relacionales