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 క్లాస్ యొక్క పద్ధతులు

మన తరగతిలో మనం ఉపయోగించగల పద్ధతుల గురించి మాట్లాడుకుందాం.

మన స్ట్రీమ్‌లో ఏదైనా పెట్టడానికి ప్రయత్నిద్దాం. దీన్ని చేయడానికి, మేము వ్రాసే () పద్ధతిని ఉపయోగిస్తాము - ఇది వ్రాయడానికి ఒక బైట్ లేదా బైట్‌ల సమితిని అంగీకరించవచ్చు.

పద్ధతి
శూన్యం వ్రాయడం (పూర్ణాంక బి) ఒక బైట్ వ్రాస్తుంది.
శూన్యం వ్రాయడం (బైట్ బి[], పూర్ణాంక ఆఫ్, ఇంట్ లెన్) నిర్దిష్ట పరిమాణంలోని బైట్‌ల శ్రేణిని వ్రాస్తుంది.
శూన్యం రైట్ బైట్‌లు(బైట్ బి[]) బైట్‌ల శ్రేణిని వ్రాస్తుంది.
రాయడానికి శూన్యం (అవుట్‌పుట్ స్ట్రీమ్ అవుట్) ప్రస్తుత అవుట్‌పుట్ స్ట్రీమ్ నుండి పాస్ అయిన అవుట్‌పుట్ స్ట్రీమ్‌కు మొత్తం డేటాను వ్రాస్తుంది.

విధానం అమలు:


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 () పద్ధతి ఈ అవుట్‌పుట్ స్ట్రీమ్‌లోని ప్రస్తుత కంటెంట్‌లను బైట్‌ల శ్రేణిగా అందిస్తుంది. మరియు మీరు బఫ్ బైట్ శ్రేణిని టెక్స్ట్‌గా పొందడానికి 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]);
    }
}
    

మా బఫర్‌లో మనం పంపిన బైట్ శ్రేణి ఉంది.

రీసెట్ () పద్ధతి బైట్ అర్రే అవుట్‌పుట్ స్ట్రీమ్‌లోని చెల్లుబాటు అయ్యే బైట్‌ల సంఖ్యను సున్నాకి రీసెట్ చేస్తుంది (కాబట్టి అవుట్‌పుట్‌లో సేకరించిన ప్రతిదీ రీసెట్ చేయబడుతుంది).


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

రీసెట్() పద్ధతికి కాల్ చేసిన తర్వాత మన బఫర్‌ని ప్రదర్శించినప్పుడు , మనకు ఏమీ లభించదు.

క్లోజ్() పద్ధతి యొక్క నిర్దిష్ట లక్షణాలు

ఈ పద్ధతి ప్రత్యేక శ్రద్ధ అవసరం. ఇది ఏమి చేస్తుందో అర్థం చేసుకోవడానికి, లోపలికి చూద్దాం:


