سؤال

هذه الصفحة: http://blog.ostermiller.org/convert-java-outputstream-inputstreamيصف كيفية إنشاء InputStream من OutputStream:

new ByteArrayInputStream(out.toByteArray())

البدائل الأخرى هي استخدام PipedStreams والخيوط الجديدة وهو أمر مرهق.

لا أحب فكرة نسخ العديد من الميجابايت إلى مجموعة بايت جديدة في الذاكرة.هل هناك مكتبة تفعل ذلك بكفاءة أكبر؟

يحرر:

بناءً على نصيحة Laurence Gonsalves، قمت بتجربة PipedStreams وتبين لي أنه ليس من الصعب التعامل معها.إليك نموذج التعليمات البرمجية في clojure:

(defn #^PipedInputStream create-pdf-stream [pdf-info]
  (let [in-stream (new PipedInputStream)
        out-stream (PipedOutputStream. in-stream)]
    (.start (Thread. #(;Here you write into out-stream)))
    in-stream))
هل كانت مفيدة؟

المحلول

إذا كنت لا ترغب في نسخ جميع البيانات إلى مخزن مؤقت في الذاكرة مرة واحدة، فسيتعين عليك الحصول على التعليمات البرمجية الخاصة بك التي تستخدم OutputStream (المنتج) والتعليمة البرمجية التي تستخدم InputStream (المستهلك) ) إما بالتناوب في نفس الموضوع، أو العمل بشكل متزامن في موضوعين منفصلين.من المحتمل أن يكون تشغيلها في نفس الخيط أكثر تعقيدًا من استخدام خيطين منفصلين، وهو أكثر عرضة للخطأ (ستحتاج إلى التأكد من أن المستهلك أبداً كتل تنتظر الإدخال، أو ستصل إلى طريق مسدود فعليًا) وستتطلب تشغيل المنتج والمستهلك في نفس الحلقة التي تبدو مقترنة بإحكام شديد.

لذا استخدم خيطًا ثانيًا.انها حقا ليست بهذا التعقيد.تحتوي الصفحة التي قمت بربطها على مثال مثالي:

  PipedInputStream in = new PipedInputStream();
  PipedOutputStream out = new PipedOutputStream(in);
  new Thread(
    new Runnable(){
      public void run(){
        class1.putDataOnOutputStream(out);
      }
    }
  ).start();
  class2.processDataFromInputStream(in);

نصائح أخرى

وهناك مكتبة مفتوحة المصدر آخر يسمى <م> EasyStream التي تتعامل مع أنابيب وخيط بطريقة شفافة. التي ليست معقدة حقا إذا كان كل شيء على ما يرام. وتنشأ المشاكل عندما (النظر في لورانس غونسالفيس سبيل المثال)

<اقتباس فقرة>   

وclass1.putDataOnOutputStream (الخروج)؛

والرميات استثناء. في هذا المثال موضوع ببساطة اكتمال وفقدت استثناء، في حين قد يتم اقتطاعها InputStream الخارجي.

وEasystream يتعامل مع انتشار استثناء والمشاكل سيئة أخرى لقد تم تصحيح لمدة سنة واحدة. (أنا mantainer المكتبة: من الواضح لي الحل هو أفضل واحد؛)) وفيما يلي مثال على كيفية استخدامه:

final InputStreamFromOutputStream<String> isos = new InputStreamFromOutputStream<String>(){
 @Override
 public String produce(final OutputStream dataSink) throws Exception {
   /*
    * call your application function who produces the data here
    * WARNING: we're in another thread here, so this method shouldn't 
    * write any class field or make assumptions on the state of the outer class. 
    */
   return produceMydata(dataSink)
 }
};

وهناك أيضا مقدمة فيها كل وسائل أخرى لتحويل OutputStream إلى InputStream وأوضح. يستحق أن يكون نظرة.

وهناك حل بسيط أن يتجنب نسخ المخزن المؤقت هو خلق ByteArrayOutputStream لأغراض خاصة:

public class CopyStream extends ByteArrayOutputStream {
    public CopyStream(int size) { super(size); }

    /**
     * Get an input stream based on the contents of this output stream.
     * Do not use the output stream after calling this method.
     * @return an {@link InputStream}
     */
    public InputStream toInputStream() {
        return new ByteArrayInputStream(this.buf, 0, this.count);
    }
}

والكتابة إلى دفق إخراج أعلاه حسب الحاجة، ثم استدعاء toInputStream للحصول على تيار إدخال أكثر من المخزن المؤقت الأساسي. النظر في دفق إخراج كما أغلقت بعد هذه النقطة.

وأعتقد أن أفضل وسيلة للتواصل InputStream إلى OutputStream هي من خلال على الأنابيب تيارات - يمكنك المتاحة في حزمة java.io، كما يلي:

// 1- Define stream buffer
private static final int PIPE_BUFFER = 2048;

// 2 -Create PipedInputStream with the buffer
public PipedInputStream inPipe = new PipedInputStream(PIPE_BUFFER);

// 3 -Create PipedOutputStream and bound it to the PipedInputStream object
public PipedOutputStream outPipe = new PipedOutputStream(inPipe);

// 4- PipedOutputStream is an OutputStream, So you can write data to it
// in any way suitable to your data. for example:
while (Condition) {
     outPipe.write(mByte);
}

/*Congratulations:D. Step 4 will write data to the PipedOutputStream
which is bound to the PipedInputStream so after filling the buffer
this data is available in the inPipe Object. Start reading it to
clear the buffer to be filled again by the PipedInputStream object.*/

في رأيي هناك نوعان من المزايا الرئيسية لهذا الرمز:

1 - لا يوجد استهلاك إضافي من الذاكرة باستثناء المخزن المؤقت

.

2 - لا تحتاج لمعالجة البيانات يدويا الطابور

وأنا عادة في محاولة لتجنب خلق موضوع منفصل بسبب زيادة فرصة من الجمود، وزيادة صعوبة فهم التعليمات البرمجية، ومشاكل التعامل مع الاستثناءات.

وهنا الحل المقترح بلدي: أ ProducerInputStream الذي يخلق المحتوى في قطع من الدعوات المتكررة إلى produceChunk ():

public abstract class ProducerInputStream extends InputStream {

    private ByteArrayInputStream bin = new ByteArrayInputStream(new byte[0]);
    private ByteArrayOutputStream bout = new ByteArrayOutputStream();

    @Override
    public int read() throws IOException {
        int result = bin.read();
        while ((result == -1) && newChunk()) {
            result = bin.read();
        }
        return result;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result = bin.read(b, off, len);
        while ((result == -1) && newChunk()) {
            result = bin.read(b, off, len);
        }
        return result;
    }

    private boolean newChunk() {
        bout.reset();
        produceChunk(bout);
        bin = new ByteArrayInputStream(bout.toByteArray());
        return (bout.size() > 0);
    }

    public abstract void produceChunk(OutputStream out);

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top