Codificación de caracteres y saltos de línea en Windows - Fundamentos de los caracteres corruptos y CRLF/LF

· Actualizado el: · · Windows, Codificación de caracteres, Caracteres corruptos, Código de salto de línea, UTF-8, CP932, PowerShell, Unicode

En las consultas relacionadas con el texto en Windows, es muy frecuente que los siguientes temas se mezclen todos a la vez.

  • ¿En qué se diferencian Shift_JIS y UTF-8?
  • ¿Por qué se producen los caracteres corruptos?
  • ¿En qué se diferencian CRLF y LF?
  • ¿Por qué a veces no se puede leer un archivo aunque se haya convertido a UTF-8?
  • ¿Por qué el mismo archivo se ve distinto en el editor, la consola, Excel y Git?

Este problema no ocurre porque el japonés sea difícil. En la mayoría de los casos, la causa es haber leído la misma secuencia de bytes bajo una suposición distinta, o haber guardado tal cual un contenido que se leyó de forma incorrecta.

Además, en Windows el mundo de Unicode y el mundo de las páginas de códigos siguen coexistiendo. A esto se suman el BOM, el código de salto de línea, la detección automática del editor, la página de códigos de la consola y la conversión de saltos de línea de Git, por lo que el tema parece complicado.

En este artículo organizamos, de forma orientada a la práctica, Shift_JIS, UTF-8 y UTF-16 -que suelen mezclarse en Windows-, por qué se producen los caracteres corruptos, la diferencia entre CRLF y LF, y por qué este tema tiende a generar confusión.

El contenido se basa en información pública de Microsoft Learn, PowerShell, Git y W3C/Unicode disponible en abril de 2026. Para más detalles, consulte las referencias al final del artículo.

Público objetivo y entorno previsto

Elemento Contenido
Público objetivo Desarrolladores y responsables de sistemas de información que en Windows intercambian archivos de texto (CSV, registros, archivos de configuración, código fuente) con otros departamentos, otros sistemas o el lado Linux
Conocimientos previos Ninguno en particular. Está estructurado para poder leerse incluso sin distinguir todavía entre una secuencia de bytes y una codificación de caracteres
Entorno previsto Windows 10 / Windows 11. Se trata tanto Windows PowerShell 5.1 como PowerShell 7
Fuera de alcance El uso de las API de conversión de codificación específicas de cada biblioteca, el diseño de fuentes/glifos, y la normalización de caracteres de ancho completo/medio

Si tiene prisa, esta es una forma de leerlo: para tener solo la visión general, lea los capítulos 1 y 2; para aislar la causa, lea los capítulos 3 y 8; y si quiere definir reglas operativas, empiece por el capítulo 7.

Índice

  1. Lo esencial primero
  2. Desglosando la terminología
    • 2.1 ¿En qué se diferencian Unicode, UTF-8, UTF-16 y CP932?
    • 2.2 Cómo entender Shift_JIS y CP932
    • 2.3 La trampa de los términos ANSI, Unicode y UTF-8N
    • 2.4 Qué es el BOM y por qué también aparece en UTF-8
  3. Por qué se producen los caracteres corruptos
    • 3.1 La verdadera causa de los caracteres corruptos
    • 3.2 Distorsión visual y corrupción de datos son cosas distintas
    • 3.3 Convertir a caracteres no representables es irreversible
  4. Las diferencias entre los caracteres de salto de línea
    • 4.1 CRLF / LF / CR
    • 4.2 El salto de línea es un problema distinto de la codificación de caracteres
    • 4.3 \n y la secuencia de bytes de salto de línea en el archivo no siempre coinciden
  5. Por qué la confusión es especialmente frecuente en Windows
    • 5.1 Unicode y las páginas de códigos heredadas coexisten
    • 5.2 Las etiquetas no están unificadas
    • 5.3 Con solo ASCII, el problema queda oculto
    • 5.4 El contenido del archivo, el nombre del archivo, la consola y el archivo fuente son capas distintas
    • 5.5 El BOM y el código de salto de línea también actúan como ejes independientes
    • 5.6 Las herramientas cambian las cosas por su cuenta
  6. Patrones habituales de incidentes
  7. Reglas prácticas para reducir incidentes
  8. Investigue caracteres corruptos y diferencias de fin de línea con estas 5 preguntas
  9. Resumen
  10. Artículos relacionados
  11. Referencias

1. Lo esencial primero

Si adelantamos solo las conclusiones, los puntos importantes son los siguientes 7.

  • Un archivo de texto no está formado por la cadena de caracteres en sí, sino por una secuencia de bytes + una codificación de caracteres + un código de salto de línea. Según el caso, también puede llevar un BOM (Byte Order Mark, marca de orden de bytes).
  • Los caracteres corruptos aparecen cuando se decodifica la misma secuencia de bytes con una codificación de caracteres distinta.
  • Los problemas de salto de línea aparecen cuando la suposición sobre el separador de línea no coincide, aunque la codificación de caracteres sea correcta.
  • Unicode y UTF-8 no significan lo mismo. Unicode se refiere al conjunto de caracteres, mientras que UTF-8 y UTF-16 son las codificaciones que convierten ese conjunto en una secuencia de bytes.
  • Lo que en Windows se llama «Shift_JIS» conviene pensarlo, en la práctica, como CP932 o la página de códigos japonesa de la familia Windows, para que la conversación no se desvíe.
  • Con solo decir «UTF-8 にした» (lo convertí a UTF-8) aún no basta como especificación. Solo se convierte en una regla operativa cuando también se decide si lleva BOM o no y el código de salto de línea.
  • El origen de la confusión no es el japonés en sí, sino que varias suposiciones con historias distintas conviven en el mismo Windows.

