Quick Tip: Cómo unir ficheros CSV en 30 líneas de código
Published: 2022-04-08 09:57:41

> _Mi apodo en las redes es [__Coding Bugs__][Dashboard] y llevo desde el año 2004 trabajando como desarrollador y arquitecto de software. En mi [dashboard][Dashboard] encontrarás artículos con información sobre lenguajes de programación, técnicas de programación y otros conceptos que te ayudarán a mejorar._

Vuelvo con otro artículo de [PowerShell][PowerShell] en el que os muestro lo fácil y rápido en generar un único fichero CSV a partir de muchos. Os resultará útil desarrollando procesos cuyo resultado sea un informe en formato CSV y tengáis que unir los contenidos de varios fichero en uno sólo.

> _CSV es una sigla que denomina a los ficheros con valores separados por comas o, en inglés, _"Comma Separated Values"_. Es un formato estandar de facto que se utiliza a menudo para el intercambio de información. El objetivo es tener un fichero de texto plano en el que cada fila es un registro, cada valor en la fila está separado por el carácter coma. Todas las filas tienen el mismo número de valores, es decir, el mismo número de comas. Visita la [RFC 4180](https://www.rfc-editor.org/rfc/rfc4180) para información detallada._

Para que el código siguiente funcione sin errores, el requisito es que todos los ficheros CSV que queremos unir tengan la misma estructura, es decir, las mismas cabeceras y en el mismo orden.

> Si queréis trabajar con ficheros CSV y utilizáis Node.js, he desarrollado una librería que simplifica la obtención de sus datos mediante objetos, arrays y filtros dinámicos. Descárgatelo con NPM y obtén más información clicando en este [enlace](https://www.npmjs.com/package/csver) y cuéntame cómo te ha ido.

Una vez hecha la introducción vamos a por el código para comentarlo.

```PowerShell
param(
	[Parameter(Mandatory=$true)]
	[String] $Location,

	[Parameter(Mandatory=$true)]
	[String] $NameFilter,

	[Parameter(Mandatory=$true)]
	[String] $OutputFile
)

If(Test-Path $OutputFile) {
 	Remove-Item $OutputFile -Force
}

# Writing headers obtained from the first file found
Get-ChildItem -Path $Location -Filter "$NameFilter.csv"
 | Select -First 1
 | Get-Content
 | Select -First 1
 | Out-File $OutputFile -Append

# Writing content for each file
Get-ChildItem -Path $Location -Filter "$NameFilter.csv"
	| Foreach {
		$_
			| Get-Content
			| Select -Skip 1
			| Out-File $OutputFile -Append
	}
```

El script necesita 3 parámetros de entrada:
1. El primero indica el lugar donde se encuentran los ficheros CSV que queremos unir,
2. El segundo permite indicar un filtro a aplicar para recoger los ficheros CSV objetivo,
3. Por último, el tercer parámetro indica dónde y cuál será el fichero resultante de la unión.

Hasta aquí muy sencillo. Los parámetros son todos de tipo `String` simplificando aún más los valores de entrada.

El siguiente bloque elimina el fichero resultante en caso de que exista. He añadido el parámetro `-Force` para evitar que esté preguntando constantemente. Esto es una elección personal, si lo quieres cambiar, adelante.

Ahora viene lo interesante, la unión de los contenidos. Para mantener la misma estructura existente en cada uno de los ficheros CSV tomo las cabeceras del primer fichero usnado mediante el comando `Get-ChildItem` y seleccionando el primero de todos ellos con `Select -First 1`.

```PowerShell
Get-ChildItem -Path $Location -Filter "$NameFilter.csv"
 | Select -First 1
 | Get-Content
 | Select -First 1
 | Out-File $OutputFile -Append
```

Obtener las cabeceras sigue el mismo patron con elementos diferentes. Leo el contenido del fichero, `Get-Content`, selecciono la primera fila, `Select -First 1` y lo escribo en el fichero de salida pasado en el tercer parámetro, `Out-File`.

Como puedes apreciar, no estoy haciendo ningún tipo de tratamiento de los datos por ser CSV ni de otro tipo, es decir, usando el comando `Import-Csv`. Como he comentado al principio del artículo, los ficheros CSV son ficheros de tipo texto y puede tratarse así al leerlo y al escribirlo.

El último bloque de código itera sobre cada contenido de cada fichero para volcar todos los datos a excepción de la primera fila. Recordad que la primera fila serán las cabeceras y no necesitamos volver a escribirla.

```PowerShell
Get-ChildItem -Path $Location -Filter "$NameFilter.csv"
	| Foreach {
		$_
			| Get-Content
			| Select -Skip 1
			| Out-File $OutputFile -Append
	}
```


Como habéis visto, con 30 líneas de código, incluyendo espacios en blanco, indentaciones, etc., tenemos la unión de varios ficheros en uno sólo. Tal vez no tengáis la necesidad de hacer esto mismo pero espero que os sirva de inspiración.

El código de este artículo lo tenéis en este [_gist_](https://gist.github.com/codbugs/76ffe0b0fb8b2d4079e997df89f326b1).

__Feedback__

Si te ha gustado este artículo no olvides clicar en el corazón o el unicornio y compartirlo con tus amigos y compañeros. Déjame tus comentarios en la parte inferior sobre lo que te ha gustado o como mejorar y si quieres que escriba acerca de otros temas mándame un mensaje directo a mi cuenta de [twitter][Twitter].

__Créditos__

La imagen de cabecera procede de [Unsplash] y es cortesía de [Mika Baumeister](https://unsplash.com/@mbaumi).


[PowerShell]: https://docs.microsoft.com/es-es/powershell/scripting/overview?view=powershell-7.2 "PowerShell"
[GitHub Profile]: https://github.com/codbugs "Mi perfil en GitHub"
[Unsplash]: https://unsplash.com/ "Unsplash"
[Twitter]: https://twitter.com/BugsCoding
[Dashboard]: https://dev.to/codbugs "Dashboard"