Tengo un archivo .\input.txt
como este:
aaa
bbb
ccc
Si lo leo usando TStrings.LoadFromFile
y lo escribo de nuevo (incluso sin aplicar ningún cambio) TStrings.SaveToFile
, crea una línea vacía al final del archivo de salida.
var
Lines : TStrings;
begin
Lines := TStringList.Create;
try
Lines.LoadFromFile('.\input.txt');
//...
Lines.SaveToFile('.\output.txt');
finally
Lines.Free;
end;
end;
Se puede observar el mismo comportamiento utilizando la TStrings.Text
propiedad que devolverá una cadena que contiene una línea vacía al final.
delphi
tstringlist
Fabrizio
fuente
fuente
\n
carácter y la función agrega\n
el archivo? ¿O la función agrega literalmente un\n
derecho después de uno existente\n
al final del archivo? POSIX requiere que los archivos de texto tengan todas sus líneas terminadas por un\n
, solo para su información. Un montón de software fue escrito para seguir algunas normas y por eso una gran cantidad de editores añadirá la terminación falta\n
al guardar archivos por defecto (por ejemplovim
, entornos de desarrollo, etc., todo de forma predeterminada hacer que sus archivos compatible con POSIX.)Respuestas:
Para Delphi 10.1 y posteriores hay una propiedad que
TrailingLineBreak
controla este comportamiento.fuente
TrailingLineBreak
propiedad tan pronto como actualice el IDE. +1 y aceptadoPara Delphi 10.1 (Berlín) o posterior, la mejor solución se describe en la respuesta de Uwe.
Para versiones anteriores de Delphi, encontré una solución creando una clase secundaria
TStringList
y anulando laTStrings.GetTextStr
función virtual, pero me alegrará saber si hay una mejor solución o si alguien más encontró algo incorrecto en mi soluciónInterfaz:
Implementación:
Ejemplo:
fuente
SetLength(Result, -2)
.GetTextStr
, siLength(Result)
es0
, entonces lo hacesSetLength(Result, -2)
, lo cual es malo. Podría ser el caso de que el efecto sea el mismoSetLength(Result, 0)
, pero no tengo ninguna garantía al respecto. La documentación oficial, al menos, no contiene dicha garantía. (Entonces, en teoría, podrían suceder cosas malas)Length(Result) = 1
, entonces lo hacesSetLength(Result, -1)
, ¡lo cual es igualmente malo! Además, podría ser el caso queResult
no termine con un salto de línea, en cuyo caso eliminará los dos últimos caracteres de la última línea. Eso también es un error. (Y eso podría suceder, por ejemplo, si lo usaTrailingLineBreak
, sospecho. Incluso si no, puede haber otras instancias). Realmente debería probar si la cadena realmente termina con un salto de línea, comoif not IncludeLastLineBreakInText and Result.EndsWith(LineBreak) then
.Pos(LineBreak, Result) = Length(Result) - Length(LineBreak) + 1
.Pos
Da el índice de la primera coincidencia. Si su cadena contiene 6 saltos de línea, le dará la posición de la primera, pero claramente espera la última one ...