আউটপুট স্ট্রিম কীভাবে ইনপুট স্ট্রিমে রূপান্তর করবেন?


337

আমি উন্নয়নের মঞ্চে আছি, যেখানে আমার দুটি মডিউল রয়েছে এবং একটি থেকে আমি একটি OutputStreamএবং দ্বিতীয় হিসাবে আউটপুট পেয়েছি , যা কেবল গ্রহণ করে InputStream। আপনি কি জানেন যে কীভাবে রূপান্তর OutputStreamকরতে হবে InputStream(বিপরীতে নয়, আমি সত্যিই এইভাবে বোঝাচ্ছি) যে আমি এই দুটি অংশ সংযোগ করতে সক্ষম হব?

ধন্যবাদ



3
@ সি0 এমরেড, অপটি কেবল অন্য দিকে, আইউইটিসকপি এর মতো কিছু চায়। যখন কেউ আউটপুট স্ট্রিমে লিখেন, অন্য কারও জন্য ইনপুট স্ট্রিম ব্যবহারের জন্য এটি উপলব্ধ হয়ে যায়। এটি মূলত পাইপড আউটপুট স্ট্রিম / পাইপড ইনপুট স্ট্রিমই করে। দুর্ভাগ্যক্রমে পাইপযুক্ত স্ট্রিমগুলি অন্য স্ট্রিম থেকে তৈরি করা যায় না।
মেবিগফ্যাটগুয়ে

সুতরাং পাইপড আউটপুট স্ট্রিম / পাইপড ইনপুট স্ট্রিম এর সমাধান?
ওয়েপয়েন্ট

মূলত আপনার ক্ষেত্রে কাজ PipedStreams জন্য অর্ডার, আপনার OutputStream মত নির্মাণ করা প্রয়োজন হবে new YourOutputStream(thePipedOutputStream)এবং new YourInputStream(thePipedInputStream)সম্ভবত উপায় আপনার প্রবাহে কাজ নয়। সুতরাং আমি মনে করি না এটিই সমাধান is
মেবিগফ্যাটগুয়ে

উত্তর:


109

একটি OutputStreamএমন একটি যেখানে আপনি ডেটা লেখেন। যদি কিছু মডিউল একটি এক্সপোজ করে OutputStream, প্রত্যাশাটি অন্য প্রান্তে কিছু পড়ার আছে।

InputStreamঅন্যদিকে প্রকাশিত কিছু এমনটি নির্দেশ করে যা আপনাকে এই স্ট্রিমটি শুনতে হবে এবং এমন ডেটা থাকবে যা আপনি পড়তে পারবেন।

সুতরাং এটি একটি InputStreamএকটি সাথে সংযোগ করা সম্ভবOutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

যেহেতু কেউ স্মরণ করেছেন, আইইউটিস copy()থেকে প্রাপ্ত পদ্ধতিটি আপনাকে এটি করতে দেয়। অন্যভাবে যাওয়া কোনও অর্থবোধ করে না ... আশা করি এটি কিছুটা বোধগম্য হবে

হালনাগাদ:

অবশ্যই আমি এটির যত বেশি চিন্তা করি, তত বেশি দেখতে পাচ্ছি যে এটি আসলে কীভাবে প্রয়োজন হবে। আমি Pipedইনপুট / আউটপুট স্ট্রিমের উল্লিখিত কয়েকটি মন্তব্য জানি , তবে এর আরও একটি সম্ভাবনা রয়েছে।

যদি প্রকাশিত আউটপুট স্ট্রিমটি একটি হয় ByteArrayOutputStreamতবে আপনি সর্বদা toByteArray()পদ্ধতিতে কল করে সম্পূর্ণ সামগ্রীগুলি পেতে পারেন । তারপরে আপনি ByteArrayInputStreamউপ-শ্রেণীর ব্যবহার করে একটি ইনপুট স্ট্রিম র‌্যাপার তৈরি করতে পারেন । এই দুটি সিউডো-স্ট্রিম, এগুলি উভয়ই মূলত কেবল বাইটের অ্যারে গুটিয়ে রাখে। স্ট্রিমগুলি এভাবে ব্যবহার করা প্রযুক্তিগতভাবে সম্ভব তবে আমার কাছে এটি এখনও খুব অদ্ভুত ...


4
অনুলিপি করুন) এপিআই অনুযায়ী ওএসে এই আইএস করুন, আমার এটি পিছনের দিকে করা দরকার
ওয়েপয়েন্ট

1
উপরে আমার সম্পাদনাটি দেখুন, কিছু রূপান্তর করা আমার পক্ষে প্রয়োজনীয়
WayPoint

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

