A ByteArrayOutputStream osztály egy kimeneti adatfolyamot valósít meg, amely adatokat ír egy bájttömbbe. A puffer automatikusan növekszik, amikor adatot írnak bele.
A ByteArrayOutputStream osztály puffert hoz létre a memóriában, és az adatfolyamba küldött összes adat a pufferben tárolódik.

ByteArrayOutputStream konstruktorok
A ByteArrayOutputStream osztály a következő konstruktorokkal rendelkezik:
Konstruktőr | |
---|---|
ByteArrayOutputStream() | Ez a konstruktor egy 32 bájt hosszúságú memórián belüli puffert hoz létre. |
ByteArrayOutputStream(int a) | Ez a konstruktor meghatározott méretű memórián belüli puffert hoz létre. |
És így néz ki belülről az osztály:
// 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];
}
A ByteArrayOutputStream osztály módszerei
Beszéljünk azokról a módszerekről, amelyeket az osztályunkban használhatunk.
Próbáljunk meg valamit betenni a folyamunkba. Ehhez a write() metódust használjuk – ez egy bájtot vagy bájtkészletet tud elfogadni az íráshoz.
Módszer | |
---|---|
érvénytelen írás (b int) | Egy bájtot ír. |
void write (bájt b[], int off, int len) | Egy adott méretű bájttömböt ír. |
void writeBytes(bájt b[]) | Egy bájttömböt ír. |
void writeTo (OutputStream out) | Minden adatot ír az aktuális kimeneti adatfolyamból az átadott kimeneti adatfolyamba. |
A módszer megvalósítása:
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);
}
Az eredmény egy új output.txt fájl, amely így néz ki:

A toByteArray() metódus ennek a kimeneti adatfolyamnak az aktuális tartalmát adja vissza bájtok tömbjeként. És használhatja a toString() metódust is, hogy a buf bájttömböt szövegként kapja meg :
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]);
}
}
A pufferünk tartalmazza azt a bájttömböt, amelyet átadtunk neki.
A reset() metódus nullára állítja a bájttömb kimeneti adatfolyamának érvényes bájtok számát (tehát a kimenetben felhalmozott minden visszaállításra kerül).
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);
}
}
Amikor a reset() metódus meghívása után megjelenítjük a pufferünket , nem kapunk semmit.
A close() metódus sajátosságai
Ez a módszer különös figyelmet érdemel. Hogy megértsük, mit csinál, vessünk egy pillantást a belsejébe:
/**
* 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 {
}
Vegye figyelembe, hogy a ByteArrayOutputStream osztály close() metódusa valójában nem csinál semmit.
Miert van az? A ByteArrayOutputStream egy memória alapú adatfolyam (azaz a felhasználó kezeli és tölti fel kódban), így a close() hívásnak nincs hatása.
Gyakorlat
Most próbáljunk meg egy fájlrendszert megvalósítani a ByteArrayOutputStream és a ByteArrayInputStream segítségével .
Írjunk egy FileSystem osztályt a singleton tervezési mintával, és használjunk egy statikus HashMap<String, byte[]> értéket , ahol:
- A karakterlánc a fájl elérési útja
- bájt[] a mentett fájlban lévő adat
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");
}
}
}
Ebben az osztályban a következő nyilvános metódusokat hoztuk létre:
- szabványos CRUD módszerek (létrehozás, olvasás, frissítés, törlés),
- egy módszer annak ellenőrzésére, hogy létezik-e fájl,
- egy módszer a fájlrendszer egy példányának beszerzésére.
Fájlból való olvasáshoz az InputStream értéket adjuk vissza . A motorháztető alatt a ByteArrayInputStream megvalósítás található. A puffer a fájlleképezésben tárolt bájttömb .
Egy másik érdekes módszer a newOutputStream . A metódus meghívásakor egy új ByteArrayOutputStream objektumot adunk vissza, amely felülír két módszert: flush és close . E metódusok bármelyikének meghívása az írást eredményezi.
És pontosan ezt tesszük: megkapjuk a bájttömböt, amelybe a felhasználó írt, és eltároljuk a másolatotértéka fájlleképezésben egy megfelelő kulccsal.
A következő kódot használjuk a fájlrendszerünk (FS) teszteléséhez:
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);
}
}
A teszt során a következő műveleteket ellenőrizzük:
- Létrehozunk egy új fájlt.
- Ellenőrizzük, hogy a létrehozott fájl üres-e.
- Néhány adatot írunk a fájlba.
- Visszaolvasjuk az adatokat, és ellenőrizzük, hogy megegyeznek-e azzal, amit írtunk.
- Töröljük a fájlt.
- Ellenőrizzük, hogy a fájlt törölték-e.
Ennek a kódnak a futtatása a következő kimenetet adja:
Fájltartalom:
Fájlba írt adatok Fájltartalom
: CodeGym
A fájl létezik: false
Miért volt szükség erre a példára?
Egyszerűen fogalmazva, az adatok mindig bájtok halmazai. Ha sok adatot kell olvasnia/írnia a lemezről/lemezre, a kód lassan fut az I/O problémák miatt. Ebben az esetben érdemes egy virtuális fájlrendszert a RAM-ban karbantartani, ugyanúgy dolgozni vele, mint egy hagyományos lemezzel. És mi lehetne egyszerűbb, mint az InputStream és az OutputStream ?
Természetesen ez egy példa az utasításokhoz, nem a gyártásra kész kód. NEM számol (a következő lista nem teljes):
- többszálú
- fájlméret-korlátok (a rendelkezésre álló RAM mennyisége egy futó JVM-hez)
- az útvonalszerkezet ellenőrzése
- metódus argumentumok ellenőrzése
Érdekes bennfentes információ:
A CodeGym feladatellenőrző szervere némileg hasonló megközelítést alkalmaz. Felpörgetünk egy virtuális FS-t, meghatározzuk, mely teszteket kell futtatni a feladat ellenőrzéséhez, lefuttatjuk a teszteket, és elolvassuk az eredményeket.
Következtetés és a nagy kérdés
A nagy kérdés a lecke elolvasása után az, hogy "Miért nem használhatom a byte[]-t , mivel az kényelmesebb és nem szab meg korlátozásokat?"
A ByteArrayInputStream előnye, hogy erős azt jelzi, hogy csak olvasható bájtokat fog használni (mivel az adatfolyam nem biztosít felületet a tartalom megváltoztatásához). Ennek ellenére fontos megjegyezni, hogy a programozó továbbra is közvetlenül hozzáférhet a bájtokhoz.
De ha néha van egy bájt[] , néha van egy fájl, néha van hálózati kapcsolat, és így tovább, akkor szüksége lesz valamiféle absztrakcióra "egy bájtfolyamhoz, és nem érdekel, hol jönni valahonnan". És ez az InputStream . Ha a forrás történetesen egy bájttömb, a ByteArrayInputStream jó InputStream használható.
Ez sok esetben hasznos, de itt van két konkrét példa:
-
Olyan könyvtárat ír, amely fogadja a bájtokat, és valahogy feldolgozza azokat (például tegyük fel, hogy ez egy képfeldolgozó segédprogramok könyvtára). A könyvtár felhasználói bájtokat biztosíthatnak fájlból, a memóriában lévő bájtból [] vagy más forrásból. Tehát olyan felületet adsz meg, amely elfogad egy InputStream -et , ami azt jelenti, hogy ha van egy byte[] , akkor azt egy ByteArrayInputStream- be kell csomagolniuk .
-
Olyan kódot ír, amely beolvassa a hálózati kapcsolatot. De ahhoz, hogy egységteszteket hajtson végre ezen a kódon, nem akar kapcsolatot nyitni, hanem csak néhány bájtot szeretne betáplálni a kódba. Tehát a kód egy InputStream-et vesz fel , a teszt pedig egy ByteArrayInputStream-en megy át .
GO TO FULL VERSION