Al trabajar con texto en Windows, el punto de partida es distinguir primero estos 4 aspectos.

  1. ¿Cuál es la secuencia de bytes de ese archivo?
  2. ¿Con qué codificación de caracteres se escribió?
  3. ¿Con qué codificación de caracteres se está leyendo?
  4. ¿El salto de línea es CRLF o LF?

Con solo distinguir esto, resulta mucho más fácil no perderse.

2. Desglosando la terminología

2.1 ¿En qué se diferencian Unicode, UTF-8, UTF-16 y CP932?

Lo más rápido es desglosar primero la terminología una vez.

Término A qué se refiere Ejemplo Confusión habitual
Unicode Marco para representar caracteres mediante números U+3042 () Se cree que es lo mismo que UTF-8
UTF-8 Codificación de caracteres que convierte Unicode en una secuencia de bytes E3 81 82 Se cree que es el propio Unicode
UTF-16LE Codificación de caracteres que convierte Unicode en una secuencia de bytes 42 30 Se confunde con la notación Unicode de los menús
CP932 Página de códigos heredada de la familia japonesa de Windows 82 A0 Se cree que es exactamente lo mismo que Shift_JIS
CRLF / LF Secuencia de bytes que separa líneas 0D 0A / 0A Se cree que es un tipo de codificación de caracteres
BOM (Byte Order Mark) Secuencia de bytes identificadora al inicio del archivo EF BB BF, entre otras Se cree que es el propio nombre de la codificación

Por ejemplo, incluso para un solo carácter como , la secuencia de bytes cambia según la codificación.

Carácter: あ

UTF-8    : E3 81 82
CP932    : 82 A0
UTF-16LE : 42 30

Lo importante es que el carácter y la secuencia de bytes son cosas distintas. Las aplicaciones manejan en pantalla algo que parece un «carácter», pero al guardar o transmitir, en última instancia intercambian secuencias de bytes. Los incidentes casi siempre ocurren en el límite de esa conversión.

2.2 Cómo entender Shift_JIS y CP932

En el terreno, es habitual llamar «Shift_JIS» de forma genérica a los archivos de texto del Windows japonés. Como conversación se entiende, pero en la práctica es un poco impreciso.

Si se quiere ser más preciso respecto al texto heredado en japonés de Windows, es más seguro pensarlo como CP932, o como la página de códigos japonesa de la familia Windows.

Si esto se trata con imprecisión, conversaciones como las siguientes se desalinean.

  • Se pidió «guárdalo en Shift_JIS», pero la otra parte asumía el CP932 del lado de Windows
  • En el lado de Linux/macOS se trató como shift_jis, pero en parte de los archivos procedentes de Windows la reproducción no coincidía
  • Se indicó guardar en «ANSI», pero qué página de códigos era eso dependía del entorno

Por eso, en las especificaciones y notas de investigación es más seguro escribir, en la medida de lo posible, de la siguiente manera.

  • CP932 en lugar de Shift_JIS
  • ACP (active code page) / en un entorno japonés, normalmente CP932 en lugar de ANSI
  • Concretar como UTF-8 no BOM, LF en lugar de simplemente texto

2.3 La trampa de los términos ANSI, Unicode y UTF-8N

En el entorno de Windows, las etiquetas de los términos también son causa de confusión.

Estos tres son especialmente confusos.

  • ANSI Aparece en la interfaz de Windows y en explicaciones antiguas, pero no es ASCII. En la mayoría de los casos se refiere a la página de códigos activa de esa máquina (ACP).
  • Unicode En algunos editores y herramientas, el término Unicode del menú puede significar UTF-16LE. Aunque le digan que se «guardó en Unicode», no necesariamente es UTF-8.
  • UTF-8N A veces se ve en editores del ámbito japonés, pero normalmente es una etiqueta de interfaz para distinguir UTF-8 sin BOM. No es el nombre oficial de una codificación de caracteres.

Es decir, en Windows el mismo término puede tener un significado distinto según la herramienta. Este es el primer gran punto de confusión.

2.4 Qué es el BOM y por qué también aparece en UTF-8

BOM es la abreviatura de Byte Order Mark (marca de orden de bytes) y se refiere al código U+FEFF colocado al inicio de un archivo o flujo. Tal como indica su nombre, su función original es indicar el orden en que se disponen los bytes.

UTF-16 y UTF-32 representan un carácter mediante un bloque de 2 o 4 bytes, por lo que es necesario indicarle a quien lee si ese bloque se ordena «desde el byte de menor peso (little-endian)» o «desde el byte de mayor peso (big-endian)». Por eso se coloca un BOM al principio, y el orden de bytes de ese BOM indica que el mismo orden se mantendrá en adelante.

Secuencia de bytes inicial Significado
FF FE UTF-16 little-endian
FE FF UTF-16 big-endian
EF BB BF UTF-8