6
ইউনিট পরীক্ষার সময় আপনি দরকারী এবং ফাইল সিস্টেমের স্পর্শ এড়ানো সম্পর্কে সুপার পেডেন্টিক।
জন

28
@ জেবিসিপি এর মন্তব্য স্পট হয়। আরেকটি ব্যবহারের ক্ষেত্রে এইচটিপি অনুরোধ চলাকালীন পিডিএফগুলি তৈরি করতে পিডিএফবক্স ব্যবহার করা হচ্ছে। পিডিএফ বাক্স একটি পিডিএফ অবজেক্ট সংরক্ষণ করার জন্য একটি আউটপুট স্ট্রিম ব্যবহার করে এবং REST এপিআই ক্লায়েন্টকে উত্তর দেওয়ার জন্য একটি ইনপুট স্ট্রিম গ্রহণ করে। সুতরাং, একটি আউটপুট স্ট্রিম -> ইনপুট স্ট্রিম একটি খুব বাস্তব-বিশ্বের ব্যবহারের কেস।
জন মানকো

200

অনেকগুলি লিঙ্ক এবং এই জাতীয় সামগ্রী রয়েছে বলে মনে হয় তবে পাইপ ব্যবহার করে কোনও আসল কোড নেই। ব্যবহারের সুবিধা java.io.PipedInputStreamএবং java.io.PipedOutputStreamএটি হ'ল মেমোরির কোনও অতিরিক্ত খরচ হয় না। ByteArrayOutputStream.toByteArray()আসল বাফারের একটি অনুলিপি ফেরত দেয়, এর অর্থ হল যে আপনার কাছে যা আছে মেমরির, আপনার এখন এটির দুটি কপি। তারপরে একটি লিখতেInputStream মাধ্যেমে এখন আপনার কাছে ডেটাটির তিনটি অনুলিপি রয়েছে।

কোড:

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
new Thread(new Runnable() {
    public void run () {
        try {
            // write the original OutputStream to the PipedOutputStream
            // note that in order for the below method to work, you need
            // to ensure that the data has finished writing to the
            // ByteArrayOutputStream
            originalByteArrayOutputStream.writeTo(out);
        }
        catch (IOException e) {
            // logging and exception handling should go here
        }
        finally {
            // close the PipedOutputStream here because we're done writing data
            // once this thread has completed its run
            if (out != null) {
                // close the PipedOutputStream cleanly
                out.close();
            }
        }   
    }
}).start();

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


21
আমি এটিকে ভোট দিয়েছি, তবে এটির নির্মাতার outকাছে যাওয়া ভাল in, অন্যথায় আপনি inরেসের শর্তের কারণে বন্ধ হওয়া পাইপ ব্যতিক্রম পেতে পারেন (যা আমি অভিজ্ঞ হয়েছি)। জাভা 8 লাম্বডাস ব্যবহার করে:PipedInputStream in = new PipedInputStream(out); ((Runnable)() -> {originalOutputStream.writeTo(out);}).run(); return in;
জন মানকো

1
@ জনমনোকো হুম ... আমার কখনও সমস্যা হয়নি। অন্য থ্রেড বা মূল থ্রেড কল আউট কল করায় কারণ আপনি এটি অনুভব করেছেন? এটি সত্য যে এই কোডটি ধরে নিয়েছে যে আপনার পাইপড আউটপুট স্ট্রিমটি আপনার সত্যের চেয়ে দীর্ঘজীবী originalOutputStream, তবে আপনি কীভাবে আপনার স্ট্রিমগুলি নিয়ন্ত্রণ করবেন তা ধরে নি। এটি বিকাশকারীকে ছেড়ে দেওয়া হয়েছে। এই কোডটিতে এমন কোনও কিছুই নেই যা বন্ধ বা ভাঙ্গা পাইপের ব্যতিক্রম ঘটায়।
মাইকহো

3
না, আমার মামলাটি যখন আমি মোঙ্গো গ্রিডএফএসে পিডিএফ সঞ্চয় করি এবং তখনই জ্যাক্স-আরএস ব্যবহার করে ক্লায়েন্টের কাছে প্রবাহিত হয় from মঙ্গোডিবি একটি আউটপুট স্ট্রিম সরবরাহ করে তবে জ্যাক্স-আরএসের একটি ইনপুট স্ট্রিম প্রয়োজন। আউটপুটস্ট্রিমটি সম্পূর্ণরূপে প্রতিষ্ঠিত হওয়ার আগে আমার পাথ পদ্ধতিটি ইনপুট স্ট্রিম সহ ধারকটিতে ফিরে আসবে, মনে হয় (সম্ভবত বাফারটি এখনও ক্যাশে করা হয়নি)। যাইহোক, জ্যাক্স-আরএস পাইপ বন্ধ ব্যতিক্রমটি ইনপুট স্ট্রিমে ফেলে দেবে। অদ্ভুত, তবে অর্ধেক সময় এটাই ঘটেছিল। উপরের কোডে পরিবর্তন করা বাধা দেয়।
জন মানকো

