2015-01-10 8 views
1

는 내가 서버에 comunicate 수 처음에는 간단한 클라이언트를 만들려고 해요 :DataoutputStream 및 BufferedWriter 생성 순서가 중요한 이유는 무엇입니까?

  1. 파일명
  2. 첫 번째에 대한

그래서 파일을 구성하는 덩어리의 순서 나는 BufferedWriter에 사용하려고 생각했다 :이 선택은 서버에서 ReadLine() 메소드가 사용되지 않는 순간부터 InputStreamReader를 사용할 수 없기 때문에 이루어졌다. 그러나 두 번째 소켓에서는 OutputStreamWriter를 사용 했으므로 소켓에 바이트 배열을 쓰는 것이 더 좋습니다 (단 하나입니까?).

그래서,이 내 클라이언트 코드의 첫 번째 버전입니다 :

public class Client 
{ 
    private static final int PART_SIZE = 1000000; // 1MB 

    public static void main(String[] args) throws IOException 
    { 
     final Path file = Paths.get(args[0]); 
     final String filenameBase = file.getFileName().toString(); 
     final byte[] buf = new byte[PART_SIZE];  
     Socket socket = new Socket(InetAddress.getLocalHost(),8080); 
     System.out.println("Socket created"); 
     int partNumber = 0; 
     Path part; 
     int bytesRead; 
     byte[] toWrite; 

     try (
      final InputStream in = Files.newInputStream(file); 
      final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 
      final DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); 
     ) { 
      System.out.println("closed="+socket.isClosed()); 
      bw.write(filenameBase,0,filenameBase.length()); 
      //other stuff for the chunk creation and spedition 
     } 
    } 
} 

는, 그러나이 코드이 예외 occours 실행하는 경우 :

Exception in thread "main" java.net.SocketException: Socket closed 
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:121) 
    at java.net.SocketOutputStream.write(SocketOutputStream.java:159) 
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) 
    at sun.nio.cs.StreamEncoder.implClose(StreamEncoder.java:316) 
    at sun.nio.cs.StreamEncoder.close(StreamEncoder.java:149) 
    at java.io.OutputStreamWriter.close(OutputStreamWriter.java:233) 
    at java.io.BufferedWriter.close(BufferedWriter.java:266) 
    at PAD.Charlie.Client.App.main(App.java:50) 

이상한 것은이를 가 나는 경우 안에있는 BufferedWriterDataOutputStream 사이의 순서를 변경해도 좋습니다.

실제로 자바 코스에서 뭔가 기억하고 있기 때문에 아이디어가 나왔습니다.하지만 세부 사항을 기억할 수는 없습니다. 내가 가지고있는 의심에 대해 저를 도울 수 있습니까? 고마워요! :)

답변

1

우선, 당신이하고있는 일은 경계가 미친 것입니다. 동일한 스트림을 텍스트 및 바이너리 데이터를 기록하려는 것으로 나타났습니다 :

  • 당신이 그 시점에서에서 버퍼링 작가를 사용하고 있기 때문에 데이터 두 종류의 인터리빙을 제어하기 어려울 것입니다

    스택

  • 인터리빙 권한을 얻더라도 "반대쪽 끝에"는 텍스트와 바이너리를 분리하기 위해 해제하지 않는 문제가 있습니다.


당신은 다음과 같이 결정 사용을 출력 스트림에 두 개의 스트림 스택을 정당화하려고

:

그래서 BufferedWriter의에 사용할 생각 최초의 하나 :이 선택이되었다 readLine() 메소드가 사용되지 않는 순간부터 서버에서 InputStreamReader를 사용할 수 없기 때문입니다. 그러나 두 번째 소켓에서는 OutputStreamWriter를 사용 했으므로 소켓에 바이트 배열을 쓰는 것이 더 좋습니다 (단 하나입니까?).

나는 논리를 따르지 않습니다. 그러나 하나의 접근법이 효과가 없다는 사실은 반드시 (다른) 것이 의미하는 것은 아닙니다.

작동하는 솔루션을 원한다면 몇 가지를 생각해 볼 수 있습니다. 가장 간단한 방법은 DataOutputStream을 클라이언트 측에만으로 사용하고 writeUTF을 사용하여 파일 이름을 쓰고 writeInt + write을 사용하여 청크를 씁니다. 청크 크기를 0으로 보내서 파일의 끝을 나타냅니다.

(당신이 전송됩니다 사전에 얼마나 많은 바이트를 알고 있다면 당신은 또한 하나 개의 큰 덩어리로 파일을 보낼 수 있습니다.)

서버 측 코드가 DataInputStream에의 통화에서 클라이언트 측을 반영해야한다.


은 그러나 당신이보고있는 행동의 차이에 대한 이유는 try 초기화에서 선언의 순서는 스트림이 try 블록의 끝에서 폐쇄되는 순서를 결정한다는 것입니다.

  • 작가가 먼저 닫혀있는 경우 :

    BufferedWriter.close() 
        -> BufferedWriter.flush() -> OutputStreamWriter.write() 
        -> OutputStreamWriter.close() -> SocketOutputStream.close() 
    DataOutputStream.close() -> SocketOutputStream.close() 
    

    닫히고의 두 번째 세트는 모든 데이터를 기록 할 필요가 없기 때문에이 OK입니다.

  • 작가는 초 후 닫혀있는 경우 : 이미 (암시)를 폐쇄했기 때문에 플러시가 소켓에 데이터를 쓸 수 없기 때문에

    DataOutputStream.close() -> SocketOutputStream.close() 
    BufferedWriter.close() 
        -> BufferedWriter.flush() -> OutputStreamWriter.write() // FAIL 
    

    실패가 발생합니다.

+0

그럼 당신은 작성하는 저에게 방법을 제안 할 수있다 : 1. 문자열을 한 번만 2.이 ByteArray 크기 3. 전체 파일 WAST까지 4 반복 2. 들어 – TwistAndShutter

+0

을 보내 ByteArray에있는 수 filename은'writeUTF()'와'readUTF()'를 사용하고 독자와 작성자를 모두 없앱니다. 크기의 경우'writeInt()'또는'writeLong()'등. – EJP

0

닫는 경우 BufferedWriter이 플러시되므로 작성자가 스트림을 만든 후 마지막으로 닫히고 둘 중 하나를 닫으면 소켓이 닫힙니다. 스택 추적을 참조하십시오. DataOutputStream은 버퍼링되지 않으므로 아무 것도하지 않습니다.

NB :

... 나는 내의 readLine() 메소드가 사용되지 않습니다 순간부터 서버에 InputStreamReader를 사용할 수 있기 때문이다. 그러나 두 번째 소켓에서는 OutputStreamWriter를 사용 했으므로 소켓에 바이트 배열을 쓰는 것이 더 좋습니다 (단 하나입니까?).

이 내용은 의미가 없습니다. InputStreamReader에는 readLine() 메서드가 없으며 더 이상 사용되지 않습니다. OutputStreamWriter은 바이트가 아닌 문자를 씁니다.