আউটপুট স্ট্রিম থেকে ইনপুট স্ট্রিম তৈরি করার সর্বাধিক দক্ষ উপায়


86

এই পৃষ্ঠা: http://blog.ostermiller.org/convert-java-outputstream-inputstream আউটপুট স্ট্রিম থেকে কীভাবে ইনপুট স্ট্রিম তৈরি করবেন তা বর্ণনা করে:

new ByteArrayInputStream(out.toByteArray())

অন্যান্য বিকল্পগুলি হ'ল পাইপডস্ট্রিম এবং নতুন থ্রেডগুলি ব্যবহার করা জটিল umbers

মেমরি বাইট অ্যারেতে অনেকগুলি মেগাবাইট অনুলিপি করার ধারণাটি আমি পছন্দ করি না। এমন কোনও লাইব্রেরি রয়েছে যা আরও দক্ষতার সাথে এটি করে?

সম্পাদনা:

লরেন্স গনসাল্ভেসের পরামর্শ অনুসারে, আমি পাইপস্ট্রিমগুলি চেষ্টা করেছিলাম এবং এটি প্রমাণিত হয়েছে যে তারা মোকাবেলা করা এতটা কঠিন নয়। ক্লোজারে নমুনা কোডটি এখানে:

(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))

উত্তর:


73

আপনি যদি সমস্ত ডেটা একবারে মেমোরি বাফারে একবারে অনুলিপি করতে না চান তবে আপনার কাছে আপনার কোড থাকতে হবে যা আউটপুট স্ট্রিম (প্রযোজক) এবং ইনপুটস্ট্রিম ব্যবহারকারী কোড ব্যবহার করে (ভোক্তা) ) হয় একই থ্রেডে বিকল্প হয়, বা দুটি পৃথক থ্রেডে একই সাথে কাজ করে। তাদের একই থ্রেডে চালিত করা সম্ভবত আরও জটিল যে দুটি পৃথক থ্রেড ব্যবহার করা আরও ত্রুটিযুক্ত প্রবণ (আপনাকে অবশ্যই এটি নিশ্চিত করতে হবে যে ভোক্তা কখনই ইনপুটটির জন্য অপেক্ষা করে না বা আপনার কার্যকরভাবে অচলাবস্থা রাখে) এবং প্রয়োজনীয়তা তৈরি করবে প্রযোজক এবং ভোক্তা একই লুপে চলমান থাকে যা দেখে মনে হয় এটি খুব শক্তভাবে জুড়েছে।

সুতরাং একটি দ্বিতীয় থ্রেড ব্যবহার করুন। এটি আসলে এত জটিল নয়। আপনি যে পৃষ্ঠাটিতে লিঙ্ক করেছেন তার একটি নিখুঁত উদাহরণ রয়েছে:

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

আমি মনে করি আপনার প্রতিটি গ্রাহক থ্রেডের জন্য নতুন পাইপড ইনপুট স্ট্রিমও তৈরি করা দরকার। আপনি যদি অন্য থ্রেড থেকে পাইপ থেকে পড়েন তবে এটি আপনাকে একটি ত্রুটি দেয়।
ডেনিস তুলসকি

@ লরেন্স: আমি আপনার 2 টি থ্রেড ব্যবহারের যুক্তি বুঝতে পারি না ... তবে এটি প্রয়োজন যে ইনপুট স্ট্রিম থেকে পড়া সমস্ত অক্ষর একটি সময়োপযোগী আউটপুট স্ট্রিমে লেখা উচিত।
স্টিফেন সি

8
স্টিফেন: কিছু লেখা না হওয়া পর্যন্ত আপনি পড়তে পারবেন না। সুতরাং কেবল একটি থ্রেডের সাথে আপনাকে প্রথমে সবকিছু লিখতে হবে (ভগিফ এড়াতে চেয়েছিল এমন একটি বড় মেমরির অ্যারে তৈরি করা) অথবা পাঠকদের ইনপুটটির জন্য অপেক্ষা করতে কখনও বাধা না দেওয়ার জন্য তাদের বিকল্প হতে খুব সচেতন হওয়া প্রয়োজন (কারণ তিনি যদি তা করেন তবে লেখক কখনও মৃত্যুদণ্ড কার্যকর করতে পারবেন না)।
লরেন্স গনসাল্ভেস