1
@ জনমনোকো আমি এটি আরও সন্ধান করছিলাম এবং PipedInputStreamজাভাদোকস থেকে দেখলাম : পাইপটি ভাঙ্গা হবে বলে যদি সংযুক্ত পাইপযুক্ত আউটপুট প্রবাহে ডেটা বাইট সরবরাহকারী কোনও থ্রেডটি আর বেঁচে না থাকে। সুতরাং আমি যা সন্দেহ করছি তা হ'ল যদি আপনি উপরের উদাহরণটি ব্যবহার করেন Jax-RSতবে ইনপুট স্ট্রিমটি গ্রাস করার আগে থ্রেডটি সম্পূর্ণ হয়ে যাচ্ছে। একই সময়ে, আমি দিকে তাকিয়ে MongoDB Javadocs। GridFSDBFileএকটি ইনপুট স্ট্রিম রয়েছে, সুতরাং কেন এটি কেবল জ্যাক্স-আরএসে পাস করবেন না ?
মাইকহো

3
@ ডেনিসচেং হ্যাঁ, অবশ্যই কিছুই বিনামূল্যে নয়, তবে এটি অবশ্যই 15 এমবি অনুলিপিটির চেয়ে ছোট হতে চলেছে। অপ্টিমাইজেশানগুলিতে ধ্রুবক থ্রেড / অবজেক্ট তৈরির সাথে জিসি মন্থ কমার পরিবর্তে একটি থ্রেড পুল ব্যবহার করা অন্তর্ভুক্ত।
মাইকহো

40

ইনপুট এবং আউটপুট স্ট্রিমগুলি কেবল শুরু এবং শেষ পয়েন্ট হওয়ায় সমাধানটি হ'ল বাইট অ্যারেতে অস্থায়ী স্টোরের ডেটা। সুতরাং আপনাকে অবশ্যই মধ্যবর্তী তৈরি করতে হবেByteArrayOutputStream , যা থেকে আপনি এটি তৈরি করেন byte[]যা নতুনের জন্য ইনপুট হিসাবে ব্যবহৃত হয় ByteArrayInputStream

public void doTwoThingsWithStream(InputStream inStream, OutputStream outStream){ 
  //create temporary bayte array output stream
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  doFirstThing(inStream, baos);
  //create input stream from baos
  InputStream isFromFirstData = new ByteArrayInputStream(baos.toByteArray()); 
  doSecondThing(isFromFirstData, outStream);
}

আশা করি এটা সাহায্য করবে.


baos.toByteArray () System.arraycopy দিয়ে একটি অনুলিপি তৈরি করে। ইশারা জন্য @mikeho ধন্যবাদ developer.classpath.org/doc/java/io/...
Mitja Gustin

20

আপনার মধ্যে একটি মধ্যবর্তী শ্রেণি প্রয়োজন হবে যা মধ্যস্থতা করবে। প্রতিবার InputStream.read(byte[]...)বলা হয়, বাফারিং ক্লাসটি পাশের বাইট অ্যারেটি পাশের পরবর্তী অংশটি পূরণ করবে OutputStream.write(byte[]...)। যেহেতু খণ্ডগুলির আকারগুলি একই নয়, অ্যাডাপ্টারের ক্লাসে নির্দিষ্ট পরিমাণ সংরক্ষণ করা দরকার যতক্ষণ না এটিতে রিড বাফারটি পূরণ করার যথেষ্ট পরিমাণ থাকে এবং / অথবা কোনও বাফার ওভারফ্লো সঞ্চয় করতে সক্ষম হয় না।

এই নিবন্ধটিতে এই সমস্যার কয়েকটি পৃথক পদ্ধতির একটি দুর্দান্ত ব্রেকডাউন রয়েছে:

http://blog.ostermiller.org/convert-java-outputstream-inputstream


1
ধন্যবাদ @ এমকামে, সার্কুলার বাফারগুলির উপর ভিত্তি করে পদ্ধতিটি আমার প্রয়োজন ঠিক তাই!
হুই ওয়াং

18
ByteArrayOutputStream buffer = (ByteArrayOutputStream) aOutputStream;
byte[] bytes = buffer.toByteArray();
InputStream inputStream = new ByteArrayInputStream(bytes);

