ByteArrayOutputStream क्लास आउटपुट स्ट्रीम लागू करतो जो बाइट अॅरेवर डेटा लिहितो . डेटा लिहिला गेल्याने बफर आपोआप वाढतो.

ByteArrayOutputStream क्लास मेमरीमध्ये बफर तयार करतो आणि स्ट्रीमला पाठवलेला सर्व डेटा बफरमध्ये साठवला जातो.

ByteArrayOutputStream कन्स्ट्रक्टर

ByteArrayOutputStream वर्गात खालील कन्स्ट्रक्टर आहेत:

कन्स्ट्रक्टर
ByteArrayOutputStream() हा कन्स्ट्रक्टर 32 बाइट लांबीचा इन-मेमरी बफर तयार करतो.
ByteArrayOutputStream(int a) हा कन्स्ट्रक्टर विशिष्ट आकारासह इन-मेमरी बफर तयार करतो.

आणि वर्ग आतून असे दिसते:


// The buffer itself, where the data is stored.
protected byte buf[];

// Current number of bytes written to the buffer.
protected int count;

public ByteArrayOutputStream() {
    this(32);
}

public ByteArrayOutputStream(int size) {
    if (size < 0) {
        throw new IllegalArgumentException("Negative initial size: "
                                           + size);
    }
    buf = new byte[size];
}
    

ByteArrayOutputStream वर्गाच्या पद्धती

आपण आपल्या वर्गात कोणत्या पद्धती वापरू शकतो याबद्दल बोलूया.

चला आपल्या प्रवाहात काहीतरी ठेवण्याचा प्रयत्न करूया. हे करण्यासाठी, आम्ही write() पद्धत वापरू - ती एक बाइट किंवा लेखनासाठी बाइट्सचा संच स्वीकारू शकते.

पद्धत
निरर्थक लेखन (int b) एक बाइट लिहितो.
शून्य लेखन (बाइट बी[], इंट ऑफ, इंट लेन) विशिष्ट आकाराच्या बाइट्सचा अॅरे लिहितो.
शून्य लेखनबाइट्स(बाइट ब[]) बाइट्सचा अ‍ॅरे लिहितो.
व्हॉइड राइटटू (आउटपुटस्ट्रीम आउट) वर्तमान आउटपुट प्रवाहापासून पास केलेल्या आउटपुट प्रवाहापर्यंत सर्व डेटा लिहितो.

पद्धत अंमलबजावणी:


public static void main(String[] args) throws IOException {
   ByteArrayOutputStream outputByte = new ByteArrayOutputStream();
   // Write one byte
   while(outputByte.size()!= 7) {
      outputByte.write("codegym".getBytes());
   }

   // Write array of bytes
   String value = "\nWelcome to Java\n";
   byte[] arrBytes = value.getBytes();
   outputByte.write(arrBytes);

   // Write part of an array
   String codeGym = "CodeGym";
   byte[] b = codeGym.getBytes();
   outputByte.write(b, 4, 3);

   // Write to a file
   FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
   outputByte.write(80);
   outputByte.writeTo(fileOutputStream);
}
    

परिणाम एक नवीन output.txt फाइल आहे जी यासारखी दिसते:

toByteArray () पद्धत या आउटपुट प्रवाहातील वर्तमान सामग्री बाइट्सच्या अॅरे म्हणून परत करते. आणि मजकूर म्हणून buf बाइट अॅरे मिळविण्यासाठी तुम्ही toString() पद्धत वापरू शकता :


public static void main(String[] args) throws IOException {
    ByteArrayOutputStream outputByte = new ByteArrayOutputStream();

    String value = "CodeGym";
    outputByte.write(value.getBytes());

    byte[] result = outputByte.toByteArray();
    System.out.println("Result: ");

    for(int i = 0 ; i < result.length; i++) {
        // Display the characters
        System.out.print((char)result[i]);
    }
}
    

आमच्या बफरमध्ये आम्ही दिलेला बाइट अॅरे आहे.