4
এই পরামর্শটি কোনও জেইই পরিবেশে ব্যবহার করা নিরাপদ যেখানে কনটেইনারটি সম্ভবত তার নিজস্ব থ্রেড চালাচ্ছে?
তোসকান

4
@ তোসকান যদি new Threadকোনও কারণেই আপনার ধারকটিতে উপযুক্ত না হয় তবে দেখুন যে থ্রেড পুল ব্যবহার করতে পারবেন কিনা।
লরেন্স গনসাল্ভেস

14

ইজিস্ট্রিম নামে আরও একটি ওপেন সোর্স লাইব্রেরি রয়েছে যা পাইপ এবং থ্রেডকে স্বচ্ছ উপায়ে নিয়ে আসে। সবকিছু ঠিকঠাক থাকলে এটি আসলে জটিল নয়। সমস্যাগুলি দেখা দেয় যখন (লরেন্স গনসাল্ভসের উদাহরণের দিকে তাকানো)

শ্রেণি 1.পুটডাটাঅনপুট স্ট্রিম (আউট);

একটি ব্যতিক্রম নিক্ষেপ। এই উদাহরণে থ্রেডটি কেবল সম্পূর্ণ হয় এবং ব্যতিক্রম হারিয়ে যায়, যখন InputStreamবাইরেরটি কেটে যায়।

ইজস্ট্রিম ব্যতিক্রম প্রচার এবং অন্যান্য কদর্য সমস্যাগুলির সাথে আমি প্রায় এক বছর ধরে ডিবাগ করছি deals (আমি গ্রন্থাগারের ম্যানটেনার: স্পষ্টতই আমার সমাধানটি সেরা;)) এটি কীভাবে ব্যবহার করতে হয় তার একটি উদাহরণ এখানে:

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)
 }
};

একটি দুর্দান্ত ভূমিকা আছে যেখানে আউটপুট স্ট্রিমকে ইনপুট স্ট্রিমে রূপান্তর করার অন্যান্য সমস্ত উপায় ব্যাখ্যা করা হয়েছে। দেখার জন্য মূল্যবান।


4
তাদের ক্লাসটি ব্যবহারের জন্য টিউটোরিয়ালটি কোড জিওএল
পি

9

একটি সাধারণ সমাধান যা বাফারটি অনুলিপি করা এড়ায় তা হল একটি বিশেষ উদ্দেশ্য তৈরি করা 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অন্তর্নিহিত বাফারের উপর একটি ইনপুট স্ট্রিমটি পেতে কল করুন। সেই বিন্দুর পরে আউটপুট স্ট্রিম বন্ধ হিসাবে বিবেচনা করুন।


7

আমি মনে করি একটি আউটপুট স্ট্রিমের সাথে ইনপুট স্ট্রিমের সংযোগ করার সর্বোত্তম উপায় হ'ল পাইপযুক্ত স্ট্রিমগুলির মাধ্যমে - 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 - আপনাকে ম্যানুয়ালি ডেটা কুইউং পরিচালনা করার দরকার নেই


4
এটি দুর্দান্ত হবে তবে জাভাদোকস বলছেন যে আপনি যদি একই থ্রেডে এগুলি পড়েন এবং লিখেন তবে আপনি অচলাবস্থা পেতে পারেন। আমি আশা করি তারা এনআইও-র সাথে এটি আপডেট করেছে!
নেট গ্লেন

1

অচলাবস্থা বৃদ্ধির সম্ভাবনা, কোড বোঝার অসুবিধা এবং ব্যতিক্রমগুলি মোকাবেলা করার সমস্যাগুলির কারণে আমি সাধারণত একটি আলাদা থ্রেড তৈরি এড়াতে চেষ্টা করি।

এখানে আমার প্রস্তাবিত সমাধান: একটি প্রযোজক ইনপুট স্ট্রিম যা প্রডাকশঙ্ককে বারবার কল করে অংশগুলিতে সামগ্রী তৈরি করে:

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);

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.