2
আপনার এটি ব্যবহার করা উচিত নয় যেহেতু toByteArray()পদ্ধতির বডিটি এই জাতীয় return Arrays.copyOf(buf, count);যা নতুন অ্যারে দেয়।
রুট জি

17

Easystream ওপেন সোর্স লাইব্রেরি একটি InputStream একটি OutputStream রূপান্তর করতে সরাসরি সমর্থন রয়েছে: http://io-tools.sourceforge.net/easystream/tutorial/tutorial.html

তারা অন্যান্য বিকল্পগুলিও তালিকাভুক্ত করে: http://io-tools.sourceforge.net/easystream/OutputStream_to_IpputStream.html


1
হ্যাঁ, সহজ প্রবাহ ব্যবহার করুন!
smartwjw

9

আমি একটি রূপান্তর সঙ্গে একই সমস্যার সম্মুখীন হয়েছি ByteArrayOutputStreamএকটি থেকে ByteArrayInputStreamএবং একটি উদ্ভূত ক্লাস থেকে ব্যবহার করে এটি মীমাংসিত ByteArrayOutputStreamযা ফিরতে সক্ষম হয় ByteArrayInputStreamযে অভ্যন্তরীণ বাফার সঙ্গে সক্রিয়া করা হয় ByteArrayOutputStream। এইভাবে কোনও অতিরিক্ত মেমরি ব্যবহৃত হয় না এবং 'রূপান্তর' খুব দ্রুত:

package info.whitebyte.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * This class extends the ByteArrayOutputStream by 
 * providing a method that returns a new ByteArrayInputStream
 * which uses the internal byte array buffer. This buffer
 * is not copied, so no additional memory is used. After
 * creating the ByteArrayInputStream the instance of the
 * ByteArrayInOutStream can not be used anymore.
 * <p>
 * The ByteArrayInputStream can be retrieved using <code>getInputStream()</code>.
 * @author Nick Russler
 */
public class ByteArrayInOutStream extends ByteArrayOutputStream {
    /**
     * Creates a new ByteArrayInOutStream. The buffer capacity is
     * initially 32 bytes, though its size increases if necessary.
     */
    public ByteArrayInOutStream() {
        super();
    }

    /**
     * Creates a new ByteArrayInOutStream, with a buffer capacity of
     * the specified size, in bytes.
     *
     * @param   size   the initial size.
     * @exception  IllegalArgumentException if size is negative.
     */
    public ByteArrayInOutStream(int size) {
        super(size);
    }

    /**
     * Creates a new ByteArrayInputStream that uses the internal byte array buffer 
     * of this ByteArrayInOutStream instance as its buffer array. The initial value 
     * of pos is set to zero and the initial value of count is the number of bytes 
     * that can be read from the byte array. The buffer array is not copied. This 
     * instance of ByteArrayInOutStream can not be used anymore after calling this
     * method.
     * @return the ByteArrayInputStream instance
     */
    public ByteArrayInputStream getInputStream() {
        // create new ByteArrayInputStream that respects the current count
        ByteArrayInputStream in = new ByteArrayInputStream(this.buf, 0, this.count);

        // set the buffer of the ByteArrayOutputStream 
        // to null so it can't be altered anymore
        this.buf = null;

        return in;
    }
}

আমি গিথুবগুলিতে জিনিসটি রেখেছি: https://github.com/nickrussler/ByteArrayInOutStream


বিষয়বস্তু বাফারের সাথে ফিট না হলে কী হবে?
ভাদিমো

তারপরে আপনার প্রথমে কোনও বাইটআরআই ইনপুট স্ট্রিম ব্যবহার করা উচিত নয়।
নিক রাশলার

এই সমাধানটিতে মেমরির সমস্ত বাইট থাকবে। ছোট ফাইলগুলির জন্য এটি ঠিক আছে তবে আপনি বাইটআরআউটপুট স্ট্রিম
ভাদিমো

1
আপনি যদি বাইটআর্রিকে বোঝাতে চান তবে এটি অভ্যন্তরীণ বাফারটি অনুলিপি করতে পারে, যা আমার পদ্ধতির দ্বিগুণ স্মৃতি গ্রহণ করবে। সম্পাদনা: আহ আমি বুঝতে পারি, ছোট ফাইলগুলির জন্য এটি অবশ্যই কাজ করে ..
নিক রাশুলার

সময়ের অপচয়। বাইটআরআউটআউটপুট স্ট্রিমের
লিখিত

3