reset () पद्धत बाइट अॅरे आउटपुट प्रवाहातील वैध बाइट्सची संख्या शून्यावर रीसेट करते (म्हणून आउटपुटमध्ये जमा केलेली प्रत्येक गोष्ट रीसेट केली जाते).


public static void main(String[] args) throws IOException {
   ByteArrayOutputStream outputByte = new ByteArrayOutputStream(120);

   String value = "CodeGym";
   outputByte.write(value.getBytes());
   byte[] result = outputByte.toByteArray();
   System.out.println("Output before reset: ");

   for (byte b : result) {
      // Display the characters
      System.out.print((char) b);
   }

   outputByte.reset();

   byte[] resultAfterReset = outputByte.toByteArray();
   System.out.println("\nOutput after reset: ");

   for (byte b : resultAfterReset) {
      // Display the characters
      System.out.print((char) b);
   }
}
    

जेव्हा आम्ही reset() मेथड कॉल केल्यानंतर आमचा बफर प्रदर्शित करतो , तेव्हा आम्हाला काहीही मिळत नाही.

क्लोज() पद्धतीची विशिष्ट वैशिष्ट्ये

ही पद्धत विशेष लक्ष देण्यास पात्र आहे. ते काय करते हे समजून घेण्यासाठी, आत डोकावून पाहू:


/**
 * Closing a {@code ByteArrayOutputStream} has no effect. The methods in
 * this class can be called after the stream has been closed without
 * generating an {@code IOException}.
 */
public void close() throws IOException {
}
    

लक्षात घ्या की ByteArrayOutputStream क्लासची close() पद्धत प्रत्यक्षात काहीही करत नाही.

अस का? ByteArrayOutputStream हा मेमरी-आधारित प्रवाह आहे (म्हणजे, कोडमध्ये वापरकर्त्याद्वारे ते व्यवस्थापित आणि पॉप्युलेट केले जाते), त्यामुळे close() कॉल करण्याचा कोणताही परिणाम होत नाही.

सराव

आता आमची ByteArrayOutputStream आणि ByteArrayInputStream वापरून फाइल प्रणाली लागू करण्याचा प्रयत्न करूया .

सिंगलटन डिझाइन पॅटर्न वापरून फाइलसिस्टम क्लास लिहू आणि स्टॅटिक हॅशमॅप<स्ट्रिंग, बाइट[]> वापरू , जिथे:

  • स्ट्रिंग हा फाईलचा मार्ग आहे
  • byte[] हा सेव्ह केलेल्या फाइलमधील डेटा आहे

import java.io.*;
import java.util.HashMap;
import java.util.Map;

class FileSystem {
   private static final FileSystem fileSystem = new FileSystem();
   private static final Map<String, byte[]> files = new HashMap<>();

   private FileSystem() {
   }

   public static FileSystem getFileSystem() {
       return fileSystem;
   }

   public void create(String path) {
       validateNotExists(path);
       files.put(path, new byte[0]);
   }

   public void delete(String path) {
       validateExists(path);
       files.remove(path);
   }

   public boolean isExists(String path) {
       return files.containsKey(path);
   }

   public InputStream newInputStream(String path) {
       validateExists(path);
       return new ByteArrayInputStream(files.get(path));
   }

   public OutputStream newOutputStream(String path) {
       validateExists(path);
       return new ByteArrayOutputStream() {
           @Override
           public void flush() throws IOException {
               final byte[] bytes = toByteArray();
               files.put(path, bytes);
               super.flush();
           }

           @Override
           public void close() throws IOException {
               final byte[] bytes = toByteArray();
               files.put(path, bytes);
               super.close();
           }
       };
   }

   private void validateExists(String path) {
       if (!files.containsKey(path)) {
           throw new RuntimeException("File not found");
       }
   }

   private void validateNotExists(String path) {
       if (files.containsKey(path)) {
           throw new RuntimeException("File exists");
       }
   }
}
    

