Java IO流之字节流:OutputStream、FileOutputStream、InputStream、FileInputStream
文章目录
JAVA IO流
Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做写出数据。
根据数据的流向分为:输入流和输出流
-
输入流:把数据从
其他设备
上读取到内存
中的流。 -
输出流:把数据从
内存
中写出到其他设备
上的流。
格局数据的类型分为:字节流和字符流。
输出流的原理(内存 --> 硬盘):
java程序 --> JVM --> OS(操作系统) --> OS调用写数据的方法 --> 把数据写到硬盘的文件中
输入流的原理(硬盘 --> 内存):
java程序 --> JVM --> OS(操作系统) --> OS调用读数据的方法 --> 把数据从硬盘文件中读取到内存中
一、字节流
一切都为字节,任何文件都是以二进制数字形式保存。在传输过程中都是以二进制数据形式传输。
字节输出流
1、OutputStream 抽象类 JDK 1.0
java.io.OutputStream
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。它定义了字节输出流的基本共性功能方法。
已知直接子类:
ByteArrayOutputStream
,FileOutputStream
, FilterOutputStream
, ObjectOutputStream
,OutputStream
, PipedOutputStream
常用方法
-
public void close()
关闭此输出流并释放与此流相关的任何系统资源 -
public void flush()
刷新此输出流并强制任何缓冲的输出字节被写出 -
public void write(byte[] b)
将b.length字节从指定的字节数组写入此输出流 -
public void write(byte[] b, int off, int len)
从指定的字节数组写入 len节字,从偏移量off开始输出到此输出流 -
public abstract void write(int b)
将指定的字节输出流,只能传入一个字节大小的十进制整数。
注意:close方法必须在完成流之后调用,以此释放相关的系统资源。
2、FileOutputStream 类
该类是继承OutputStream
抽象类的子类
java.io.FileOutputStream
类是文件输出流,将内存中的数据写到硬盘中的文件中。
异常:
IOException
构造方法( 共5个 )
-
public FileOutputStream(File file) throws FileNotFoundException
创建文件输出流以写入由指定的File
对象表示的文件。(如原来已经有该文件,会被覆盖重写新的数据) -
public FileOutputStream(String name)throws FileNotFoundException
创建文件输出流以指定的名称写入文件。(name为文件的路径)。(如原来已经有该文件,会被覆盖重写新的数据) -
public FileOutputStream(File file,boolean append) throws FileNotFoundException
JDK1.4开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建) -
public FileOutputStream(String name,boolean append) throws FileNotFoundException
JDK1.1开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)
public class FileOutputStreamConstructor{
public static void main(String[] args) throws IOException{
// 以File对象创建输出流
File file = new File("a.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 以文件名称创建输出流 当前文件的output文件夹下的a.txt文件
FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
fileOutputStream.close();
}
}
写出字节流
- 写出字节:
write(int b)
方法,每次可以写出一个字节数据IOException
public class DemonFileOutputStream{
public static void main(String[] args) throws IOException{
FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
fileOutputStream.write(97); // 像文件中写入的是小写字母a
fileOutputStream.close();
}
}
字节流写入文件的原理: 向a.txt文件写入了97,在程序运行的时候,因为是字节流,会将97转为二进制整数1100001写入到a.txt文件中,当打开a.txt文件时,这些文本编辑器,会自动将写入的二进制整数1100001通过编码解析。默认解析规则为:0-127的十进制整数会比对ASCII表,其他值会以系统默认码表查询。这里二进制转换为十进制数为97,则97在ASII表中对应的是小写字母a。那么打开a.txt显示的是 a 。
ASCII表
48为0 以此为0~9 9为57
65为A 以此为A~Z(26个字母)Z为90
97为a 以此为a~z(26个字母)z为122
当字节十进制在0-127时,会解析ASCII表。当第一个为负数,第二个为整数或负数,则会组合在一起,形成2个字节解析为中文。需要注意的是UTF-8编码一个中文字符占3个字节,GBK编码一个中文占2个字节。
public class DemonFileOutputStream{
public static void main(String[] args) throws IOException{
FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
// write(byte[] b)
byte[] a = {65,67,68,69};
fileOutputStream.write(a); // 查看a.txt文件写入的是 ACDE
byte[] b = {-65,-66,-67,68};
fileOutputStream.write(b); // 查看a.txt文件写入的是 烤紻
// write(byte[] b, int off, int len)
fileOutputStream.write(a, 1, 2); // 查看a.txt文件写入的是 CD
// 写的是字节数组a的索引为1开始的2个长度的数据 67,68
// 把字符串转换成字节数组
String str = "你好";
byte[] c = str.getBytes();
System.out.println(Arrays.toString(byte)); // [-28, -67, -96, -27, -91, -67]
// 需要注意的是UTF-8编码一个中文字符占3个字节,GBK编码一个中文占2个字节
fileOutputStream.write(c); // 就会把字符串以字节流的方式写入到a.txt文件中
}
}
数据追加续写与换行
构造方法:
-
public FileOutputStream(File file,boolean append) throws FileNotFoundException
JDK1.4开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建) -
public FileOutputStream(String name,boolean append) throws FileNotFoundException
JDK1.1开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)
写入换行字符串:
- win:\r\n
- mac:/r
- Linux:/n
public class FileOutputStreamTest {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("b.txt",true);
for (int i = 0; i < 10; i++) {
fileOutputStream.write("你好".getBytes());
fileOutputStream.write("\r\n".getBytes()); // win 下的换行符
}
fileOutputStream.close();
}
}
字节输入流
1、InputStream 抽象类 JDK 1.0
java.io.InputStream
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。它定义了字节输出流的基本共性功能方法。
已知直接子类:
AudioInputStream
, ByteArrayInputStream
,FileInputStream
, FilterInputStream
,InputStream
, ObjectInputStream
, PipedInputStream
, SequenceInputStream
,StringBufferInputStream
常用方法
-
public void close()
关闭此输入流并释放与此流相关的系统资源 -
public abstract int read()
从输入流中读取数据的下一个字节。 -
public int read(byte[] b)
从该输入流读取最多byte.length
个字节的数据到字节数组。 返回读取文件中有效字节个数,并且会将有效字节存放在byte数组中。如果读到文末,则返回-1 -
public int read(byte[] b, int off, int len)
从该输入流读取从off索引开始到最多len
字节的数据到字节数组。如果读到文末,则返回-1
注意:close方法必须在完成流之后调用,以此释放相关的系统资源。
2、FileInputStream 类
该类是继承InputStream
抽象类的子类
java.io.FileInputStream
类是文件输入流,从文件中读取数据。
异常:
FileNotFoundException
构造方法
-
public FileInputStream(File file) throws FileNotFoundException
通过打开实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名。 -
public FileInputStream(String name) throws FileNotFoundException
通过打开实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名。
public int read(byte[] b)
中byte[]数组的作用,以及返回值是什么?起到缓冲作用,返回值为读取字节数的有效个数,当读到文末时,没有有效字节数了就会返回-1。一般数组的长度定义为1024(1kb)
byte[] bytes = new byte[1024];
读取字节流
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("a.txt");
// read() 只读取一个字节的数据并返回该数据,如果读到文末,则返回-1
/*int read = 0;
while ( (read = inputStream.read()) != -1){
// read = inputStream.read(); // 读取了一个字节,指针会自动向后移一位
System.out.print( read+":" );
System.out.print((char) read +" ");
}*/
int read1 = 0;
byte[] bytes = new byte[1024];
while ((read1 = inputStream.read(bytes)) != -1){
// System.out.println(read1); // 输出读取有效字节个数
// System.out.println(Arrays.toString(bytes)); // 输出由二进制数据转换成十进制的数
// System.out.println(new String(bytes)); // 使用String的该构造方法,会将1024个字节全部输出,空格也会输出
System.out.println(new String(bytes,0, read1)); // 该方法就是从字节数组索引为0开始到有效个数的长度截至,转为字符
}
inputStream.close();
}
}
练习:文件复制
可复制任何文件
public class CopyFile {
public static void main(String[] args) throws IOException {
// 1)复制文本
/*FileInputStream fileInputStream = new FileInputStream("a.txt");
byte[] bytes = new byte[1024];
int read = 0;
while((read = fileInputStream.read(bytes))! = -1){
FileOutputStream fileOutputStream = new FileOutputStream("b.txt");
fileOutputStream.write(bytes,0, read);
}
fileOutputStream.close();
fileInputStream.close();*/
// 2)复制图片
/*FileInputStream fileInputStream = new FileInputStream("D:/IMG_20191127_181018.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("E:/IMG.jpg");
byte[] bytes = new byte[1024];
int read = 0;
while ( (read = fileInputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0, read);
}
fileOutputStream.close();
fileInputStream.close();*/
// 3)复制音频
FileInputStream fileInputStream = new FileInputStream("D:\\媒体\\音乐\\勇气.mp3");
FileOutputStream fileOutputStream = new FileOutputStream("E:/勇气.mp3");
byte[] bytes = new byte[1024];
int read = 0;
while ( (read = fileInputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0, read);
}
fileOutputStream.close();
fileInputStream.close();
}
}
注意:
- 先关闭写文件的数据流,再关闭读取文件的数据流。(因为写数据,已经写完了,读取的数据肯定就已经读完了)
- 当复制文件或读取写入的文件数据字节数小的话,建议使用单个读取字节的方法;当复制文件或读取写入文件的数据字节数大的话,建议使用new byte[1024]的整数倍。少使用数组,浪费空间,因为数组中每一位都会占去一定的空间。
推荐阅读
-
Java IO流之字节流:OutputStream、FileOutputStream、InputStream、FileInputStream
-
Java IO流 InputStream 、OutputStream、FileOutputStream、FileInputStream
-
Java 字节流InputStream、OutputStream、FileInputStream、FileOutputStream
-
Java流操作,InputStream、OutputStream及子类FileInputStream、FileOutputStream;BufferedInpu
-
IO流(一):概念,字节流,InputStream,OutputStream,FileInputStream,FileOutputStream