আইও এক্সট্রা গ্রন্থাগারটি কার্যকর হতে পারে। উদাহরণস্বরূপ, আপনি একটি gzip করতে চান তাহলে InputStreamব্যবহার GZIPOutputStreamএবং আপনি এটা ঘটতে করতে চান সিঙ্ক্রোনাস (8192 এর ডিফল্ট বাফারের আকার ব্যবহার করে):

InputStream is = ...
InputStream gz = IOUtil.pipe(is, o -> new GZIPOutputStream(o));

নোট করুন যে লাইব্রেরিতে 100% ইউনিট পরীক্ষার কভারেজ রয়েছে (এটির জন্য অবশ্যই মূল্য!) এবং এটি মাভেন সেন্ট্রালে রয়েছে। ম্যাভেন নির্ভরতা হ'ল:

<dependency>
  <groupId>com.github.davidmoten</groupId>
  <artifactId>io-extras</artifactId>
  <version>0.1</version>
</dependency>

পরবর্তী সংস্করণ পরীক্ষা করার জন্য নিশ্চিত হন।


0

আমার দৃষ্টিকোণ থেকে java.io.PipedInputStream / java.io.PededOutputStream বিবেচনার জন্য সেরা বিকল্প। কিছু পরিস্থিতিতে আপনি বাইটআরআইআইপুট স্ট্রিম / বাইটআরআউটআউটপুট স্ট্রিম ব্যবহার করতে পারেন। সমস্যাটি হ'ল একটি বাইটআররেআউটপুট স্ট্রিমকে একটি বাইটআররেইনপুট স্ট্রিমে রূপান্তর করতে আপনাকে বাফারটি সদৃশ করতে হবে। এছাড়াও বাইটআরআউটপুস্ট্রিম / বাইটআরআরআইপুট স্ট্রিম 2 জিবিতে সীমাবদ্ধ। এখানে একটি আউটপুস্ট্রিম / ইনপুটস্ট্রিম বাস্তবায়ন আমি বাইটআরআউটআউটপুটস্ট্রিম / বাইটআরআরআইপুট স্ট্রিম সীমাবদ্ধতা (স্কালা কোড, তবে জাভা বিকাশকারীদের জন্য সহজেই বোধগম্য) বাইপাস করতে লিখেছিলাম:

import java.io.{IOException, InputStream, OutputStream}

import scala.annotation.tailrec

/** Acts as a replacement for ByteArrayOutputStream
  *
  */
class HugeMemoryOutputStream(capacity: Long) extends OutputStream {
  private val PAGE_SIZE: Int = 1024000
  private val ALLOC_STEP: Int = 1024

  /** Pages array
    *
    */
  private var streamBuffers: Array[Array[Byte]] = Array.empty[Array[Byte]]

  /** Allocated pages count
    *
    */
  private var pageCount: Int = 0

  /** Allocated bytes count
    *
    */
  private var allocatedBytes: Long = 0

  /** Current position in stream
    *
    */
  private var position: Long = 0

  /** Stream length
    *
    */
  private var length: Long = 0

  allocSpaceIfNeeded(capacity)

  /** Gets page count based on given length
    *
    * @param length   Buffer length
    * @return         Page count to hold the specified amount of data
    */
  private def getPageCount(length: Long) = {
    var pageCount = (length / PAGE_SIZE).toInt + 1

    if ((length % PAGE_SIZE) == 0) {
      pageCount -= 1
    }

    pageCount
  }

  /** Extends pages array
    *
    */
  private def extendPages(): Unit = {
    if (streamBuffers.isEmpty) {
      streamBuffers = new Array[Array[Byte]](ALLOC_STEP)
    }
    else {
      val newStreamBuffers = new Array[Array[Byte]](streamBuffers.length + ALLOC_STEP)
      Array.copy(streamBuffers, 0, newStreamBuffers, 0, streamBuffers.length)
      streamBuffers = newStreamBuffers
    }

    pageCount = streamBuffers.length
  }

  /** Ensures buffers are bug enough to hold specified amount of data
    *
    * @param value  Amount of data
    */
  private def allocSpaceIfNeeded(value: Long): Unit = {
    @tailrec
    def allocSpaceIfNeededIter(value: Long): Unit = {
      val currentPageCount = getPageCount(allocatedBytes)
      val neededPageCount = getPageCount(value)

      if (currentPageCount < neededPageCount) {
        if (currentPageCount == pageCount) extendPages()

        streamBuffers(currentPageCount) = new Array[Byte](PAGE_SIZE)
        allocatedBytes = (currentPageCount + 1).toLong * PAGE_SIZE

        allocSpaceIfNeededIter(value)
      }
    }

    if (value < 0) throw new Error("AllocSpaceIfNeeded < 0")
    if (value > 0) {
      allocSpaceIfNeededIter(value)

      length = Math.max(value, length)
      if (position > length) position = length
    }
  }

