Saltar al contenido principal

File Read Utilities

Paquete: @tiendana/ngx-core/validators

Utilidades RxJS para lectura de archivos, conversión de formatos y manipulación de File objects.

Características​

✅ Lectura de File y Blob como ArrayBuffer o Data URL con FileReader, expuesta como Observable
✅ Detección del tipo real por cabecera binaria (getFileType)
✅ Conversión de URLs de imagen a Data URL o a File
✅ sanitizeFileName para limpiar nombres de archivo

import {
readAsArrayBuffer,
readAsDataURL,
getFileType,
urlToDataUrl,
urlImageToFile,
sanitizeFileName
} from '@tiendana/ngx-core/validators';

Funciones Disponibles​

readAsArrayBuffer​

Lee un File o Blob como ArrayBuffer usando FileReader.

Firma:

function readAsArrayBuffer(blob: Blob): Observable<any>

Parámetros:

  • blob: File o Blob a leer

Retorna: Observable que emite el ArrayBuffer y completa. Emite un error si el valor no es un File o Blob.

Uso:

import { readAsArrayBuffer } from '@tiendana/ngx-core/validators';

onFileSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
readAsArrayBuffer(file).subscribe(buffer => {
console.log('Buffer length:', buffer.byteLength);
});
}
}

readAsDataURL​

Lee un File o Blob como Data URL (base64).

Firma:

function readAsDataURL(blob: Blob): Observable<any>

Parámetros:

  • blob: File o Blob a leer

Retorna: Observable que emite el Data URL (data:...;base64,...) y completa. Emite un error si el valor no es un File o Blob.

Uso:

import { readAsDataURL } from '@tiendana/ngx-core/validators';

onImageSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
readAsDataURL(file).subscribe(dataUrl => {
// Usar dataUrl para preview de imagen
this.imagePreview = dataUrl as string;
});
}
}
tip

readAsDataURL es ideal para crear previsualizaciones de imágenes antes de subirlas al servidor.

getFileType​

Obtiene el tipo de un archivo leyendo su cabecera (magic numbers), no su extensión.

Firma:

function getFileType(arrayBuffer: ArrayBuffer, file?: File): string

Parámetros:

  • arrayBuffer: ArrayBuffer del archivo (usar con readAsArrayBuffer)
  • file: File opcional; solo se usa para escribir su extensión original en la consola

Retorna: 'png', 'jpeg', 'gif', 'pdf', 'xlsx' o 'unknown'

Cabeceras reconocidas (primeros 4 bytes):

ResultadoArchivos
pngPNG
jpegJPEG (cabeceras ffd8ffe0, e1, e2, e3 y e8)
gifGIF
pdfPDF
xlsxCualquier contenedor ZIP: .xlsx, .docx, .zip...
unknownTodo lo demás
Límites conocidos
  • svg y zip no se detectan nunca. Un SVG es texto (<svg ...) y su cabecera no coincide con ninguna regla; un ZIP real coincide primero con la regla de xlsx. No uses getFileType ni requiredFileType para aceptar SVG o ZIP.
  • Un .docx o un .zip devuelven 'xlsx': la cabecera de todos los formatos basados en ZIP es la misma.
  • Escribe en la consola (console.log) la cabecera, la extensión original y el tipo detectado en cada llamada.

Uso:

import { readAsArrayBuffer, getFileType } from '@tiendana/ngx-core/validators';

onFileSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
readAsArrayBuffer(file).subscribe(buffer => {
const realType = getFileType(buffer, file);

if (realType === 'unknown') {
alert('Tipo de archivo no soportado');
}
});
}
}

Para validar el tipo dentro de un formulario reactivo usa CustomValidators.requiredFileType, que se apoya en esta función.

urlToDataUrl​

Convierte una URL de imagen a Data URL (base64).

Firma:

function urlToDataUrl(imageUrl: string): Observable<string | ArrayBuffer>

Parámetros:

  • imageUrl: URL de la imagen

Retorna: Observable que emite el Data URL y completa

Uso:

import { urlToDataUrl } from '@tiendana/ngx-core/validators';

convertRemoteImage() {
urlToDataUrl('https://example.com/image.jpg').subscribe(
dataUrl => {
console.log('Base64:', dataUrl);
// Usar dataUrl para almacenar localmente, enviar a API, etc.
},
error => console.error('Error al convertir imagen:', error)
);
}
aviso

urlToDataUrl hace un fetch a la URL. Asegúrate de que la URL sea accesible y no tenga problemas de CORS.

urlImageToFile​

Convierte una URL de imagen a File object.