या वर्गात, आम्ही खालील सार्वजनिक पद्धती तयार केल्या आहेत:

  • मानक CRUD पद्धती (तयार करा, वाचा, अपडेट करा, हटवा),
  • फाइल अस्तित्वात आहे की नाही हे तपासण्याची पद्धत,
  • फाइल सिस्टमचे उदाहरण मिळविण्याची पद्धत.

फाइलमधून वाचण्यासाठी, आम्ही इनपुटस्ट्रीम परत करतो . हुड अंतर्गत ByteArrayInputStream अंमलबजावणी आहे. बफर हा फाईल्स मॅपमध्ये संग्रहित केलेला बाइट अॅरे आहे.

दुसरी मनोरंजक पद्धत म्हणजे newOutputStream . जेव्हा ही पद्धत कॉल केली जाते, तेव्हा आम्ही एक नवीन ByteArrayOutputStream ऑब्जेक्ट परत करतो जो दोन पद्धती ओव्हरराइड करतो: flush आणि close . यापैकी कोणत्याही पद्धतीला कॉल केल्याने लेखन घडले पाहिजे.

आणि आम्ही तेच करतो: आम्हाला वापरकर्त्याने लिहिलेला बाइट अॅरे मिळतो आणि एक प्रतमूल्ययोग्य की सह फाईल्स मॅपमध्ये .

आमची फाइल सिस्टम (FS) तपासण्यासाठी आम्ही खालील कोड वापरतो:


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import static java.nio.charset.StandardCharsets.UTF_8;

public class MyFileSystemTest {
   public static void main(String[] args) throws IOException {
       FileSystem fileSystem = FileSystem.getFileSystem();
       final String path = "/user/bin/data.txt";

       // Create a file
       fileSystem.create(path);
       System.out.println("File created successfully");

       // Make sure it's empty
       try (InputStream inputStream = fileSystem.newInputStream(path)) {
           System.out.print("File contents:\t");
           System.out.println(read(inputStream));
       }

       // Write data to it
       try (final OutputStream outputStream = fileSystem.newOutputStream(path)) {
           outputStream.write("CodeGym".getBytes(UTF_8));
           System.out.println("Data written to file");
       }

       // Read data
       try (InputStream inputStream = fileSystem.newInputStream(path)) {
           System.out.print("File contents:\t");
           System.out.println(read(inputStream));
       }

       // Delete the file
       fileSystem.delete(path);

       // Verify that the file does not exist in the FS
       System.out.print("File exists:\t");
       System.out.println(fileSystem.isExists(path));

   }

   private static String read(InputStream inputStream) throws IOException {
       return new String(inputStream.readAllBytes(), UTF_8);
   }
}
    

चाचणी दरम्यान, आम्ही खालील क्रिया सत्यापित करतो:

  1. आम्ही एक नवीन फाइल तयार करतो.
  2. तयार केलेली फाईल रिकामी असल्याचे आम्ही तपासतो.
  3. आम्ही फाइलमध्ये काही डेटा लिहितो.
  4. आम्ही डेटा परत वाचतो आणि आम्ही लिहिलेल्या गोष्टींशी जुळतो याची पडताळणी करतो.
  5. आम्ही फाइल हटवतो.
  6. आम्ही सत्यापित करतो की फाइल हटविली गेली आहे.

हा कोड चालवल्याने आम्हाला हे आउटपुट मिळते:

फाइल यशस्वीरित्या तयार केली
फाइल सामग्री:
फाइल फाइल करण्यासाठी लिहिलेला डेटा
फाइल सामग्री: CodeGym
फाइल अस्तित्वात आहे: असत्य

हे उदाहरण का आवश्यक होते?

सोप्या भाषेत सांगायचे तर डेटा हा नेहमीच बाइट्सचा संच असतो. तुम्हाला डिस्कवरून/वर भरपूर डेटा वाचण्याची/लिहायची असल्यास, तुमचा कोड I/O समस्यांमुळे हळू चालेल. या प्रकरणात, RAM मध्‍ये व्हर्च्युअल फाइल सिस्‍टम राखण्‍यास अर्थ आहे, जसे आपण पारंपारिक डिस्कसह कार्य कराल. आणि InputStream आणि OutputStream पेक्षा सोपे काय असू शकते ?