  /**
    * Writes the specified byte to this output stream. The general
    * contract for <code>write</code> is that one byte is written
    * to the output stream. The byte to be written is the eight
    * low-order bits of the argument <code>b</code>. The 24
    * high-order bits of <code>b</code> are ignored.
    * <p>
    * Subclasses of <code>OutputStream</code> must provide an
    * implementation for this method.
    *
    * @param      b the <code>byte</code>.
    */
  @throws[IOException]
  override def write(b: Int): Unit = {
    val buffer: Array[Byte] = new Array[Byte](1)

    buffer(0) = b.toByte

    write(buffer)
  }

  /**
    * Writes <code>len</code> bytes from the specified byte array
    * starting at offset <code>off</code> to this output stream.
    * The general contract for <code>write(b, off, len)</code> is that
    * some of the bytes in the array <code>b</code> are written to the
    * output stream in order; element <code>b[off]</code> is the first
    * byte written and <code>b[off+len-1]</code> is the last byte written
    * by this operation.
    * <p>
    * The <code>write</code> method of <code>OutputStream</code> calls
    * the write method of one argument on each of the bytes to be
    * written out. Subclasses are encouraged to override this method and
    * provide a more efficient implementation.
    * <p>
    * If <code>b</code> is <code>null</code>, a
    * <code>NullPointerException</code> is thrown.
    * <p>
    * If <code>off</code> is negative, or <code>len</code> is negative, or
    * <code>off+len</code> is greater than the length of the array
    * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
    *
    * @param      b   the data.
    * @param      off the start offset in the data.
    * @param      len the number of bytes to write.
    */
  @throws[IOException]
  override def write(b: Array[Byte], off: Int, len: Int): Unit = {
    @tailrec
    def writeIter(b: Array[Byte], off: Int, len: Int): Unit = {
      val currentPage: Int = (position / PAGE_SIZE).toInt
      val currentOffset: Int = (position % PAGE_SIZE).toInt

      if (len != 0) {
        val currentLength: Int = Math.min(PAGE_SIZE - currentOffset, len)
        Array.copy(b, off, streamBuffers(currentPage), currentOffset, currentLength)

        position += currentLength

        writeIter(b, off + currentLength, len - currentLength)
      }
    }

    allocSpaceIfNeeded(position + len)
    writeIter(b, off, len)
  }

  /** Gets an InputStream that points to HugeMemoryOutputStream buffer
    *
    * @return InputStream
    */
  def asInputStream(): InputStream = {
    new HugeMemoryInputStream(streamBuffers, length)
  }

  private class HugeMemoryInputStream(streamBuffers: Array[Array[Byte]], val length: Long) extends InputStream {
    /** Current position in stream
      *
      */
    private var position: Long = 0

    /**
      * Reads the next byte of data from the input stream. The value byte is
      * returned as an <code>int</code> in the range <code>0</code> to
      * <code>255</code>. If no byte is available because the end of the stream
      * has been reached, the value <code>-1</code> is returned. This method
      * blocks until input data is available, the end of the stream is detected,
      * or an exception is thrown.
      *
      * <p> A subclass must provide an implementation of this method.
      *
      * @return the next byte of data, or <code>-1</code> if the end of the
      *         stream is reached.
      */
    @throws[IOException]
    def read: Int = {
      val buffer: Array[Byte] = new Array[Byte](1)

      if (read(buffer) == 0) throw new Error("End of stream")
      else buffer(0)
    }