Aquí surge la duda: si UTF-8 opera en unidades de 1 byte y por tanto no debería tener un problema de orden, ¿por qué lleva BOM?

La razón es que el BOM de UTF-8 no se usa para el orden de bytes, sino como una marca (firma) que indica «este archivo es UTF-8». Como UTF-8 es compatible con ASCII, si el contenido son solo caracteres alfanuméricos no se puede distinguir de una página de códigos heredada. Si se coloca EF BB BF al principio, quien lee puede determinar que «debe leerse como UTF-8 y no como la página de códigos activa».

Visto desde el lado contrario, esto es lo siguiente.

  • Ventaja de añadir el BOM: es menos probable que quien lee se equivoque al deducir la codificación de caracteres. En particular, Windows PowerShell 5.1 lee los archivos de script sin BOM como si estuvieran en la página de códigos activa, por lo que los scripts con caracteres no ASCII se corrompen si no llevan BOM.
  • Desventaja de añadir el BOM: se agregan 3 bytes adicionales al principio. En los sistemas que desconocen el BOM, se trata como si al inicio de la primera línea se hubiera mezclado un carácter invisible. Incidentes como que solo el nombre de la primera columna de la cabecera de un CSV no coincida, o que la línea #! de un script de shell no se reconozca, se originan aquí.

Es decir, el BOM de UTF-8 no es una cuestión de «es correcto o incorrecto añadirlo», sino un parámetro de configuración que se decide según quién vaya a leer el archivo. Precisamente por eso, como se ve en el apartado 7.1, es necesario decidir no solo «convertirlo a UTF-8», sino también «si lleva BOM o no».

3. Por qué se producen los caracteres corruptos

3.1 La verdadera causa de los caracteres corruptos

La verdadera causa de los caracteres corruptos es bastante simple.

  1. Convertir una cadena de caracteres en una secuencia de bytes con una determinada codificación
  2. Volver a convertir esa secuencia de bytes en una cadena de caracteres con una codificación distinta
  3. Si las suposiciones no coinciden, el resultado es una cadena de caracteres distinta

Por ejemplo, si se guarda en UTF-8, la secuencia de bytes queda así.

E3 81 82

Si se lee esto como UTF-8, es , pero si se lee bajo la suposición de CP932, aparece como una cadena distinta similar a 縺�. Lo que está roto en este caso no es «el japonés», sino la suposición de decodificación.

Si hay que resumir los caracteres corruptos en una sola línea, es esto:

Se leyó la misma secuencia de bytes con una codificación de caracteres distinta.

Cómo la misma secuencia de bytes se convierte en un carácter correcto o en uno corruptoUn carácter japonés se codifica en UTF-8 como la secuencia de bytes E3 81 82. Si esa secuencia se decodifica como UTF-8 se recupera el carácter original, pero si se decodifica como CP932 se obtiene una cadena irreconocible, porque la suposición de lectura no coincide.Codificar y guardar en UTF-8Decodificar como UTF-8Decodificar como CP932Un carácter japonésSecuencia de bytes E3 81 82Esto es todo lo que hay en el archivoCarácter original recuperado ── la suposición coincideCadena irreconocible (caracteres corruptos) ── la suposición no coincide

Figura 1: En las dos bifurcaciones, el contenido del archivo (la secuencia de bytes) es el mismo. Lo único que cambia es la suposición que aplica quien lee

3.2 Distorsión visual y corrupción de datos son cosas distintas

Lo importante aquí es distinguir entre la etapa en la que todavía se puede revertir y la etapa en la que ya es difícil revertir.

Por ejemplo, con el siguiente flujo todavía existe la posibilidad de revertir.

  1. Abrir un archivo UTF-8 como si fuera CP932
  2. En pantalla se ve algo similar a 縺�
  3. Todavía no se ha guardado

En esta etapa, la secuencia de bytes original todavía se conserva en UTF-8. Si se vuelve a abrir con la codificación de caracteres correcta, es posible recuperarla.

Lo peligroso es el siguiente flujo.

  1. Leer erróneamente un archivo UTF-8 como si fuera CP932
  2. Guardar tal cual el contenido que se ve corrupto
  3. Se pierde la secuencia de bytes original en UTF-8

Llegados a este punto, ya no es una distorsión visual, sino una corrupción de datos.

El punto de inflexión entre distorsión visual y corrupción de datosUn archivo UTF-8 abierto bajo la suposición de CP932 produce solo una distorsión visual en pantalla mientras la secuencia de bytes original se conserva, pero si el contenido mal leído se guarda tal cual, la secuencia de bytes original se pierde y el resultado es una corrupción de datos irreversible.Abrir bajo la suposición de CP932Volver a abrirGuardar tal cualArchivo guardado en UTF-8La secuencia de bytes es E3 81 82En pantalla se ve una cadena irreconocible= distorsión visual. La secuencia de bytes sigue siendo UTF-8Si se especifica la codificación correcta, se recupera el originalSe reescribe con CP932 la cadena mal leída= corrupción de datos. Se pierde la secuencia de bytes originalAunque luego se sepa cuál era la codificación correcta, ya no se puede recuperar

