【问题标题】:How do I write to an OutputStream using DefaultHttpClient?如何使用 DefaultHttpClient 写入 OutputStream?
【发布时间】:2012-04-26 03:55:37
【问题描述】:

如何使用org.apache.http.impl.client.DefaultHttpClient 获得OutputStream

我希望将长字符串写入输出流。

使用HttpURLConnection 你可以这样实现它:

HttpURLConnection connection = (HttpURLConnection)url.openConnection();
OutputStream out = connection.getOutputStream();
Writer wout = new OutputStreamWriter(out);
writeXml(wout);

有没有类似于我上面的使用DefaultHttpClient 的方法?我如何使用DefaultHttpClient 而不是HttpURLConnectionOutputStream 写信?

例如

DefaultHttpClient client = new DefaultHttpClient();

OutputStream outstream = (get OutputStream somehow)
Writer wout = new OutputStreamWriter(out);

【问题讨论】:

  • @KeithRandall ,我已经编辑过了。希望现在很清楚。
  • 请说明你想写什么。在您的两个示例中,getOutputStream() 返回一个用于为 http POST 请求提交请求数据的流。
  • @EugeneKuleshov,如何使用 org.apache.http.impl.client.DefaultHttpClient 获得输出流?

标签: java httpclient outputstream


【解决方案1】:

我知道另一个答案已经被接受,只是为了记录,这是一个可以使用 HttpClient 写出内容而无需在内存中进行中间缓冲的方法。

    AbstractHttpEntity entity = new AbstractHttpEntity() {

        public boolean isRepeatable() {
            return false;
        }

        public long getContentLength() {
            return -1;
        }

        public boolean isStreaming() {
            return false;
        }

        public InputStream getContent() throws IOException {
            // Should be implemented as well but is irrelevant for this case
            throw new UnsupportedOperationException();
        }

        public void writeTo(final OutputStream outstream) throws IOException {
            Writer writer = new OutputStreamWriter(outstream, "UTF-8");
            writeXml(writer);
            writer.flush();
        }

    };
    HttpPost request = new HttpPost(uri);
    request.setEntity(entity);

【讨论】:

  • 这个过程还有其他例子吗? writeTo 在哪里被调用?
  • @Haraldo 请求执行时,HttpClient 框架调用request.getEntity().writeTo()。这意味着您不能编写一个启动 POST 然后将其 OutputStream 返回给调用者以调用多个写入的单线程客户端。
  • @oleg,我的 android 未定义 writeXml() 函数?你写的吗?请给我看看你的 writeXml() 代码好吗?
  • 只是为了澄清这一点,关于 isStreaming() - 在这里返回 false 是否正确?我原以为这种逻辑会被认为是流式传输。
  • 这个答案比记忆正确的答案更好。
【解决方案2】:

您无法直接从 BasicHttpClient 获取 OutputStream。你必须创建一个HttpUriRequest 对象并给它一个HttpEntity 来封装你想要发送的内容。例如,如果您的输出足够小以适合内存,您可以执行以下操作:

// Produce the output
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out, "UTF-8");
writeXml(writer);

// Create the request
HttpPost request = new HttpPost(uri);
request.setEntity(new ByteArrayEntity(out.toByteArray()));

// Send the request
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);

如果数据足够大以至于您需要对其进行流式传输,则变得更加困难,因为没有接受 OutputStream 的HttpEntity 实现。您需要写入临时文件并使用 FileEntity 或可能设置管道并使用 InputStreamEntity

编辑请参阅 oleg 的答案以获取演示如何流式传输内容的示例代码 - 毕竟您不需要临时文件或管道。

【讨论】:

  • 问题:这个 writeXml(writer) 在做什么?另外,您如何将字节数组传递给 request.setEntity()?
  • @MattGrogan 它正在实现应用程序逻辑以实际生成发布到远程服务器的内容(从问题中的示例代码复制)。
  • 所以如果我有需要写入的数据,我应该调用 writer.write(data) 来代替 writeXml() 吗?
  • 是的,writeXml() 正在计算要传递给 writer.write() 的东西。
  • 抱歉有额外的问题,但我真的需要让这个工作。你如何将 out.toByteArray() 传递给 request.setEntity(),我没有看到任何需要字节数组的重载。
【解决方案3】:

这在 android 上运行良好。它也应该适用于大文件,因为不需要缓冲。

PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream();
out.connect(in);
new Thread() {
    @Override
    public void run() {
        //create your http request
        InputStreamEntity entity = new InputStreamEntity(in, -1);
        request.setEntity(entity);
        client.execute(request,...);
        //When this line is reached your data is actually written
    }
}.start();
//do whatever you like with your outputstream.
out.write("Hallo".getBytes());
out.flush();
//close your streams

【讨论】:

    【解决方案4】:

    我写了一个 Apache 的 HTTP 客户端 API [PipedApacheClientOutputStream] 的反转,它使用 Apache Commons HTTP 客户端 4.3.4 为 HTTP POST 提供了一个 OutputStream 接口。

    调用代码如下所示:

    // Calling-code manages thread-pool
    ExecutorService es = Executors.newCachedThreadPool(
      new ThreadFactoryBuilder()
      .setNameFormat("apache-client-executor-thread-%d")
      .build());
    
    
    // Build configuration
    PipedApacheClientOutputStreamConfig config = new      
      PipedApacheClientOutputStreamConfig();
    config.setUrl("http://localhost:3000");
    config.setPipeBufferSizeBytes(1024);
    config.setThreadPool(es);
    config.setHttpClient(HttpClientBuilder.create().build());
    
    // Instantiate OutputStream
    PipedApacheClientOutputStream os = new     
    PipedApacheClientOutputStream(config);
    
    // Write to OutputStream
    os.write(...);
    
    try {
      os.close();
    } catch (IOException e) {
      logger.error(e.getLocalizedMessage(), e);
    }
    
    // Do stuff with HTTP response
    ...
    
    // Close the HTTP response
    os.getResponse().close();
    
    // Finally, shut down thread pool
    // This must occur after retrieving response (after is) if interested   
    // in POST result
    es.shutdown();
    

    注意 - 实际上,相同的客户端、执行器服务和配置可能会在应用程序的整个生命周期中重复使用,因此上述示例中的外部准备和关闭代码可能会存在于 bootstrap/init 和终结代码中,而不是直接与 OutputStream 实例化内联。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-11
      • 1970-01-01
      • 1970-01-01
      • 2019-09-13
      • 2022-09-30
      • 1970-01-01
      • 2020-10-16
      • 2020-01-31
      相关资源
      最近更新 更多