    /**
      * Reads up to <code>len</code> bytes of data from the input stream into
      * an array of bytes.  An attempt is made to read as many as
      * <code>len</code> bytes, but a smaller number may be read.
      * The number of bytes actually read is returned as an integer.
      *
      * <p> This method blocks until input data is available, end of file is
      * detected, or an exception is thrown.
      *
      * <p> If <code>len</code> is zero, then no bytes are read and
      * <code>0</code> is returned; otherwise, there is an attempt to read at
      * least one byte. If no byte is available because the stream is at end of
      * file, the value <code>-1</code> is returned; otherwise, at least one
      * byte is read and stored into <code>b</code>.
      *
      * <p> The first byte read is stored into element <code>b[off]</code>, the
      * next one into <code>b[off+1]</code>, and so on. The number of bytes read
      * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
      * bytes actually read; these bytes will be stored in elements
      * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
      * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
      * <code>b[off+len-1]</code> unaffected.
      *
      * <p> In every case, elements <code>b[0]</code> through
      * <code>b[off]</code> and elements <code>b[off+len]</code> through
      * <code>b[b.length-1]</code> are unaffected.
      *
      * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
      * for class <code>InputStream</code> simply calls the method
      * <code>read()</code> repeatedly. If the first such call results in an
      * <code>IOException</code>, that exception is returned from the call to
      * the <code>read(b,</code> <code>off,</code> <code>len)</code> method.  If
      * any subsequent call to <code>read()</code> results in a
      * <code>IOException</code>, the exception is caught and treated as if it
      * were end of file; the bytes read up to that point are stored into
      * <code>b</code> and the number of bytes read before the exception
      * occurred is returned. The default implementation of this method blocks
      * until the requested amount of input data <code>len</code> has been read,
      * end of file is detected, or an exception is thrown. Subclasses are encouraged
      * to provide a more efficient implementation of this method.
      *
      * @param      b   the buffer into which the data is read.
      * @param      off the start offset in array <code>b</code>
      *                 at which the data is written.
      * @param      len the maximum number of bytes to read.
      * @return the total number of bytes read into the buffer, or
      *         <code>-1</code> if there is no more data because the end of
      *         the stream has been reached.
      * @see java.io.InputStream#read()
      */
    @throws[IOException]
    override def read(b: Array[Byte], off: Int, len: Int): Int = {
      @tailrec
      def readIter(acc: Int, b: Array[Byte], off: Int, len: Int): Int = {
        val currentPage: Int = (position / PAGE_SIZE).toInt
        val currentOffset: Int = (position % PAGE_SIZE).toInt

        val count: Int = Math.min(len, length - position).toInt

        if (count == 0 || position >= length) acc
        else {
          val currentLength = Math.min(PAGE_SIZE - currentOffset, count)
          Array.copy(streamBuffers(currentPage), currentOffset, b, off, currentLength)

          position += currentLength

          readIter(acc + currentLength, b, off + currentLength, len - currentLength)
        }
      }

      readIter(0, b, off, len)
    }

    /**
      * Skips over and discards <code>n</code> bytes of data from this input
      * stream. The <code>skip</code> method may, for a variety of reasons, end
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
      * This may result from any of a number of conditions; reaching end of file
      * before <code>n</code> bytes have been skipped is only one possibility.
      * The actual number of bytes skipped is returned. If <code>n</code> is
      * negative, the <code>skip</code> method for class <code>InputStream</code> always
      * returns 0, and no bytes are skipped. Subclasses may handle the negative
      * value differently.
      *
      * The <code>skip</code> method of this class creates a
      * byte array and then repeatedly reads into it until <code>n</code> bytes
      * have been read or the end of the stream has been reached. Subclasses are
      * encouraged to provide a more efficient implementation of this method.
      * For instance, the implementation may depend on the ability to seek.
      *
      * @param      n the number of bytes to be skipped.
      * @return the actual number of bytes skipped.
      */
    @throws[IOException]
    override def skip(n: Long): Long = {
      if (n < 0) 0
      else {
        position = Math.min(position + n, length)
        length - position
      }
    }
  }
}

ব্যবহার করা সহজ, কোনও বাফার নকল নয়, 2 জিবি মেমরির সীমা নেই

val out: HugeMemoryOutputStream = new HugeMemoryOutputStream(initialCapacity /*may be 0*/)

out.write(...)
...

val in1: InputStream = out.asInputStream()

in1.read(...)
...

val in2: InputStream = out.asInputStream()

in2.read(...)
...

-1

আপনি যদি একটি ইনপুট স্ট্রিম থেকে আউটপুট স্ট্রিম তৈরি করতে চান তবে একটি প্রাথমিক সমস্যা আছে। এটি শেষ না হওয়া অবধি কোনও আউটপুটস্ট্রিমে ব্লক করার পদ্ধতি। সুতরাং লেখার পদ্ধতি শেষ হয়ে গেলে ফলাফল পাওয়া যায়। এর দুটি পরিণতি রয়েছে:

  1. আপনি যদি কেবল একটি থ্রেড ব্যবহার করেন তবে সবকিছু না লেখা পর্যন্ত আপনাকে অপেক্ষা করতে হবে (যাতে আপনার স্ট্রিমের ডেটা মেমরি বা ডিস্কে সঞ্চয় করা দরকার)।
  2. এটি শেষ হওয়ার আগে যদি আপনি ডেটা অ্যাক্সেস করতে চান তবে আপনার দ্বিতীয় থ্রেডের প্রয়োজন।