Firma:

function urlImageToFile(imageUrl: string): Observable<File>

Parámetros:

  • imageUrl: URL de la imagen

Retorna: Observable con el File object

Uso:

import { urlImageToFile } from '@tiendana/ngx-core/validators';

convertUrlToFile() {
urlImageToFile('https://example.com/photo.jpg').subscribe(
file => {
console.log('File name:', file.name);
console.log('File size:', file.size);
console.log('File type:', file.type);

// Usar file para asignar a FormControl
this.form.patchValue({ image: file });
},
error => console.error('Error al convertir a File:', error)
);
}

Características:

  • Extrae el nombre del archivo de la URL
  • Preserva el tipo MIME
  • Retorna un File object válido para FormData o FormControl

sanitizeFileName​

Elimina de un nombre de archivo todo carácter que no sea letra ASCII, dígito, espacio, guion o guion bajo, colapsa los espacios repetidos en uno y recorta los extremos.

Firma:

function sanitizeFileName(fileName: string): string

Parámetros:

  • fileName: Nombre de archivo a sanitizar

Retorna: Nombre sanitizado (solo a-z, A-Z, 0-9, espacio, - y _)

Uso:

import { sanitizeFileName } from '@tiendana/ngx-core/validators';

sanitizeFileName('mi archivo (copia) #1!.pdf'); // "mi archivo copia 1pdf"
sanitizeFileName('informe final '); // "informe final"
Elimina el punto de la extensión

El punto también es un carácter no permitido, así que sanitizeFileName('foto.png') devuelve 'fotopng'. Sanitiza solo el nombre base y vuelve a añadir la extensión:

const dot = file.name.lastIndexOf('.');
const safe = dot > 0
? sanitizeFileName(file.name.slice(0, dot)) + file.name.slice(dot)
: sanitizeFileName(file.name);

Las letras con tilde (á, ñ) tampoco están permitidas y se eliminan.

Casos de Uso Comunes​

Preview de Imagen antes de Subir​

import { readAsDataURL } from '@tiendana/ngx-core/validators';

imagePreview: string | null = null;

onImageSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
readAsDataURL(file).subscribe(dataUrl => {
this.imagePreview = dataUrl as string;
});
}
}
<input type="file" (change)="onImageSelect($event)" accept="image/*">
@if (imagePreview) {
<img [src]="imagePreview" alt="Preview">
}

Validar Tipo Real de Archivo​

import { readAsArrayBuffer, getFileType } from '@tiendana/ngx-core/validators';

validateFileType(file: File, allowedTypes: string[]) {
readAsArrayBuffer(file).subscribe(buffer => {
const realType = getFileType(buffer, file);

// Recuerda: JPEG es 'jpeg' (no 'jpg') y no se detectan 'svg' ni 'zip'
if (!allowedTypes.includes(realType)) {
alert(`Tipo de archivo no permitido. Se esperaba: ${allowedTypes.join(', ')}`);
}
});
}

// Uso
onFileSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
this.validateFileType(file, ['png', 'jpeg', 'pdf']);
}
}

Convertir URL Remota a File para Upload​

import { urlImageToFile } from '@tiendana/ngx-core/validators';

loadRemoteImage(url: string) {
urlImageToFile(url).subscribe(file => {
// Asignar a FormControl
this.form.patchValue({ avatar: file });

// O crear FormData para upload
const formData = new FormData();
formData.append('file', file);

this.http.post('/api/upload', formData).subscribe();
});
}

Manejo de Errores​

Las funciones que retornan Observables (readAsArrayBuffer, readAsDataURL, urlToDataUrl, urlImageToFile) pueden emitir errores:

import { readAsDataURL } from '@tiendana/ngx-core/validators';
import { catchError } from 'rxjs/operators';
import { of } from 'rxjs';

onFileSelect(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
readAsDataURL(file).pipe(
catchError(error => {
console.error('Error al leer archivo:', error);
return of(null);
})
).subscribe(dataUrl => {
if (dataUrl) {
this.imagePreview = dataUrl as string;
}
});
}
}

Notas Importantes​

  • RxJS: Todas las funciones, salvo getFileType y sanitizeFileName (síncronas), retornan Observables, no Promises
  • File vs Blob: Las funciones aceptan tanto File como Blob
  • CORS: urlToDataUrl y urlImageToFile requieren que la URL sea accesible sin restricciones CORS
  • Memoria: Al convertir a base64, el tamaño aumenta ~33%. Usar con archivos pequeños/medianos
  • Browser support: FileReader es compatible con todos los navegadores modernos

Ver También​