Figura 2: El punto de inflexión es un único paso: si se volvió a abrir o si se guardó. En una investigación, hay que confirmar esto primero siempre

En la práctica, es importante no resumirlo todo en la frase «se corrompió el texto», sino distinguir al menos estos dos puntos.

  • ¿La secuencia de bytes en sí sigue siendo correcta?
  • ¿El contenido mal leído ya se volvió a guardar?

3.3 Convertir a caracteres no representables es irreversible

Otro caso peligroso es cuando se convierte una cadena Unicode a una página de códigos más limitada, como CP932.

En ese momento, si se incluyen caracteres que no existen en el destino, ocurre alguna de las siguientes situaciones.

  • Se sustituye por ?
  • Se inserta un carácter de reemplazo
  • Se produce un error de conversión
  • Se aproxima a otro carácter cercano

Por ejemplo, algunos emojis o kanji ampliados no se pueden convertir directamente a CP932. Este tipo de incidente debe analizarse no en función de «si se puede leer», sino de si, tras una conversión de ida y vuelta, se recupera el original.

Una vez perdida, la información no se recupera aunque después se conozca la codificación correcta.

4. Las diferencias entre los caracteres de salto de línea

4.1 CRLF / LF / CR

El salto de línea también es una secuencia de bytes.

  • CR = carriage return = 0D
  • LF = line feed = 0A
  • En los archivos de texto de Windows, CRLF (0D 0A) es lo tradicional
  • En los sistemas Linux/Unix, LF (0A) es lo habitual
  • CR solo puede aparecer en contextos antiguos, como los sistemas Mac clásicos

En forma de tabla, queda así.

Salto de línea Secuencia de bytes Contexto principal
CRLF 0D 0A Archivos de texto tradicionales de Windows, herramientas heredadas
LF 0A Linux / macOS / muchas herramientas de desarrollo
CR 0D Datos heredados bastante antiguos

4.2 El salto de línea es un problema distinto de la codificación de caracteres

Este punto es bastante importante.

El código de salto de línea es un problema distinto de la codificación de caracteres.

Incluso en un mismo archivo UTF-8, el salto de línea puede ser CRLF o LF. Por ejemplo, para un contenido «A, salto de línea, B», la secuencia de bytes cambia de la siguiente manera.

UTF-8 + LF   : 41 0A 42
UTF-8 + CRLF : 41 0D 0A 42

Es decir,

  • Es UTF-8, pero solo el salto de línea difiere
  • Es CP932, pero el salto de línea es LF
  • Es UTF-16LE, pero el salto de línea es CRLF

son situaciones perfectamente posibles.

Por eso, cuando se dice «lo convertí a UTF-8 pero sigue siendo distinto», en realidad puede ser que no sea la codificación de caracteres, sino solo el salto de línea, lo que está desalineado.

4.3 \n y la secuencia de bytes de salto de línea en el archivo no siempre coinciden

Desde el punto de vista de un programador, este es un punto que genera confusión de forma discreta.

El hecho de escribir \n en el código fuente no significa que en el archivo aparezca necesariamente solo 0A. Según el lenguaje, el runtime o el modo de texto de la API de E/S, en Windows \n puede convertirse en CRLF.

Es decir, lo siguiente puede quedar desalineado.

  • La representación del salto de línea en el código fuente
  • La cadena de caracteres en tiempo de ejecución
  • La secuencia de bytes guardada en el archivo
  • El salto de línea que se ve en el editor

Por esto ocurren incidentes como «pensaba que había escrito LF, pero el archivo tenía CRLF».

Los editores recientes manejan LF solo con normalidad, pero las herramientas periféricas, las aplicaciones heredadas y las operaciones empresariales todavía mantienen la suposición de CRLF. Por eso, el problema del salto de línea no es «cosa del pasado»: sigue apareciendo con normalidad en la práctica actual.

5. Por qué la confusión es especialmente frecuente en Windows

5.1 Unicode y las páginas de códigos heredadas coexisten

Esta es la razón principal por la que Windows resulta complicado.

En Windows coexisten dos caminos:

  • el que usa Unicode
  • el que trabaja basado en páginas de códigos

Las aplicaciones más recientes, la Web y los recursos multiplataforma tienden a inclinarse hacia UTF-8, mientras que en los CSV, TXT, registros, el entorno de Excel y las integraciones de sistemas empresariales antiguos todavía persiste CP932. Además, en algunas salidas y en el entorno de ciertas API, UTF-16LE también aparece con normalidad.

Es decir, dentro de una sola máquina Windows coexisten múltiples culturas de texto.

5.2 Las etiquetas no están unificadas

Lo que aumenta la confusión no es la tecnología en sí, sino el desajuste de las etiquetas.

  • Se dice «Shift_JIS», pero en realidad es CP932
  • Se dice «ANSI», pero en realidad es la página de códigos activa
  • Se dice «Unicode», pero en realidad es UTF-16LE
  • Se dice «UTF-8», pero en realidad todavía no está definido si lleva BOM o no
  • Aparecen etiquetas propias de cada editor, como «UTF-8N»

Si esto se deja ambiguo, la conversación parece entenderse, pero en realidad las cosas no coinciden.

5.3 Con solo ASCII, el problema queda oculto

Este también es un factor importante.

