Una hoja de cálculo lleva dos capas de identidad. Está la cuadrícula de celdas, y están los metadatos del documento que viajan junto a ella: título, autor, empresa, palabras clave, las marcas de tiempo. Excel nunca muestra esa segunda capa en la cuadrícula, y sin embargo es la capa que Windows Search indexa, la que SharePoint lee para titular un documento, y por la que un sistema de gestión de registros archiva. Cuando un libro de trabajo generado hereda su Autor y su Título de la plantilla a partir de la cual se construyó, cada sistema posterior registra al diseñador de la plantilla como autor de cuatro mil estados de cuenta de clientes. Los metadatos no son correctos en ninguna parte y se consultan en todas
HotXLS expone esta capa como propiedades ordinarias a nivel de libro de trabajo en sus dos motores: la fachada BIFF para .xls y la fachada OOXML para .xlsx. Lees un campo después de abrir un archivo y escribes un campo antes de guardarlo. La biblioteca decide en qué contenedor físico aterriza el valor. Lo que vale la pena entender antes de escribir un generador es qué campos soporta realmente cada formato, dónde viven físicamente esos campos, y la única regla de compuerta que gobierna si un .xlsx registra algún metadato en absoluto
Dos formatos, dos modelos de almacenamiento
La razón por la que una biblioteca de hojas de cálculo necesita dos implementaciones de metadatos, y la razón por la que las herramientas a medio terminar estampan correctamente un formato y olvidan el otro, es que .xls y .xlsx guardan sus propiedades en lugares sin relación. Un libro de trabajo BIFF las escribe en flujos de archivo compuesto OLE, principalmente el conjunto de propiedades SummaryInformation que es anterior al propio Excel, junto al registro WRITEACCESS dentro del flujo que nombra a quien guardó el archivo por última vez. Un libro de trabajo OOXML las guarda como partes XML dentro del paquete zip, divididas por propósito: docProps/core.xml contiene los campos Dublin Core (título, creador, asunto, palabras clave, fechas) y docProps/app.xml contiene los campos a nivel de aplicación como la empresa y la aplicación generadora, según ECMA-376 Parte 1
HotXLS aplana ambos modelos de almacenamiento en propiedades directas del objeto de libro de trabajo. Nunca abres un flujo de conjunto de propiedades ni editas una parte XML a mano. Asignas cadenas y fechas al libro de trabajo, y el contenedor correcto se materializa para el formato en que guardes
Estampar libros de trabajo generados desde el registro de negocio
Del lado XLSX, TXLSXWorkbook expone Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application y AppVersion como cadenas, más Created y Modified como valores TDateTime donde cero significa sin establecer. La regla que cierra el agujero de la herencia cabe en una oración: asigna cada campo en cada ejecución, tomando los valores del registro de negocio en lugar de confiar en lo que la plantilla llevara por casualidad
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('statement-template.xlsx') <> 1 then
raise Exception.Create('Template not available');
// Sobrescribe cada campo: todo lo que quede sin tocar se
// hereda de quien haya diseñado la plantilla.
Book.Title := 'Account Statement 2026-06 / ACME Corp';
Book.Subject := 'Monthly account statement';
Book.Author := 'Billing Service 4.2';
Book.LastModifiedBy := 'Billing Service 4.2';
Book.Company := 'Northwind Financial';
Book.Category := 'Customer Delivery';
Book.Keywords := 'statement;billing;2026-06;acct-10024';
Book.Description := 'Generated document - manual edits are not retained';
Book.Created := Now;
Book.Modified := Now;
Book.SaveAs('statement-10024.xlsx');
finally
Book.Free;
end;
end;
El campo Keywords recompensa más reflexión de la que suele recibir. La infraestructura de búsqueda lo indexa literalmente, tanto Windows Search como SharePoint y la mayoría de los productos DMS, así que una convención separada por punto y coma que lleve el número de cuenta y el período convierte cada libro de trabajo entregado en un registro localizable sin ningún viaje a la base de datos. Ese mismo alcance es la trampa. Las propiedades viajan con cada copia del archivo, mucho más allá de los controles de acceso del sistema que las escribió, así que los datos personales no tienen lugar ahí
El par de marcas de tiempo tiene una semántica que vale la pena fijar en una política en lugar de dejarla al hábito. Created debería marcar el momento en que tu pipeline generó el documento y luego permanecer congelado. Modified es el campo que Excel actualiza cada vez que un destinatario guarda el archivo, así que una divergencia entre los dos después de la entrega es evidencia positiva de que alguien editó el libro de trabajo más adelante, lo que zanja más de una disputa sobre de quién son realmente los números de una hoja de cálculo reenviada. Una trampa se esconde en el estado sin establecer: es el valor literal cero, no una excepción ni un null, así que el código de auditoría tiene que comprobar el cero explícitamente. Formatea un TDateTime sin establecer sin esa protección y tus registros se llenan de una fecha de diciembre de 1899 confiadamente incorrecta
DocPropsTouched: el libro de trabajo que se envía sin docProps
Un indicador de solo lectura, DocPropsTouched, controla el escritor de propiedades de XLSX. Un libro de trabajo en el que nunca se asignó ninguna propiedad no produce ninguna parte docProps en absoluto; HotXLS se niega a escribir un esqueleto de metadatos vacío. El comportamiento es ordenado, y tiene dos consecuencias alrededor de las cuales vale la pena diseñar
El código de recepción del lado consumidor no debe suponer que core.xml existe en cada paquete. Una herramienta que lo exija de forma estricta rechazará archivos mínimos perfectamente válidos. Y si tu postura de cumplimiento exige que cada documento saliente lleve al menos una identidad de generador, esa exigencia se convierte en código en lugar de una propiedad del formato: asigna Application y Author incondicionalmente en la ruta de guardado, ya que un libro de trabajo sin tocar es completamente legal según la especificación mientras viola silenciosamente tu política
La superficie XLS heredada y la trampa de Comments
La fachada BIFF lleva el conjunto de campos más antiguo y pequeño: Title, Subject, Author, Keywords, Comments, Company y Manager, más LastSavedBy, un alias de UserName, que escribe el registro WRITEACCESS que Excel muestra cuando otro usuario tiene el archivo bloqueado
var
Legacy: IXLSWorkbook; // interfaz con conteo de referencias: sin Free manual
begin
Legacy := TXLSWorkbook.Create;
if Legacy.Open('archive-1999.xls') <= 0 then
raise Exception.Create('Cannot open archive file');
Legacy.Title := 'FY1999 ledger (migrated copy)';
Legacy.Author := 'Archive Migration Batch';
Legacy.Company := 'Northwind Financial';
Legacy.Comments := 'Migrated 2026-06-11; source retained in cold storage';
Legacy.LastSavedBy := 'migration-svc'; // registro WRITEACCESS de BIFF
Legacy.SaveAs('archive-1999-stamped.xls');
end;
Una colisión de nombres causa confusión recurrente. La propiedad Comments a nivel de documento aquí es la observación de texto libre que se muestra en el diálogo de propiedades del archivo. No tiene nada que ver con los comentarios de celda, que son objetos de la capa de dibujo adjuntos a rangos a través de una API completamente separada. Una revisión de código que acepta "ya escribimos Comments" sin comprobar a cuál se refiere ha aceptado una afirmación sobre la función equivocada, y eso ocurre más a menudo de lo que el nombre compartido sugeriría. Los dos comparten el nombre y ni un solo byte de almacenamiento
Leer metadatos en la recepción, y la brecha del sondeo
La lectura es simétrica. Después de Open, las mismas propiedades regresan pobladas desde el archivo, lo que convierte una auditoría de metadatos de libros de trabajo entrantes en un bucle corto
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open(FileName) = 1 then
begin
Writeln(Format('%s | title="%s" author="%s" created=%s',
[ExtractFileName(FileName), Book.Title, Book.Author,
FormatDateTime('yyyy-mm-dd', Book.Created)]));
if Book.Created = 0 then
Writeln(' no creation date recorded');
end;
finally
Book.Free;
end;
end;
Mientras lo haces, planifica en torno a una limitación. No hay un sondeo de solo propiedades. GetSheetNames puede listar hojas sin cargar un libro de trabajo, pero leer Title o Author implica un Open completo, así que la clasificación de metadatos a lo largo de un archivo histórico grande paga el costo de análisis completo en cada archivo. Del lado BIFF puedes recortar ese costo para auditorías de solo lectura estableciendo _DisableGraphics en true antes de abrir, lo que omite directamente la capa de dibujo. Encaja en un bucle que solo lee propiedades y estadísticas de celdas, y es exactamente lo incorrecto en el momento en que la misma instancia pudiera guardar, porque el contenido de dibujo omitido se descartaría. Cuando la estructura de hojas por sí sola puede prefiltrar el conjunto, siendo las exportaciones de una sola hoja lo obvio a omitir, las técnicas económicas de nuestro artículo sobre listado de hojas e inspección ligera reducen cuántos archivos llegan al pase costoso. Y en trabajos de estampado masivo, donde se escriben miles de salidas en lugar de inspeccionarlas, los patrones de rendimiento del lado de escritura de nuestro artículo sobre escrituras en streaming para trabajos por lotes se trasladan sin cambios, ya que la asignación de propiedades no agrega nada medible al tiempo de guardado
Cruzar formatos y contener la fuga
Las propiedades hacen el viaje de ida y vuelta limpiamente dentro de una sola fachada: abre un .xlsx, edítalo, guárdalo, y el conjunto regresa intacto. Cruzar formatos es donde la suposición de paridad se rompe, porque los conjuntos de campos de BIFF y OOXML no se alinean uno a uno. BIFF tiene Manager y ninguna marca de tiempo; OOXML tiene Category, Description y el par Created/Modified. Un convertidor que copia a ciegas pierde todo lo que el formato de destino no puede contener, así que mapea los campos explícitamente y pon el mapeo en tu lista de verificación de conversión junto a todo lo demás que no sobrevive al viaje
La fuga que abre la herencia de plantillas corre en la otra dirección: información que nunca quisiste enviar. Nombres de autor, etiquetas internas de proyecto aparcadas en las palabras clave, un título de borrador que nadie aprobó. La disciplina de sobrescribirlo todo del generador anterior es toda la defensa, y vale la pena verificarla como lo haría un externo, abriendo el diálogo de Propiedades al que cualquier cliente puede llegar o descomprimiendo el .xlsx y leyendo docProps/core.xml directamente desde el paquete. Lo que ves ahí es exactamente lo que ve cada indexador posterior
Esa visibilidad posterior es también la razón por la que unos pocos campos merecen más cuidado que el resto. Título, Autor, Palabras clave (que aparecen como Etiquetas) y Comentarios o Descripción cargan la mayor parte del peso de indexación en SharePoint y Windows Search. Un Título genuinamente distinto por documento, que lleve el período y la cuenta, hace más por la localizabilidad que cualquier esquema de nombres de carpeta apilado encima, y cuesta una asignación por guardado
Las propiedades de documento son el pulido profesional más barato que un libro de trabajo generado puede llevar, y el defecto más comúnmente enviado cuando nadie se hace cargo de ellas. Ambas superficies de propiedades descritas aquí pertenecen al componente HotXLS para Delphi, que las escribe de forma nativa para XLS y XLSX sin automatización de Excel