/**
 * 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 క్లాస్ క్లోజ్() పద్ధతి నిజానికి ఏమీ చేయదని గమనించండి .

అది ఎందుకు? ఒక ByteArrayOutputStream అనేది మెమరీ-ఆధారిత స్ట్రీమ్ (అంటే, ఇది కోడ్‌లో వినియోగదారుచే నిర్వహించబడుతుంది మరియు జనాభా చేయబడుతుంది), కాబట్టి క్లోజ్() కి కాల్ చేయడం వల్ల ఎటువంటి ప్రభావం ఉండదు.

సాధన

ఇప్పుడు మన ByteArrayOutputStream మరియు ByteArrayInputStream ఉపయోగించి ఫైల్ సిస్టమ్‌ను అమలు చేయడానికి ప్రయత్నిద్దాం .

సింగిల్‌టన్ డిజైన్ నమూనాను ఉపయోగించి ఫైల్‌సిస్టమ్ క్లాస్‌ని వ్రాద్దాం మరియు స్టాటిక్ హాష్‌మ్యాప్<స్ట్రింగ్, బైట్[]> , ఇక్కడ:

  • స్ట్రింగ్ అనేది ఫైల్‌కి మార్గం
  • బైట్[] అనేది సేవ్ చేయబడిన ఫైల్‌లోని డేటా

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 ఆబ్జెక్ట్‌ను తిరిగి అందిస్తాము: ఫ్లష్ మరియు క్లోజ్ . ఈ పద్ధతుల్లో దేనినైనా కాల్ చేయడం వలన వ్రాయడం జరుగుతుంది.

మరియు మనం చేసేది అదే: వినియోగదారు వ్రాసిన బైట్ శ్రేణిని మేము పొందుతాము మరియు కాపీని ఇలా నిల్వ చేస్తామువిలువతగిన కీతో ఫైల్‌ల మ్యాప్‌లో .

మా ఫైల్ సిస్టమ్ (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 సమస్యల కారణంగా మీ కోడ్ నెమ్మదిగా రన్ అవుతుంది. ఈ సందర్భంలో, ర్యామ్‌లో వర్చువల్ ఫైల్ సిస్టమ్‌ను నిర్వహించడం అర్ధమే, దానితో మీరు సాంప్రదాయ డిస్క్‌తో అదే విధంగా పని చేస్తారు. మరియు InputStream మరియు OutputStream కంటే సరళమైనది ఏది ?

వాస్తవానికి, ఇది సూచనల కోసం ఒక ఉదాహరణ, ఉత్పత్తికి సిద్ధంగా ఉన్న కోడ్ కాదు. ఇది పరిగణనలోకి తీసుకోదు (క్రింది జాబితా సమగ్రమైనది కాదు):

  • మల్టీథ్రెడింగ్
  • ఫైల్ పరిమాణ పరిమితులు (నడుస్తున్న JVM కోసం అందుబాటులో ఉన్న RAM మొత్తం)
  • మార్గం నిర్మాణం యొక్క ధృవీకరణ
  • పద్ధతి వాదనల ధృవీకరణ

ఆసక్తికరమైన అంతర్గత సమాచారం:
CodeGym టాస్క్ వెరిఫికేషన్ సర్వర్ కొంతవరకు సారూప్య విధానాన్ని ఉపయోగిస్తుంది. మేము వర్చువల్ FSని స్పిన్ అప్ చేస్తాము, టాస్క్ వెరిఫికేషన్ కోసం ఏ పరీక్షలను అమలు చేయాలో నిర్ణయిస్తాము, పరీక్షలను అమలు చేస్తాము మరియు ఫలితాలను చదవండి.

ముగింపు మరియు పెద్ద ప్రశ్న

ఈ పాఠం చదివిన తర్వాత పెద్ద ప్రశ్న ఏమిటంటే "నేను బైట్‌ని ఎందుకు ఉపయోగించలేను [] , ఎందుకంటే ఇది మరింత సౌకర్యవంతంగా ఉంటుంది మరియు పరిమితులను విధించదు?"

ByteArrayInputStream యొక్క ప్రయోజనం ఏమిటంటే, మీరు చదవడానికి-మాత్రమే బైట్‌లను ఉపయోగించబోతున్నారని ఇది బలంగా సూచిస్తుంది (ఎందుకంటే స్ట్రీమ్ దాని కంటెంట్‌ను మార్చడానికి ఇంటర్‌ఫేస్‌ను అందించదు). ప్రోగ్రామర్ ఇప్పటికీ బైట్‌లను నేరుగా యాక్సెస్ చేయగలరని గమనించడం ముఖ్యం .

కానీ కొన్నిసార్లు మీ వద్ద బైట్[] ఉంటే , కొన్నిసార్లు మీ వద్ద ఫైల్ ఉంటుంది, కొన్నిసార్లు మీకు నెట్‌వర్క్ కనెక్షన్ ఉంటుంది, ఇంకా ఇలా ఉంటే, మీకు "బైట్‌ల స్ట్రీమ్‌కి ఒక రకమైన సంగ్రహణ అవసరం అవుతుంది మరియు అవి ఎక్కడ ఉన్నాయో నేను పట్టించుకోను. నుండి వచ్చి". మరియు ఇన్‌పుట్‌స్ట్రీమ్ అంటే అదే . మూలం బైట్ శ్రేణి అయినప్పుడు, ByteArrayInputStream ఉపయోగించడానికి మంచి ఇన్‌పుట్ స్ట్రీమ్ .

ఇది చాలా సందర్భాలలో ఉపయోగకరంగా ఉంటుంది, కానీ ఇక్కడ రెండు నిర్దిష్ట ఉదాహరణలు ఉన్నాయి:

  1. మీరు బైట్‌లను స్వీకరించి వాటిని ఎలాగైనా ప్రాసెస్ చేసే లైబ్రరీని వ్రాస్తున్నారు (ఉదాహరణకు, ఇది ఇమేజ్ ప్రాసెసింగ్ యుటిలిటీల లైబ్రరీ అని అనుకుందాం). మీ లైబ్రరీ యొక్క వినియోగదారులు ఫైల్ నుండి బైట్‌లను అందించగలరు, ఇన్-మెమరీ బైట్[] , లేదా మరేదైనా మూలం నుండి. కాబట్టి మీరు ఇన్‌పుట్‌స్ట్రీమ్‌ను ఆమోదించే ఇంటర్‌ఫేస్‌ను అందిస్తారు , అంటే వారికి బైట్[] ఉంటే, వారు దానిని బైట్‌అర్రేఇన్‌పుట్‌స్ట్రీమ్‌లో చుట్టాలి .

  2. మీరు నెట్‌వర్క్ కనెక్షన్‌ని చదివే కోడ్‌ని వ్రాస్తున్నారు. కానీ ఈ కోడ్‌పై యూనిట్ పరీక్షలను నిర్వహించడానికి, మీరు కనెక్షన్‌ని తెరవకూడదు — మీరు కోడ్‌కి కొన్ని బైట్‌లను అందించాలనుకుంటున్నారు. కాబట్టి కోడ్ ఇన్‌పుట్ స్ట్రీమ్‌ను తీసుకుంటుంది మరియు మీ పరీక్ష బైట్అర్రేఇన్‌పుట్ స్ట్రీమ్‌లో పాస్ అవుతుంది .