Como UTF-8 es compatible con el rango ASCII, un archivo que solo contiene caracteres alfanuméricos y símbolos puede «leerse más o menos bien» incluso bajo una suposición incorrecta. Del lado de CP932 también, el rango equivalente a ASCII no se corrompe visualmente con facilidad, por lo que el problema no sale a la superficie.

Como resultado, se produce una situación como esta.

  • Un archivo de configuración solo en inglés se ve sin problemas
  • Se rompe en el momento en que se añade una sola línea en japonés
  • Un problema que estuvo latente todo el tiempo se manifiesta por primera vez durante la operación

Por eso, los incidentes de codificación de caracteres suelen parecer como si «funcionaba hasta ayer, pero hoy se rompió de repente». En realidad, en muchos casos la trampa ya estaba ahí desde antes, y simplemente se hizo visible en el momento en que entró un carácter no ASCII.

5.4 El contenido del archivo, el nombre del archivo, la consola y el archivo fuente son capas distintas

En Windows, si se agrupa todo lo siguiente bajo el nombre «codificación de caracteres», surge confusión.

  • Nombre de archivo / ruta
  • Contenido del archivo
  • Visualización en la consola
  • La codificación del propio archivo de código fuente
  • El formato de la cadena de caracteres en tiempo de ejecución
  • La visualización en el portapapeles o en los componentes de la interfaz gráfica

Por ejemplo, aunque el nombre de archivo en japonés se vea con normalidad, el contenido del archivo puede estar guardado en CP932. A la inversa, aunque el archivo en sí esté en UTF-8, si la página de códigos de la consola no coincide, solo la visualización se corromperá.

Una operación como chcp 65001 también actúa, básicamente, sobre la suposición del lado de la consola, y no cambia la secuencia de bytes de los archivos existentes.

Además, aunque el archivo de código fuente esté en UTF-8, el archivo de registro que se escribe en tiempo de ejecución no necesariamente estará en UTF-8. Es necesario distinguir cada vez de qué capa de codificación de caracteres se está hablando.

Además, en el Windows japonés, \ puede verse como el símbolo del yen, lo cual también tiende a mezclarse con el tema de la codificación de caracteres. Sin embargo, en la mayoría de los casos esto es un problema de la fuente de visualización o del glifo, y no significa que haya cambiado el sentido del separador de rutas ni el de la secuencia de escape.

5.5 El BOM y el código de salto de línea también actúan como ejes independientes

Con decir simplemente «UTF-8» todavía solo se ha decidido la mitad.

En la práctica, lo siguiente también influye.

  • Si lleva BOM o no
  • Si el salto de línea es CRLF o LF

Por ejemplo, incluso dentro de un mismo UTF-8,

  • hay herramientas de Windows que solo pueden leerlo si lleva BOM
  • hay procesos de tipo Unix en los que, si lleva BOM, se añade un carácter de más en la primera columna
  • hay herramientas del lado heredado que tienen dificultades si solo hay LF
  • con CRLF, los scripts de shell o el diff pueden ensuciarse

de esta manera, aunque la codificación de caracteres coincida, el incidente todavía puede ocurrir.

5.6 Las herramientas cambian las cosas por su cuenta

Lo que complica aún más las cosas es que las herramientas locales cambian las cosas de forma implícita.

  • El editor hace una detección automática
  • Al guardar, añade o quita el BOM
  • Git convierte entre CRLF y LF
  • El shell o los comandos guardan con la codificación de caracteres predeterminada
  • La exportación a CSV usa una página de códigos inesperada
  • Los valores predeterminados difieren entre versiones de PowerShell u otras herramientas

Es decir, aunque quien trabaja no lo haya especificado, en la práctica de Windows alguna capa añade suposiciones por su cuenta.

Esta es la verdadera causa de «no cambié nada, pero se rompió». En realidad, en no pocos casos, no es la persona sino el valor predeterminado de la herramienta el que hace el cambio.

6. Patrones habituales de incidentes

Si se resumen los incidentes típicos en una tabla, queda así.

Escenario Lo que realmente está desalineado Síntoma típico
Una herramienta heredada de Windows interpreta un archivo de configuración UTF-8 no BOM como ANSI/CP932 La suposición de decodificación Solo el japonés se corrompe
Se pasa un CSV en CP932 a un sistema que asume UTF-8 La suposición de decodificación , errores de decodificación, japonés incomprensible
Se pasa un registro en UTF-16LE a una herramienta de texto de tipo Unix La suposición de codificación de caracteres Se mezclan bytes NUL y el archivo parece binario
Un archivo fuente en LF se convierte a CRLF en otro entorno La suposición de salto de línea Diferencias enormes de fin de línea, fallos en scripts
Se guarda tal cual un contenido mal leído La secuencia de bytes en sí se convierte en algo distinto Corrupción de datos irreversible
La especificación se limita a decir «exporte un CSV» La interfaz no está definida Se lee en Excel pero se rompe en otra herramienta
Solo se decide «unificar en UTF-8» El BOM y el salto de línea no están definidos Solo fallan algunas herramientas

El patrón especialmente peligroso es aquel en el que se ve la distorsión visual y, aun así, se guarda tal cual, sellando el incidente.

7. Reglas prácticas para reducir incidentes

