Transferindo Arquivo via Socket

Entou enviando um arquivo via socket mais precisamente um arquivo DBF. A transferencia e recepção do arquivo estao funcionando corretamente, mas estou tendo um problema com a codificação de caracteres. Como é um tabela de banco de dados q estou mandando, ha alguns caracteres especiais neste arquivo e alguns destes caracteres nao estao vindo corretamente via socket, por exemplo o “é” e o “ç” estao gravando “?” no arquivo.
Sei q tenho q especificar um charset em meu stream mas mesmo assim nao esta funcionando corretamente.

Este é o modo q cria o streaming de transferencia no servidor:

in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"ISO-8859-1"));
out = new PrintStream(clientSocket.getOutputStream(),false,"ISO-8859-1");

e este eh o modo q crio no cliente:

in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"ISO-8859-1"));
out = new PrintStream(socket.getOutputStream());

O mais estranho é q há varios outros caracteres especiais q estao vindo corretamente.

Se o que você está transferindo são realmente apenas arquivos, você não precisa usar BufferedReader nem PrintStream, pode usar apenas InputStream e OutputStream com FileInputStream e FileOutputStream.

Dê uma olhada em:
http://www.inf.ufrgs.br/procpar/disc/inf01008/trabalhos/sem01-1/t2/PDPT2Claus/Performance_JavaIO.htm

Esse tutorial me ajudou bastante, tomara que lhe ajude também.

Inté

Certo, mas como diz ali neste tutorial, o BufferReader ajuda a “empilhar” os dados para agilizar o processo.
Baixei o código fonte do commons-net do Apache para dar uma olhada como fazem para mandar arquivos para Ftp, entao verifiquei q eles abrem os streamings do seguinte modo:

in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"ISO-8859-1")); out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"ISO-8859-1"));
Alterei meu código para este mesmo modo, mas infelizmente ficou na mesma!!! Mudei para a codificação UTF-8 e até fiz buscar a padrão do sistema pelo System.getProperty(“file.encoding”) onde me retornou Cp1252 e tb continua do mesmo modo :frowning:
Já li muita coisa mas nenhuma mudou o resultado!!!

estranho, o charset seria esse mesmo, tenta testar pedindo pra ele gravar ali o arquivo antes de enviar e vc abre pra ver se ta tudo ok! no arquivo, dae tem como saber so o problema esta no caminho ou na recepcao, tem como ver tbem como que esse dado estar la no DBF ?

apenas sugestões.
t+

Entao, resolvido meu problema…

Nao tinha nada a ver com socket ou leitura dos dados do arquivo mas sim com o modo q eu armazenava os dados de leitura. Qdo lia o arquivo (em byte) eu armazenava em um StringBuilder ate completar 500 character para dai mandar via socket. Eu fazia deste modo:

[code]FileInputStream inArq;
inArq = new FileInputStream(nomeArquivo);
envia = new StringBuilder();

while ((retorno = inArq.read()) != -1)
{
envia.append((char)retorno);
if (envia.length() &gt 500)
{
…enviando dados
envia = new StringBuilder();
}
}[/code]

mas o modo certo para se gravar os dados dentro de StringBuild com o charset correto é assim:

envia.append(new String(new byte[]{(byte)retorno},"ISO-8859-1"));

Ai vai a dica para quem eventualmente for armazenar dados de arquivo em uma String (StringBuilder), sempre colocoque o charset qdo declarar um novo String pois alguns carateres especiais podem ser trocados por ?

vlw

Não sei não, não teria sido melhor armazenar o conteúdo do pedaço lido do arquivo num byte[] ou num ByteBuffer para evitar essas dores de cabeça com codificação de caracteres?

Só sugerindo…

Inté

Fala pessoal,

soh queria fazer um comentario, quando vcs estao lendo arquivos binarios, ou seja, arquivos nao abertos corretamente pelo notepad (jpg, doc, bmp, mp3, dbf etc) vc nao deve utilizar nem Writers e Readers. Esses sao todos utilizados para streams de caracteres e nao de bytes.

O correto nesses casos eh utilizar InputStream e OutputStream, claro, vc pode utilizar os Buffereds que sao muito mais performaticos, mas NAO utilize readers e writers.

O comentario do KWill procede :smiley: porque quando se trabalha com caracteres dentro da jvm exite uma maluquice de convercoes entre ascii, unicode, utf8 etc e voce nao pode correr o risco de alterar um unico byte!!! :roll:

Assim, as vezes essas conversoes podem tirar alguns bytes que nao sao significativos para o caracter mas sao significaticos para o arquivo binario que pode aparecer corrmpido depois.

Armazena-los em Strings tb nao eh recomendavel, pois as strings tb fazem essas conversoes.

Um exemplo simpes seria, imaginem um caracter escrito em uma arquivo ascii, logo ele soh tem 8 bits, mas quando vc o poe em uma string java ele se torna unicode, passando a ter 16 bits (1 char java tem 16 bits, 2 bytes), ai dependendo de como vc trasnfira / armazene essa string depois ela pode armazenar como unicode, o que adiciona um byte em cada caracter.

Outro caso eh contrario, que eh muito comum, vc le um arquivo que tem caracters unicode, assim, cada caracter tem 2 bytes, logo, os caracteres comuns entre unicode e ascii tem os mesmo valores, mas o unicode tem que usar 2 bytes para representa-lo, onde, um byte tem apenas zeros agora, se vc o enviar por um processo UTF8 ele pode (vai) jogar fora os bytes nao necessarios durante a transferencia, assim mandando menos e ganhando performance o que eh uma boa coisa e normalmente nao traz problemas a arquivos texto, os editores atuais lidam bem com unicode e ascii, mas imagina a zona que pode virar um arquivo binario.

Agora, o que tem dentro de um arquivo binario?? Unicode ou ascii??

Na verdade nem um nem outro, cada formato de aquivo possui um sistema interno de controle, assim, cada byte pode ter um significado completamente maluco, como uma linha locada no DBF ou um controle dizendo qual a compactacado do JPEG.

Cedo ou tarde, mesmo setando o charset vc vai ter problemas com essas transferencias corrompendo os dbfs.

Complique muito?? :smiley: Foi mal, soh tentando ajudar :smiley:

[]`s