Alguns tem me perguntado sobre quebra de linha no Delphi 2010, o que está dando de errado.
Antes de falar sobre isso, precisamos saber como funciona a quebra de linha.
No sistema ASCII (caracteres de um byte) a quebra de linha nos sistemas gnu linux / unix é feita somente com o caracter #10 (ou \n line feed - LF para os íntimos). Já para sistemas windows a quebra é feita com #13#10 ou CR\LF.
Há ainda mais um agravante: assim como no GNU linux e unix o #10 sozinho é considerado como quebra de linha, há também alguns sistemas onde o #13 sozinho é considerado como quebra de linha. Então, alguns editores, como o
notepad++ interpretam tanto o #10 isolado como o #13 isolado como quebras de linha, bem como a dupla #13#10, para atender a todas as demandas.
O #13 ou \r é chamado de Carriage Return (CR) e o #10 ou \n é chamado de Line Feed (LF). Nas impressoras matriciais e maquinas de escrever elétricas antigas, para se pular uma linha e se escrever na linha de baixo, eram necessarios dois comandos:
O Carriage Return retornava o cabeçote de impressão para a posição mais a esquerda e o Line Feed fazia o papel "rolar" a altura de uma linha.
Por isso os caracteres CR e LF são tratados até hoje como comandos, e também por isso que em sistemas windows ASCII a quebra de linha é formada pelos caracteres CR e LF juntos.
O que acontece com o Delphi 2010 é que agora os caracteres, unicode, são formados por 2 bytes e não apenas um. Isso significa que o byte da direita deve ser preenchido com alguma coisa. Lembrando que, em sistemas IBM-PC, como a leitura é feita da direita para a esquerda, o byte mais significativo é o da direita e o menos significativo é o da esquerda. é como se escrevêssemos números em que a casa das unidades fica a esquerda e a casa das dezenas e centenas vão sendo postas a direita desta. (para ilustrar somente).
Então no Delphi Unicode a quebra de linha se dá não apenas com #13#10, mas com #13#0#10#0, veja os exemplos.
Para salvar os arquivos no formato correto pergunte-se qual o formato de arquivo que o destino necessita, se é unicode ou ASCII, e qual é a quebra de linha nesse sistema.
É interessante sempre salvar um arquivo como UNICODE e sempre usar a constante LineBreak (PROPRIEDADE DO TSTRINGLIST NA UNIT CLASSES) do Delphi, que fornece a quebra de linha correta de acordo com o sistema. (CASO VOCÊ ESTEJA USANDO TSTRINGLIST)
Para analizar os arquivos gerados use um editor Hexadecimal. usarei por exemplo o
HexPlorer.
Cuidado: quando usar o #0, lembre-se que ele deve ser usado apenas nos Delphis anteriores ao 2009 como o 7, ou qualquer outra linguagem que seja nativamente ASCII. Isso porque embora no Delphi 2010 a quebra de linha tenha mudado para #13#0#10#0 os chars no Delphi 2010 JÁ TEM 2 bytes JÁ VEM com o #0 no final.
Nesse caso, o #13 já é automaticamente #13#0 e o #10 já é #10#0. Na verdade o número dos caracteres especiais continuam sendo 13 e 10, isso não muda. Os zeros a esquerda, assim como são desnecessários, torna-se também desnecessário colocar o "zero à direita" em um sistema IBM-PC litle endian, onde, como já dissemos, o "byte à esquerda" (mais significativo) fica à direita.
Então se você digitar #13#0#10#0 no Delphi 2010 na verdade ele vai virar #13#0#0#0#10#0#0#0 com duas quebras de string desnecessárias e que farão com que sua string seja quebrada no meio e nem chegue ao arquivo.
Faremos 6 exemplos: dois salvando em ASCII e usando as sequencias #13#10 e a constante LineBreak. e os outros dois nesse mesmo esquema só que usando Unicode. Os últimos dois usaremos TFileStream.
procedure TForm1.Button1Click(Sender: TObject);
begin
with TStringList.Create do
try
Text := 'Hello' + #13#10 + 'World';
SaveToFile(ExtractFilePath(Application.ExeName)+'\teste1.txt', TEncoding.ASCII);
finally
Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
with TStringList.Create do
try
Text := 'Hello' + LineBreak + 'World';
SaveToFile(ExtractFilePath(Application.ExeName)+'\teste2.txt', TEncoding.ASCII);
finally
Free;
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
with TStringList.Create do
try
Text := 'Hello' + #13#10 + 'World';
SaveToFile(ExtractFilePath(Application.ExeName)+'\teste3.txt', TEncoding.Unicode);
finally
Free;
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
with TStringList.Create do
try
Text := 'Hello' + LineBreak + 'World';
SaveToFile(ExtractFilePath(Application.ExeName)+'\teste4.txt', TEncoding.Unicode);
finally
Free;
end;
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste5.txt', fmCreate) do
try
Write('Hello' + #13#10 + 'World', 24);
finally
Free;
end;
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste6.txt', fmCreate) do
try
Write('Hello' + #13#0#10#0 + 'World', 30);
finally
Free;
end;
end;
Conclusão: para quebrar linha use sempre #13#10 juntos, mas tome cuidado com o encoding e com quem será o receptor. Se o destino for unicode e você utilizar o Delphi 7 (ascii) utilize widestrings, mas se o destino for ASCII e você utilizar Delphi 2010 (unicode), utilize AnsiStrings, Encoding.ASCII e quebra de linha #13#10.
Agora vamos duplicar os exemplos 5 e 6 e vamos executá-los tanto no Delphi 2010 como no Delphi 7.
procedure TForm1.Button1Click(Sender: TObject);
var
teste: AnsiString;
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste1.txt', fmCreate) do
try
teste := 'Hello' + #13#10 + 'World';
Write(Pointer(teste)^, Length(teste)*SizeOf(AnsiChar));
finally
Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
teste: AnsiString;
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste2.txt', fmCreate) do
try
teste := 'Hello' + #13#0#10#0 + 'World';
Write(Pointer(teste)^, Length(teste)*SizeOf(AnsiChar));
finally
Free;
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
teste: WideString;
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste3.txt', fmCreate) do
try
teste := 'Hello' + #13#10 + 'World';
Write(Pointer(teste)^, Length(teste)*SizeOf(WideChar));
finally
Free;
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
var
teste: WideString;
begin
with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste4.txt', fmCreate) do
try
teste := 'Hello' + #13#0#10#0 + 'World';
Write(Pointer(teste)^, Length(teste)*SizeOf(WideChar));
finally
Free;
end;
end;
O código acima, executado no Delphi 2010, cria 4 arquivos. Repare que usando AnsiString o #13#10 equivale literalmente a #13#10 e o #13#0#10#0 também é transcrito normalmente. Repare também que usando widestrings cada char terá o dobro do tamanho, sendo o mesmo código que teria em ASCII + 00. O #13#10 sai automaticamente como #13#0#10#0 e colocar #0 nessa string duplicaria o #0.
Não abra com o notepad. Principalmente os arquivos 2 e 4 com #13#0#10#0 forçados, pois eles serão interpretados erroneamente e mostrarão as letras com um espaço entre si, como se estivesse lendo um Unicode mal formatado. Use sempre o
Hexplorer.
|
Arquivo teste1 |
|
Arquivo teste2 |
|
Arquivo teste3 |
|
Arquivo teste4 |
E é isso aí. Até a próxima ;)
Boa tarde
ResponderExcluirOs arquivos testes não abrem!
hospedei eles no finado spaces, que mudou de nome e hoje é o sky drive ou coisa parecida. Devo ter eles em algum lugar, depois eu subo outro link. Vai copiando o código da página por enquanto.
ResponderExcluir