A partir de aquí, veremos qué reglas operativas conviene definir para reducir los incidentes.

7.1 Defina la línea base para texto nuevo

Para los archivos nuevos, es razonable considerar UTF-8 como primera opción. Sin embargo, con eso solo no basta.

Como mínimo, es más seguro decidir también lo siguiente.

  • Si es UTF-8 with BOM o UTF-8 no BOM
  • Si el salto de línea es CRLF o LF
  • Quién va a leer el archivo
  • Si se necesita compatibilidad con herramientas heredadas de Windows
  • Si también lo leerán Linux, macOS, CI o contenedores

Por ejemplo, para código fuente o archivos de configuración pensados para ser multiplataforma, UTF-8 no BOM + LF suele ser la primera opción. Por otro lado, si es necesario ajustarse a herramientas antiguas de Windows o a una operación ya existente, todavía puede ser necesario usar UTF-8 with BOM o CP932 + CRLF.

Lo importante es decidirlo en función de con quién se va a intercambiar el archivo, más que basándose en generalidades sobre «qué es lo correcto».

7.2 No modifique por su cuenta los archivos heredados existentes

Si un archivo existente está en CP932, es más seguro no convertirlo a UTF-8 de forma incidental durante una pequeña modificación cotidiana.

Una operación del lado seguro sería la siguiente.

  • Mantener la codificación de caracteres, el BOM y el salto de línea originales en los archivos existentes
  • Separar la conversión de codificación de caracteres como una tarea de migración independiente
  • Confirmar el objeto de conversión y el uso posterior antes de hacer una conversión masiva

Los incidentes de caracteres corruptos suelen originarse en la buena intención de «modernizar de paso».

7.3 Trate la codificación de caracteres y el salto de línea como parte de la interfaz

En los CSV, TXT, registros, archivos de configuración y protocolos simples, no solo el contenido, sino el propio formato de texto es la interfaz.

En la especificación, es más seguro incluir como mínimo lo siguiente.

  • Codificación de caracteres
  • Presencia o ausencia de BOM
  • Código de salto de línea
  • Presencia o ausencia de cabecera
  • Especificación de las comillas y el carácter separador
  • Con qué herramienta se verificó

Por ejemplo, las tres letras «CSV» por sí solas no bastan. Solo cuando se escribe algo como UTF-8 with BOM, CRLF, separado por comas, con cabecera, la conversación deja de desviarse.

7.4 Sea explícito en los límites de lectura y escritura

También del lado del código, es más seguro no depender de valores predeterminados implícitos.

  • Especificar explícitamente la codificación de caracteres al leer y escribir archivos
  • Tener en cuenta la codificación de caracteres también al intercambiar texto entre procesos
  • Fijar también el salto de línea como parte de la especificación en los procesos de exportación e importación
  • No usar una redirección de shell improvisada como ruta de producción

En particular en Windows, «haber podido guardar» y «haber guardado con la secuencia de bytes correcta» no son lo mismo.

7.5 Comparta también las reglas de Git y del editor

Git no es una herramienta que corrija automáticamente la codificación de caracteres. En cambio, en cuanto al código de salto de línea, sí puede intervenir una conversión.

Por eso, es más seguro decidir lo siguiente a nivel de repositorio.

  • Si el código fuente usará LF como base
  • Si se permitirá CRLF para textos exclusivos de Windows
  • Cómo fijarlo mediante .gitattributes
  • Cómo compartir la configuración del editor

Es importante pensar la codificación de caracteres y el código de salto de línea por separado. Aunque Git alinee los saltos de línea, los incidentes de codificación de caracteres siguen ahí.

7.6 No se quede en «se corrompió el texto»; diga qué se desalineó

En el terreno, esta forma de reformular suele funcionar bien.

  • Forma poco útil: «se corrompió el texto»
  • Forma útil: «parece que se está abriendo un archivo UTF-8 no BOM bajo la suposición de CP932»
  • Forma poco útil: «el final de línea está raro»
  • Forma útil: «un archivo en LF se está convirtiendo a CRLF, lo que aumenta las diferencias»

Con solo poder decir qué se desalineó, la velocidad de la investigación cambia considerablemente.

7.7 Cómo comprobarlo: puntos clave por herramienta

Las reglas vistas hasta aquí solo funcionan si van acompañadas de una forma de comprobarlas. Para las tres herramientas más usadas, resumimos «dónde ver la codificación actual» y «dónde cambiarla».

Herramienta Dónde ver la codificación actual Dónde cambiarla
VS Code En la barra de estado, abajo a la derecha. Aparecen la codificación, como UTF-8, junto con la indicación de salto de línea CRLF/LF Al hacer clic en la codificación mostrada en la barra de estado aparecen las opciones de volver a abrir o volver a guardar. El valor predeterminado se define en files.encoding, en la pantalla de configuración
Bloc de notas La barra de estado muestra la codificación del documento Se abre «Archivo» y luego «Guardar como», y se elige en el campo «Codificación» del cuadro de diálogo
PowerShell Lo más fiable es ver directamente los bytes iniciales del archivo (comando más abajo) El parámetro -Encoding del cmdlet que escribe el archivo. El valor predeterminado se define en $PSDefaultParameterValues

VS Code

