Path: blob/master/src/java.base/share/classes/java/io/DataOutputStream.java
41152 views
/*1* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;2627/**28* A data output stream lets an application write primitive Java data29* types to an output stream in a portable way. An application can30* then use a data input stream to read the data back in.31* <p>32* A DataOutputStream is not safe for use by multiple concurrent33* threads. If a DataOutputStream is to be used by more than one34* thread then access to the data output stream should be controlled35* by appropriate synchronization.36*37* @see java.io.DataInputStream38* @since 1.039*/40public class DataOutputStream extends FilterOutputStream implements DataOutput {41/**42* The number of bytes written to the data output stream so far.43* If this counter overflows, it will be wrapped to Integer.MAX_VALUE.44*/45protected int written;4647/**48* bytearr is initialized on demand by writeUTF49*/50private byte[] bytearr = null;5152private final byte[] writeBuffer = new byte[8];5354/**55* Creates a new data output stream to write data to the specified56* underlying output stream. The counter {@code written} is57* set to zero.58*59* @param out the underlying output stream, to be saved for later60* use.61* @see java.io.FilterOutputStream#out62*/63public DataOutputStream(OutputStream out) {64super(out);65}6667/**68* Increases the written counter by the specified value69* until it reaches Integer.MAX_VALUE.70*/71private void incCount(int value) {72int temp = written + value;73if (temp < 0) {74temp = Integer.MAX_VALUE;75}76written = temp;77}7879/**80* Writes the specified byte (the low eight bits of the argument81* {@code b}) to the underlying output stream. If no exception82* is thrown, the counter {@code written} is incremented by83* {@code 1}.84* <p>85* Implements the {@code write} method of {@code OutputStream}.86*87* @param b the {@code byte} to be written.88* @throws IOException if an I/O error occurs.89* @see java.io.FilterOutputStream#out90*/91public synchronized void write(int b) throws IOException {92out.write(b);93incCount(1);94}9596/**97* Writes {@code len} bytes from the specified byte array98* starting at offset {@code off} to the underlying output stream.99* If no exception is thrown, the counter {@code written} is100* incremented by {@code len}.101*102* @param b the data.103* @param off the start offset in the data.104* @param len the number of bytes to write.105* @throws IOException if an I/O error occurs.106* @see java.io.FilterOutputStream#out107*/108public synchronized void write(byte b[], int off, int len)109throws IOException110{111out.write(b, off, len);112incCount(len);113}114115/**116* Flushes this data output stream. This forces any buffered output117* bytes to be written out to the stream.118* <p>119* The {@code flush} method of {@code DataOutputStream}120* calls the {@code flush} method of its underlying output stream.121*122* @throws IOException if an I/O error occurs.123* @see java.io.FilterOutputStream#out124* @see java.io.OutputStream#flush()125*/126public void flush() throws IOException {127out.flush();128}129130/**131* Writes a {@code boolean} to the underlying output stream as132* a 1-byte value. The value {@code true} is written out as the133* value {@code (byte)1}; the value {@code false} is134* written out as the value {@code (byte)0}. If no exception is135* thrown, the counter {@code written} is incremented by136* {@code 1}.137*138* @param v a {@code boolean} value to be written.139* @throws IOException if an I/O error occurs.140* @see java.io.FilterOutputStream#out141*/142public final void writeBoolean(boolean v) throws IOException {143out.write(v ? 1 : 0);144incCount(1);145}146147/**148* Writes out a {@code byte} to the underlying output stream as149* a 1-byte value. If no exception is thrown, the counter150* {@code written} is incremented by {@code 1}.151*152* @param v a {@code byte} value to be written.153* @throws IOException if an I/O error occurs.154* @see java.io.FilterOutputStream#out155*/156public final void writeByte(int v) throws IOException {157out.write(v);158incCount(1);159}160161/**162* Writes a {@code short} to the underlying output stream as two163* bytes, high byte first. If no exception is thrown, the counter164* {@code written} is incremented by {@code 2}.165*166* @param v a {@code short} to be written.167* @throws IOException if an I/O error occurs.168* @see java.io.FilterOutputStream#out169*/170public final void writeShort(int v) throws IOException {171writeBuffer[0] = (byte)(v >>> 8);172writeBuffer[1] = (byte)(v >>> 0);173out.write(writeBuffer, 0, 2);174incCount(2);175}176177/**178* Writes a {@code char} to the underlying output stream as a179* 2-byte value, high byte first. If no exception is thrown, the180* counter {@code written} is incremented by {@code 2}.181*182* @param v a {@code char} value to be written.183* @throws IOException if an I/O error occurs.184* @see java.io.FilterOutputStream#out185*/186public final void writeChar(int v) throws IOException {187writeBuffer[0] = (byte)(v >>> 8);188writeBuffer[1] = (byte)(v >>> 0);189out.write(writeBuffer, 0, 2);190incCount(2);191}192193/**194* Writes an {@code int} to the underlying output stream as four195* bytes, high byte first. If no exception is thrown, the counter196* {@code written} is incremented by {@code 4}.197*198* @param v an {@code int} to be written.199* @throws IOException if an I/O error occurs.200* @see java.io.FilterOutputStream#out201*/202public final void writeInt(int v) throws IOException {203writeBuffer[0] = (byte)(v >>> 24);204writeBuffer[1] = (byte)(v >>> 16);205writeBuffer[2] = (byte)(v >>> 8);206writeBuffer[3] = (byte)(v >>> 0);207out.write(writeBuffer, 0, 4);208incCount(4);209}210211/**212* Writes a {@code long} to the underlying output stream as eight213* bytes, high byte first. In no exception is thrown, the counter214* {@code written} is incremented by {@code 8}.215*216* @param v a {@code long} to be written.217* @throws IOException if an I/O error occurs.218* @see java.io.FilterOutputStream#out219*/220public final void writeLong(long v) throws IOException {221writeBuffer[0] = (byte)(v >>> 56);222writeBuffer[1] = (byte)(v >>> 48);223writeBuffer[2] = (byte)(v >>> 40);224writeBuffer[3] = (byte)(v >>> 32);225writeBuffer[4] = (byte)(v >>> 24);226writeBuffer[5] = (byte)(v >>> 16);227writeBuffer[6] = (byte)(v >>> 8);228writeBuffer[7] = (byte)(v >>> 0);229out.write(writeBuffer, 0, 8);230incCount(8);231}232233/**234* Converts the float argument to an {@code int} using the235* {@code floatToIntBits} method in class {@code Float},236* and then writes that {@code int} value to the underlying237* output stream as a 4-byte quantity, high byte first. If no238* exception is thrown, the counter {@code written} is239* incremented by {@code 4}.240*241* @param v a {@code float} value to be written.242* @throws IOException if an I/O error occurs.243* @see java.io.FilterOutputStream#out244* @see java.lang.Float#floatToIntBits(float)245*/246public final void writeFloat(float v) throws IOException {247writeInt(Float.floatToIntBits(v));248}249250/**251* Converts the double argument to a {@code long} using the252* {@code doubleToLongBits} method in class {@code Double},253* and then writes that {@code long} value to the underlying254* output stream as an 8-byte quantity, high byte first. If no255* exception is thrown, the counter {@code written} is256* incremented by {@code 8}.257*258* @param v a {@code double} value to be written.259* @throws IOException if an I/O error occurs.260* @see java.io.FilterOutputStream#out261* @see java.lang.Double#doubleToLongBits(double)262*/263public final void writeDouble(double v) throws IOException {264writeLong(Double.doubleToLongBits(v));265}266267/**268* Writes out the string to the underlying output stream as a269* sequence of bytes. Each character in the string is written out, in270* sequence, by discarding its high eight bits. If no exception is271* thrown, the counter {@code written} is incremented by the272* length of {@code s}.273*274* @param s a string of bytes to be written.275* @throws IOException if an I/O error occurs.276* @see java.io.FilterOutputStream#out277*/278public final void writeBytes(String s) throws IOException {279int len = s.length();280for (int i = 0 ; i < len ; i++) {281out.write((byte)s.charAt(i));282}283incCount(len);284}285286/**287* Writes a string to the underlying output stream as a sequence of288* characters. Each character is written to the data output stream as289* if by the {@code writeChar} method. If no exception is290* thrown, the counter {@code written} is incremented by twice291* the length of {@code s}.292*293* @param s a {@code String} value to be written.294* @throws IOException if an I/O error occurs.295* @see java.io.DataOutputStream#writeChar(int)296* @see java.io.FilterOutputStream#out297*/298public final void writeChars(String s) throws IOException {299int len = s.length();300for (int i = 0 ; i < len ; i++) {301int v = s.charAt(i);302writeBuffer[0] = (byte)(v >>> 8);303writeBuffer[1] = (byte)(v >>> 0);304out.write(writeBuffer, 0, 2);305}306incCount(len * 2);307}308309/**310* Writes a string to the underlying output stream using311* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>312* encoding in a machine-independent manner.313* <p>314* First, two bytes are written to the output stream as if by the315* {@code writeShort} method giving the number of bytes to316* follow. This value is the number of bytes actually written out,317* not the length of the string. Following the length, each character318* of the string is output, in sequence, using the modified UTF-8 encoding319* for the character. If no exception is thrown, the counter320* {@code written} is incremented by the total number of321* bytes written to the output stream. This will be at least two322* plus the length of {@code str}, and at most two plus323* thrice the length of {@code str}.324*325* @param str a string to be written.326* @throws UTFDataFormatException if the modified UTF-8 encoding of327* {@code str} would exceed 65535 bytes in length328* @throws IOException if some other I/O error occurs.329* @see #writeChars(String)330*/331public final void writeUTF(String str) throws IOException {332writeUTF(str, this);333}334335/**336* Writes a string to the specified DataOutput using337* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>338* encoding in a machine-independent manner.339* <p>340* First, two bytes are written to out as if by the {@code writeShort}341* method giving the number of bytes to follow. This value is the number of342* bytes actually written out, not the length of the string. Following the343* length, each character of the string is output, in sequence, using the344* modified UTF-8 encoding for the character. If no exception is thrown, the345* counter {@code written} is incremented by the total number of346* bytes written to the output stream. This will be at least two347* plus the length of {@code str}, and at most two plus348* thrice the length of {@code str}.349*350* @param str a string to be written.351* @param out destination to write to352* @return The number of bytes written out.353* @throws UTFDataFormatException if the modified UTF-8 encoding of354* {@code str} would exceed 65535 bytes in length355* @throws IOException if some other I/O error occurs.356*/357static int writeUTF(String str, DataOutput out) throws IOException {358final int strlen = str.length();359int utflen = strlen; // optimized for ASCII360361for (int i = 0; i < strlen; i++) {362int c = str.charAt(i);363if (c >= 0x80 || c == 0)364utflen += (c >= 0x800) ? 2 : 1;365}366367if (utflen > 65535 || /* overflow */ utflen < strlen)368throw new UTFDataFormatException(tooLongMsg(str, utflen));369370final byte[] bytearr;371if (out instanceof DataOutputStream dos) {372if (dos.bytearr == null || (dos.bytearr.length < (utflen + 2)))373dos.bytearr = new byte[(utflen*2) + 2];374bytearr = dos.bytearr;375} else {376bytearr = new byte[utflen + 2];377}378379int count = 0;380bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);381bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);382383int i = 0;384for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII385int c = str.charAt(i);386if (c >= 0x80 || c == 0) break;387bytearr[count++] = (byte) c;388}389390for (; i < strlen; i++) {391int c = str.charAt(i);392if (c < 0x80 && c != 0) {393bytearr[count++] = (byte) c;394} else if (c >= 0x800) {395bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));396bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));397bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));398} else {399bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));400bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));401}402}403out.write(bytearr, 0, utflen + 2);404return utflen + 2;405}406407private static String tooLongMsg(String s, int bits32) {408int slen = s.length();409String head = s.substring(0, 8);410String tail = s.substring(slen - 8, slen);411// handle int overflow with max 3x expansion412long actualLength = (long)slen + Integer.toUnsignedLong(bits32 - slen);413return "encoded string (" + head + "..." + tail + ") too long: "414+ actualLength + " bytes";415}416417/**418* Returns the current value of the counter {@code written},419* the number of bytes written to this data output stream so far.420* If the counter overflows, it will be wrapped to Integer.MAX_VALUE.421*422* @return the value of the {@code written} field.423* @see java.io.DataOutputStream#written424*/425public final int size() {426return written;427}428}429430431