简介
👨💻个人主页:@云边牧风
👨🎓小编介绍:欢迎来到云边牧风破烂的小星球🌝
📋专栏:Java基础知识
🔑本章内容:输入输出流
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~
这一节的主要内容有:
写二进制文件
读二进制文件
抽象类OutputStream
派生类BufferedOutputStream
一、二进制文件的读写
1.1二进制文件
原则上讲, 所有文件都是由字节组成 的
如果文件中的内容应被解释为字符,则文件被称为文本文件;否则为二进制文件
注意 : 一些文字处理软件(如 Word 等)产生的文件 中,数据要被解释为字体、格式、图形和其他非字符信息,因此,这样的文件 是二进制文件 ,不能用 Reader 流正确读取
1.2写二进制文件
常用来写文件的输出流类:
FileOutputStream
流程图:
先用File类打开本地文件,实例化输入输出流,然后调用流的读写方法读取或写入数据,最后关闭流。
FileOutputStream(File file, boolean append);
FileOutputStream(String name, boolean append);
注意:append参数为true时,数据从文件尾部写入;append参数为false时,数据覆盖原文件。
使用FileOutputStream流可以写入字节数据到目标文件,FileOutputStream提供了单字节写入和byte数组写入两种方式。建议使用byte数组写入,将待写入的数据存储到一个byte数组中,然后再写入文件。当写入的文件已经存在时,需要指明写入方式是覆盖还是追加。
DataOutputStream
package java.io;
public class DataOutputStream extends FilterOutputStream implements DataOutput {
// “数据输出流”的字节数
protected int written;
// “数据输出流”对应的字节数组
private byte[] bytearr = null;
// 构造函数
public DataOutputStream(OutputStream out) {
super(out);
}
// 增加“输出值”
private void incCount(int value) {
int temp = written + value;
if (temp < 0) {
temp = Integer.MAX_VALUE;
}
written = temp;
}
// 将int类型的值写入到“数据输出流”中
public synchronized void write(int b) throws IOException {
out.write(b);
incCount(1);
}
// 将字节数组b从off开始的len个字节,都写入到“数据输出流”中
public synchronized void write(byte b[], int off, int len)
throws IOException
{
out.write(b, off, len);
incCount(len);
}
// 清空缓冲,即将缓冲中的数据都写入到输出流中
public void flush() throws IOException {
out.flush();
}
// 将boolean类型的值写入到“数据输出流”中
public final void writeBoolean(boolean v) throws IOException {
out.write(v ? 1 : 0);
incCount(1);
}
// 将byte类型的值写入到“数据输出流”中
public final void writeByte(int v) throws IOException {
out.write(v);
incCount(1);
}
// 将short类型的值写入到“数据输出流”中
// 注意:short占2个字节
public final void writeShort(int v) throws IOException {
// 写入 short高8位 对应的字节
out.write((v >>> 8) & 0xFF);
// 写入 short低8位 对应的字节
out.write((v >>> 0) & 0xFF);
incCount(2);
}
// 将char类型的值写入到“数据输出流”中
// 注意:char占2个字节
public final void writeChar(int v) throws IOException {
// 写入 char高8位 对应的字节
out.write((v >>> 8) & 0xFF);
// 写入 char低8位 对应的字节
out.write((v >>> 0) & 0xFF);
incCount(2);
}
// 将int类型的值写入到“数据输出流”中
// 注意:int占4个字节
public final void writeInt(int v) throws IOException {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(4);
}
private byte writeBuffer[] = new byte[8];
// 将long类型的值写入到“数据输出流”中
// 注意:long占8个字节
public final void writeLong(long v) throws IOException {
writeBuffer[0] = (byte)(v >>> 56);
writeBuffer[1] = (byte)(v >>> 48);
writeBuffer[2] = (byte)(v >>> 40);
writeBuffer[3] = (byte)(v >>> 32);
writeBuffer[4] = (byte)(v >>> 24);
writeBuffer[5] = (byte)(v >>> 16);
writeBuffer[6] = (byte)(v >>> 8);
writeBuffer[7] = (byte)(v >>> 0);
out.write(writeBuffer, 0, 8);
incCount(8);
}
// 将float类型的值写入到“数据输出流”中
public final void writeFloat(float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
// 将double类型的值写入到“数据输出流”中
public final void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
// 将String类型的值写入到“数据输出流”中
// 实际写入时,是将String对应的每个字符转换成byte数据后写入输出流中。
public final void writeBytes(String s) throws IOException {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
out.write((byte)s.charAt(i));
}
incCount(len);
}
// 将String类型的值写入到“数据输出流”中
// 实际写入时,是将String对应的每个字符转换成char数据后写入输出流中。
public final void writeChars(String s) throws IOException {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
int v = s.charAt(i);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
incCount(len * 2);
}
// 将UTF-8类型的值写入到“数据输出流”中
public final void writeUTF(String str) throws IOException {
writeUTF(str, this);
}
// 将String数据以UTF-8类型的形式写入到“输出流out”中
static int writeUTF(String str, DataOutput out) throws IOException {
//获取String的长度
int strlen = str.length();
int utflen = 0;
int c, count = 0;
// 由于UTF-8是1~4个字节不等;
// 这里,根据UTF-8首字节的范围,判断UTF-8是几个字节的。
for (int i = 0; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
if (utflen > 65535)
throw new UTFDataFormatException(
"encoded string too long: " + utflen + " bytes");
// 新建“字节数组bytearr”
byte[] bytearr = null;
if (out instanceof DataOutputStream) {
DataOutputStream dos = (DataOutputStream)out;
if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
dos.bytearr = new byte[(utflen*2) + 2];
bytearr = dos.bytearr;
} else {
bytearr = new byte[utflen+2];
}
// “字节数组”的前2个字节保存的是“UTF-8数据的长度”
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
// 对UTF-8中的单字节数据进行预处理
int i=0;
for (i=0; i<strlen; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) break;
bytearr[count++] = (byte) c;
}
// 对预处理后的数据,接着进行处理
for (;i < strlen; i++){
c = str.charAt(i);
// UTF-8数据是1个字节的情况
if ((c >= 0x0001) && (c <= 0x007F)) {
bytearr[count++] = (byte) c;
} else if (c > 0x07FF) {
// UTF-8数据是3个字节的情况
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
// UTF-8数据是2个字节的情况
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
// 将字节数组写入到“数据输出流”中
out.write(bytearr, 0, utflen+2);
return utflen + 2;
}
public final int size() {
return written;
}
}
BufferedOutputStream
package java.io;
public class BufferedOutputStream extends FilterOutputStream {
// 保存“缓冲输出流”数据的字节数组
protected byte buf[];
// 缓冲中数据的大小
protected int count;
// 构造函数:新建字节数组大小为8192的“缓冲输出流”
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
// 构造函数:新建字节数组大小为size的“缓冲输出流”
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
// 将缓冲数据都写入到输出流中
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
// 将“数据b(转换成字节类型)”写入到输出流中
public synchronized void write(int b) throws IOException {
// 若缓冲已满,则先将缓冲数据写入到输出流中。
if (count >= buf.length) {
flushBuffer();
}
// 将“数据b”写入到缓冲中
buf[count++] = (byte)b;
}
public synchronized void write(byte b[], int off, int len) throws IOException {
// 若“写入长度”大于“缓冲区大小”,则先将缓冲中的数据写入到输出流,然后直接将数组b写入到输出流中
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
return;
}
// 若“剩余的缓冲空间 不足以 存储即将写入的数据”,则先将缓冲中的数据写入到输出流中
if (len > buf.length - count) {
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
// 将“缓冲数据”写入到输出流中
public synchronized void flush() throws IOException {
flushBuffer();
out.flush();
}
}
常用写字节的方法:
void write( int n); //写单个字节
void write( byte b[]);
void write( byte b[], int offset, int len);
1.3读二进制文件
常用来读文件的输入流类:
FileInputStream
DataInputSteam
BufferedInputStream
常用读二进制文件的方法:
int read(); //返回读取的单个字节的编码值
int read( byte b[]); //读取b.length个字节到字节数组b中
int read( byte b[], int offset, int len);
二、抽象类OutputStream
派生类FileOutputStream
派生类BufferedOutputStream
三、读/写二进制文件实例
实例1:复制功能
import java.io.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
String fileName1 = "D:\\1234567890\\grade.txt";//定义文件的路径
String fileName2 = "D:\\1234567890\\grade_2.txt";//定义文件的路径
BufferedInputStream in = new BufferedInputStream(
new FileInputStream(fileName1));
BufferedOutputStream out = new BufferedOutputStream(
new FileOutputStream( fileName2 ) ) ;
int c;
byte buffer[]=new byte[1024];
while((c=in.read(buffer))!=-1){
for(int i=0;i<c;i++)
out.write(buffer[i]);
}
in.close();
out.close();
}
}
实例2:剪切mp3
int start = 2375680;//320kbps(比特率)*58s*1024/8=2375680 比特率可以查看音频属性获知
int end = 4915200;//320kbps*120s*1024/8=4915200
四、派生类DataOutputStream
4.1、写二进制文件
如:将三个int型数字255/0/-1写入数据文件data1.dat
import java.io.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
//String fileName1 = "D:\\1234567890\\grade.txt";//定义文件的路径
//String fileName2 = "D:\\1234567890\\grade_2.txt";//定义文件的路径
String fileName3 = "D:\\1234567890\\data1.dat" ;
int value0 = 255, value1 = 0, value2 = -1;
DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName3));
out.writeInt( value0 );
out.writeInt( value1 );
out.writeInt( value2 );
out.close();
}
}
运行结果
运行程序后,在对应文件夹内 生成数据文件 data1.dat用写字板打开没有任何显示用 ultraEdit 打开查看其二进制信息 , 内容为 00 00 00 FF 00 00 00 00 FF FF FF FF , 每个 int 数字都是32个 bit 的
说明
五、派生类BufferedOutputStream
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream( fileName ) ) );
如:向文件中写入各种数据类型的数,并统计写入的字节数
import java.io.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
//String fileName1 = "D:\\1234567890\\grade.txt";//定义文件的路径
String fileName = "D:\\1234567890\\mixedTypes.dat" ;
DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(fileName)));
dataOut.writeInt( 0 );
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.writeDouble( 31.2 );
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.writeBytes("JAVA");
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.close();
}
}
输出为:
4 bytes have been written.
12 bytes have been written.
16 bytes have been written.
结束语:
以上是Jav第六章第4节的全部内容 希望大家喜欢
下一节讲第六章第5节:文件读写—— 随机存取文件读写
喜欢的可以点赞+关注哈 ❤