La codificación predeterminada de VS Code es UTF-8 (sin BOM). Para cambiarla en un archivo concreto, se hace clic en la indicación de la barra de estado y se elige si el archivo abierto se va a volver a abrir con otra codificación, o si se va a volver a guardar con otra codificación. Si solo hubo una lectura errónea, lo primero es volver a abrirlo, lo cual corresponde al criterio del apartado 3.2.

Para cambiar el valor predeterminado, se especifica files.encoding en la configuración. Los valores incluyen utf8 (sin BOM), utf8bom (con BOM), utf16le, windows1252, entre otros. También se puede diferenciar por lenguaje.

{
  "files.encoding": "utf8",
  "[powershell]": {
    "files.encoding": "utf8bom"
  }
}

El criterio del apartado 2.4 de usar BOM únicamente en los scripts que se ejecutan con Windows PowerShell 5.1 se puede expresar mediante esta configuración por lenguaje.

Bloc de notas

A partir de la Build 18963 de Windows 10, el Bloc de notas tiene una columna en la barra de estado que muestra la codificación del documento, y el valor predeterminado para los archivos nuevos es UTF-8 (sin BOM). Al guardar, se abre «Archivo» y luego «Guardar como», y se elige en el campo «Codificación» del cuadro de diálogo. Este campo permite elegir incluso si lleva BOM o no, de modo que aquí se refleja la política decidida en el apartado 7.1.

Cuando se recibe un reporte de que «al abrirlo con el Bloc de notas se corrompió el texto», lo más rápido es revisar primero este campo y la indicación de la barra de estado.

PowerShell

Los valores predeterminados de PowerShell varían mucho según la versión. Sin saber esto, es habitual recibir consultas del tipo «al generar la salida con PowerShell, la herramienta no puede leerla».

  • PowerShell 6 en adelante (la serie PowerShell 7): el valor predeterminado de toda salida de texto es utf8NoBOM, es decir, UTF-8 sin BOM.
  • Windows PowerShell 5.1: el valor predeterminado no está unificado entre los distintos cmdlets.

Si se resumen en una tabla los principales de la versión 5.1, queda así.

Comando Valor predeterminado al escribir
Out-File, operadores de redirección > >> UTF-16LE
Set-Content, Add-Content (cuando el destino está vacío o no existe) Default (página de códigos activa; en un entorno japonés, CP932)
Export-Csv Ascii
Start-Transcript UTF-8 with BOM
New-Item -Type File -Value UTF-8 no BOM

El lado de la lectura también tiene valores predeterminados. Cuando no hay BOM, Get-Content y el motor de PowerShell, al leer un archivo de script, lo asumen como Default (página de códigos activa), mientras que Import-Csv y Select-String lo asumen como UTF-8. Es decir, incluso para el mismo archivo, la suposición cambia según con qué cmdlet se lea.

Para saber si el archivo que tiene a mano lleva BOM, basta con mirar los bytes iniciales.

# PowerShell 7: muestra los primeros 3 bytes en hexadecimal
Get-Content -Path .\sample.txt -AsByteStream -TotalCount 3 | Format-Hex

# Windows PowerShell 5.1 no tiene -AsByteStream, así que se usa -Encoding Byte
Get-Content -Path .\sample.txt -Encoding Byte -TotalCount 3 | Format-Hex

Si el inicio es EF BB BF, es UTF-8 with BOM; si es FF FE, es UTF-16LE; en cualquier otro caso, no lleva BOM. Es la misma lectura que la tabla del apartado 2.4.

Si se quiere fijar explícitamente el valor predeterminado, se usa $PSDefaultParameterValues.

# Fija en UTF-8 el valor predeterminado de todos los cmdlets que tienen el parámetro Encoding
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

Aquí hay una trampa entre versiones. Aunque la cadena utf8 sea la misma, en Windows PowerShell 5.1 significa UTF-8 with BOM, mientras que en PowerShell 6 en adelante significa UTF-8 no BOM. Si se quiere fijar también la presencia o ausencia de BOM, es más seguro especificar explícitamente utf8BOM / utf8NoBOM, disponibles desde PowerShell 6 en adelante.

Además, $OutputEncoding es la codificación de caracteres usada para el intercambio con programas externos, y no afecta a la codificación que usan la redirección o los cmdlets al guardar en un archivo. Este es un punto fácil de confundir.

8. Investigue caracteres corruptos y diferencias de fin de línea con estas 5 preguntas

Si se pierde el rumbo durante la investigación, lo más rápido es volver a estas 5 preguntas.

  1. ¿Cuál es ahora mismo la secuencia de bytes de este archivo?
    • ¿Es UTF-8?
    • ¿Es UTF-8 with BOM?
    • ¿Es CP932?
    • ¿Es UTF-16LE?
  2. ¿Quién lo escribió primero, y bajo qué suposición?
    • Editor
    • Aplicación heredada
    • Exportación desde Excel
    • Shell/script
    • Proceso por lotes/middleware
  3. ¿Quién lo está leyendo ahora, y bajo qué suposición?
    • Detección automática del editor
    • Página de códigos de la consola
    • Codificación de caracteres predeterminada de la biblioteca
    • Especificación del lado de importación
  4. ¿Cuáles son el BOM y el salto de línea?
    • Con o sin BOM
    • CRLF/LF
  5. ¿El contenido mal leído ya se guardó?
    • ¿Es solo una cuestión de visualización todavía?
    • ¿Ya se volvió a guardar y se perdió la secuencia de bytes?