বৈকল্পিক 1 বাইট অ্যারে ব্যবহার করে বা দায়ের করা যেতে পারে। পাইপগুলি ব্যবহার করে ভেরিয়েন্ট 1 প্রয়োগ করা যেতে পারে (হয় প্রত্যক্ষভাবে বা অতিরিক্ত বিমূর্ততার সাথে - যেমন রিংবফার বা অন্য মন্তব্য থেকে গুগল লিব)।

প্রকৃতপক্ষে স্ট্যান্ডার্ড জাভা সহ সমস্যাটি সমাধান করার কোনও উপায় নেই। প্রতিটি সমাধান এগুলির একটির একটি বাস্তবায়ন।

"ধারাবাহিকতা" নামে একটি ধারণা রয়েছে ( বিশদগুলির জন্য উইকিপিডিয়া দেখুন)। এক্ষেত্রে মূলত এর অর্থ:

  • একটি বিশেষ আউটপুট স্ট্রিম রয়েছে যা নির্দিষ্ট পরিমাণের ডেটা আশা করে
  • যদি পরিমাণ পৌঁছে যায়, তবে স্ট্রিমটি তার পাল্টাটিকে নিয়ন্ত্রণ দেয় যা একটি বিশেষ ইনপুট স্ট্রিম
  • ইনপুট স্ট্রিমটি পড়া না হওয়া অবধি ডেটার পরিমাণ উপলব্ধ করে দেয়, তারপরে, এটি নিয়ন্ত্রণটি আউটপুট প্রবাহে ফিরিয়ে দেয়

কিছু ভাষায় এই ধারণাটি তৈরি করা হয়েছে, জাভাটির জন্য আপনার কিছু "যাদু" প্রয়োজন। উদাহরণস্বরূপ জাভা জন্য অ্যাপাচি প্রয়োগ থেকে "কমন্স-জাভাফ্লো"। অসুবিধাটি হ'ল এর জন্য নির্মাণের সময় কিছু বিশেষ বাইকোড পরিবর্তন প্রয়োজন। সুতরাং কাস্টম বিল্ড স্ক্রিপ্টগুলির সাথে সমস্ত স্টোরকে একটি অতিরিক্ত লাইব্রেরিতে রাখার অর্থ হবে।


-1

পুরানো পোস্ট তবে অন্যকে সহায়তা করতে পারে, এইভাবে ব্যবহার করুন:

OutputStream out = new ByteArrayOutputStream();
...
out.write();
...
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(out.toString().getBytes()));

1
স্ট্রিং -> আকার সমস্যা
ব্যবহারকারী 1594895

এছাড়াও, toString().getBytes()একটি স্ট্রিম * এ কল করা প্রবাহের বিষয়বস্তু ফিরিয়ে দেবে না।
মার্টেন বোদেউয়েস

-1

আপনি যদি কোনও আউটপুট স্ট্রিমটিকে একটি ইনপুট স্ট্রিমে রূপান্তর করতে না পারেন তবে জাভা পাইপড আউটপুট স্ট্রিম এবং পাইপেড ইনপুট স্ট্রিম ব্যবহার করে এমন একটি উপায় সরবরাহ করে যা কোনও পাইপইডপুট স্ট্রিমের সাথে সম্পর্কিত পাইপডিনপুট স্ট্রিমের মাধ্যমে উপলব্ধ হয়ে ওঠার জন্য ডেটা থাকতে পারে।
তৃতীয় পক্ষের লাইব্রেরিগুলির সাথে ডিল করার সময় কিছুক্ষণ আগে আমি একইরকম পরিস্থিতির মুখোমুখি হয়েছিলাম যেগুলি একটি আউটপুট স্ট্রিম উদাহরণের পরিবর্তে তাদের কাছে একটি ইনপুট স্ট্রিম উদাহরণ পাঠানো দরকার।
আমি এই সমস্যাটি যেভাবে স্থির করেছি তা হ'ল পাইপড ইনপুটস্ট্রিম এবং পাইপড আউটপুট স্ট্রিম।
যেভাবে সেগুলি ব্যবহার করা কৌশলপূর্ণ এবং আপনি যা চান তা অর্জন করতে আপনাকে অবশ্যই মাল্টিথ্রেডিং ব্যবহার করতে হবে। আমি সম্প্রতি গিথুবে একটি বাস্তবায়ন প্রকাশ করেছি যা আপনি ব্যবহার করতে পারেন। লিঙ্কটি
এখানে । কীভাবে এটি ব্যবহার করতে হয় তা বুঝতে আপনি উইকির মাধ্যমে যেতে পারেন।

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