अर्थात, हे निर्देशांचे उदाहरण आहे, उत्पादन-तयार कोड नाही. याचा हिशेब नाही (खालील यादी सर्वसमावेशक नाही):

  • मल्टीथ्रेडिंग
  • फाइल आकार मर्यादा (चालू JVM साठी उपलब्ध RAM चे प्रमाण)
  • पथ संरचनेची पडताळणी
  • पद्धत युक्तिवादांची पडताळणी

स्वारस्यपूर्ण आंतरिक माहिती:
CodeGym कार्य पडताळणी सर्व्हर काहीसा समान दृष्टीकोन वापरतो. आम्ही व्हर्च्युअल FS फिरवतो, कार्य पडताळणीसाठी कोणत्या चाचण्या चालवायला हव्यात हे ठरवतो, चाचण्या चालवतो आणि परिणाम वाचतो.

निष्कर्ष आणि मोठा प्रश्न

हा धडा वाचल्यानंतर मोठा प्रश्न असा आहे की "मी फक्त byte[] का वापरू शकत नाही , कारण ते अधिक सोयीचे आहे आणि त्यावर बंधने लादत नाहीत?"

ByteArrayInputStream चा फायदा असा आहे की ते सशक्तपणे सूचित करते की तुम्ही केवळ-वाचनीय बाइट्स वापरणार आहात (कारण प्रवाह त्याची सामग्री बदलण्यासाठी इंटरफेस प्रदान करत नाही). ते म्हणाले, हे लक्षात घेणे महत्त्वाचे आहे की प्रोग्रामर अद्याप बाइट्समध्ये थेट प्रवेश करू शकतो .

परंतु काहीवेळा आपल्याकडे बाइट[] असल्यास , काहीवेळा आपल्याकडे फाईल असेल, काहीवेळा आपल्याकडे नेटवर्क कनेक्शन असेल आणि असेच, आपल्याला "बाइट्सच्या प्रवाहासाठी काही प्रकारचे अ‍ॅब्स्ट्रॅक्शन आवश्यक असेल आणि ते कुठे आहेत याची मला पर्वा नाही. कडून आला आहे". आणि तेच InputStream आहे. जेव्हा स्त्रोत बाइट अॅरे असेल तेव्हा, ByteArrayInputStream वापरण्यासाठी एक चांगला इनपुटस्ट्रीम आहे.

हे बर्याच परिस्थितींमध्ये उपयुक्त आहे, परंतु येथे दोन विशिष्ट उदाहरणे आहेत:

  1. तुम्ही लायब्ररी लिहित आहात जी बाइट्स मिळवते आणि त्यावर कशी तरी प्रक्रिया करते (उदाहरणार्थ, समजा ती इमेज प्रोसेसिंग युटिलिटीजची लायब्ररी आहे). तुमच्या लायब्ररीचे वापरकर्ते फाईल, इन-मेमरी बाइट[] वरून किंवा इतर स्त्रोतांकडून बाइट देऊ शकतात. त्यामुळे तुम्ही एक इंटरफेस प्रदान करा जो एक InputStream स्वीकारतो , याचा अर्थ त्यांच्याकडे बाइट[] असल्यास , त्यांना ते ByteArrayInputStream मध्ये गुंडाळणे आवश्यक आहे .

  2. तुम्ही कोड लिहित आहात जो नेटवर्क कनेक्शन वाचतो. परंतु या कोडवर युनिट चाचण्या करण्यासाठी, तुम्ही कनेक्शन उघडू इच्छित नाही — तुम्हाला फक्त कोडमध्ये काही बाइट्स फीड करायचे आहेत. त्यामुळे कोड एक इनपुटस्ट्रीम घेते आणि तुमची चाचणी ByteArrayInputStream मध्ये पास होते .