Cuando se completan estas 5 preguntas, la causa suele quedar a la vista.

9. Resumen

Que la codificación de caracteres y el salto de línea en Windows parezcan complicados no se debe a que el japonés en sí sea difícil. Es porque la secuencia de bytes, la codificación de caracteres, el BOM, el código de salto de línea y los valores predeterminados de las herramientas existen por separado, y además, en Windows coexisten culturas de texto antiguas y nuevas.

En especial, conviene recordar estos 6 puntos.

  • Los caracteres corruptos son el resultado de leer la misma secuencia de bytes con una codificación distinta
  • El problema del salto de línea es un asunto en un eje distinto al de la codificación de caracteres
  • No confíe demasiado, tal cual, en los términos Shift_JIS, CP932, ANSI o Unicode
  • Con «lo convertí a UTF-8» no basta: también hacen falta el BOM y el salto de línea
  • Distinga entre la distorsión visual y la corrupción de datos ya guardada
  • En las especificaciones, escriba algo como UTF-8 no BOM, LF en lugar de simplemente texto

En resumen, lo práctico al trabajar con texto en Windows es pensar que no se trata de «una cuestión de cadenas de caracteres», sino de cómo alinear los acuerdos sobre la secuencia de bytes.

10. Artículos relacionados

11. Referencias

  1. Microsoft Learn, Code Page Identifiers - Win32 apps https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
  2. Microsoft Learn, about_Character_Encoding - PowerShell https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-7.6
  3. Microsoft Learn, Understanding file encoding in VS Code and PowerShell https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding?view=powershell-7.6
  4. W3C Internationalization, Character encodings: Essential concepts https://www.w3.org/International/articles/definitions-characters/
  5. Git documentation, gitattributes https://git-scm.com/docs/gitattributes
  6. Git documentation, git-config https://git-scm.com/docs/git-config
  7. Microsoft Learn, The Unicode standard - Globalization (la secuencia de bytes del BOM y el uso del BOM de UTF-8 como firma) https://learn.microsoft.com/en-us/globalization/encoding/unicode-standard
  8. Microsoft Learn, What was new in 20H1 Windows 10 Insider Preview Builds (la adopción de UTF-8 como predeterminado en el Bloc de notas en la Build 18963, y la adición de la indicación de codificación en la barra de estado) https://learn.microsoft.com/en-us/previous-versions/windows-insider/archive/new-in-20h1

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Por qué se producen los caracteres corruptos?
Porque se lee la misma secuencia de bytes con una codificación de caracteres distinta de la que se usó al escribirla. Por ejemplo, si se guarda `あ` en UTF-8, se obtiene la secuencia de bytes E3 81 82, pero si esta se lee bajo la suposición de CP932, aparece como una cadena distinta similar a `縺`. En este caso, lo que está roto no es el japonés, sino la suposición de decodificación. Sin embargo, si el contenido mal leído se vuelve a guardar tal cual, se pierde la secuencia de bytes original y el resultado deja de ser una distorsión visual para convertirse en corrupción de datos, por lo que es importante volver a abrir el archivo con la codificación correcta antes de guardarlo.
¿Cuál es la diferencia entre CRLF y LF?
Es una diferencia en los bytes usados para separar líneas. CRLF son 2 bytes (0D 0A) y se ha usado tradicionalmente en los archivos de texto de Windows, mientras que LF es 1 byte (0A) y es habitual en Linux/macOS y en muchas herramientas de desarrollo. Lo importante es que el código de salto de línea es un problema distinto de la codificación de caracteres. Incluso en un mismo archivo UTF-8, el salto de línea puede ser CRLF o LF, así que cuando se piensa «lo convertí a UTF-8 pero sigue siendo distinto», a veces lo que está desalineado es solo el salto de línea, no la codificación.
¿Son lo mismo Shift_JIS y CP932?
En una conversación se entienden como equivalentes, pero en la práctica es más seguro distinguirlos. Si se quiere ser preciso respecto al texto heredado del Windows japonés, conviene pensarlo como CP932 o como la página de códigos japonesa de la familia Windows. De igual modo, en Windows, «ANSI» suele referirse a la página de códigos activa de esa máquina, y el «Unicode» que aparece en los menús de los editores a veces significa UTF-16LE. En las especificaciones y notas de investigación, escribir algo concreto como «UTF-8 no BOM, LF» ayuda a que la conversación no se desvíe.
¿Qué se debe definir en la especificación de un archivo de texto?
Con decir «lo convertí a UTF-8» no basta: solo se convierte en una regla operativa cuando también se decide la presencia o ausencia de BOM y el código de salto de línea. En archivos de intercambio como los CSV o los registros, es más seguro especificar también la codificación, la presencia de BOM, el salto de línea, la presencia de cabecera y el carácter separador. Para código fuente o configuraciones pensados para ser multiplataforma, UTF-8 no BOM + LF suele ser la primera opción, mientras que si hay que ajustarse a herramientas antiguas de Windows, todavía puede ser necesario usar UTF-8 with BOM o CP932 + CRLF.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog