一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论什么样的流对象,底层传输的始终为二进制数据。
字节输出流【OutputStream】&【FileOutPutStream】
java.io.OutputStream
,字节输出流。这个抽象类是表示字节输出流的所有类的超类。
定义了一些子类共性的成员方法:
- 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) 将指定的字节写入此输出流。
其中常用的子类:
- public class FileOutputStream extends OutputStream
FileOutputStream:文件字节输出流
作用:把内存中的数据写到硬盘文件中
构造方法:
- FileOutputStream(File file) 创建文件输出流以写入由指定的
File
对象表示的文件。 - FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
参数:写入数据的目的地
(File file):目的地是一个文件
(String name):目的地是一个文件的路径
构造方法的作用:
- 创建一个FileOutputStream对象
- 会根据构造方法中传递的文件/文件路径,创建一个空的文件
- 会把FileOutputStream对象指向创建好的文件
字节输出流写入数据到文件
写入数据的原理(内存->硬盘):
Java程序->JVM(Java虚拟机)->OS(操作系统)->OS调用写数据方法->把数据写到文件中
字节输出流的使用步骤:
- 创建一个FileOutputStream对象,构造方法中传递写入数据目的地
- 调用FileOutputStream中的write,把数据写到文件中
- 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)
代码示例:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01OutputStream {
public static void main(String[] args) throws IOException {
// 1. 创建一个FileOutputStream对象,构造方法中传递写入数据目的地
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 2. 调用FileOutputStream中的write,把数据写到文件中
fileOutputStream.write(111);
// 3. 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)
fileOutputStream.close();
}
}
字节输出流写多个字节的方法
- public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流
代码实例:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
// 1. 创建一个FileOutputStream对象,构造方法中传递写入数据目的地
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 2. 调用FileOutputStream中的write,把数据写到文件中
byte[] bytes = {66, 67, 68};
fileOutputStream.write(bytes);
// 3. 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)
fileOutputStream.close();
}
}
如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
如果写的第一个字节是负数,那么第一个字节会和第二个字节组成一个中文显示,查询系统默认码表(GBK)。那我们将数组中的第一个元素改为负数
byte[] bytes = {-66, 67, 68};
重新执行下方法,可以见先两个字母变成了一个汉字。注意:这不是乱码
- public void write(byte[], int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
该方法可以把一部分数据写入都文件中。比如说,我只想让txt文件中显示CD两个字母,那么我们可以把off
起始长度设为1,len
结束长度设为2
代码示例:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
// 1. 创建一个FileOutputStream对象,构造方法中传递写入数据目的地
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 2. 调用FileOutputStream中的write,把数据写到文件中
byte[] bytes = {66, 67, 68, 69, 70};
fileOutputStream.write(bytes, 1, 2);
// 3. 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)
fileOutputStream.close();
}
}
可以看见文件中只有CD两个字母
写入字符串的第二种方法,可以使用String类中的方法,把字符串转换为数组
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
// 1. 创建一个FileOutputStream对象,构造方法中传递写入数据目的地
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 2. 调用FileOutputStream中的write,把数据写到文件中
byte[] bytes = "你好".getBytes();
System.out.println(Arrays.toString(bytes));
fileOutputStream.write(bytes);
// 3. 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)
fileOutputStream.close();
}
}
可见文件中显示了你好两个字
字节输出流的续写与换行
在刚在的不断地执行方法和创建文件中,我其实并没有删掉原来的文件再执行方法,这就说明了重新执行一次方法会新建一个文件,如果本来就有这个文件就会把原来的文件覆盖掉。那么如何才能不让他替换,而是继续往后写,Java给我们提供了两个方法:
追加写/续写:使用两个参数的构造方法
- public FileOutputStream(File file, boolean append) throws FileNotFoundException:创建文件输出流以写入由指定的File对象表示的文件。如果第二个参数是true,则字节将被写入文件的末尾而不是开头。
file - 要打开的文件写入。
append - 如果是 true ,那么字节将被写入文件的末尾,而不是开头
- public FileOutputStream(String name, boolean append) throws FileNotFoundException:创建文件输出流以指定的名称写入文件。如果第二个参数是true,则字节将写入文件的末尾而不是开头。
name - 与系统相关的文件名
append - 如果是 true ,那么字节将被写入文件的末尾,而不是开头
代码实例:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt", true);
fileOutputStream.write("你好".getBytes());
fileOutputStream.close();
}
}
连续执行两次方法,可以看见文件中出现了两个你好。
如果想要换行,需要写入换行符号,也是String类型的字符串,但是系统不一样字符串也不一样
- windows:\n\r
- linux/unix:/n
- mac:/r
代码示例:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt", true);
for (int i = 0; i < 10; i++) {
fileOutputStream.write("你好".getBytes());
fileOutputStream.write("\r\n".getBytes());
}
fileOutputStream.close();
}
}
接着刚才的两个你好继续
字节输入流【InputStrem】&【FileInputStream】
java.io.InputStream
:这个抽象类是表示输入字节流的所有类的超类。 可以读取字节信息到内存中。它定义了字节输入流的基本共性方法。
-
public void close() throws IOException
:关闭此输入流并释放与流相关联的任何系统资源。 -
public abstract int read() throws IOException
:从输入流读取数据的下一个字节。 -
public int read(byte[] b) throws IOException
:从输入流读取一些字节数,并将它们存储到缓冲区。
小贴士:当完成流的操作时,必须调用close()方法,释放系统资源。
java.io.FileInputStream
:从文件系统中的文件获取输入字节。
构造方法:
- FileInputStream(File file):通过打开与实际文件的连接创建一个
FileInputStream
,该文件由文件系统中的File
对象file
命名。 - FileInputStream (String name):通过打开与实际文件的连接来创建一个
FileInputStream
,该文件由文件系统中的路径名name
命名。
读取数据的原理(硬盘->内存):
Java程序->JVM->OS->OS读取数据的方法->读取数据
字节输入流的使用步骤:
- 创建FileInputStream对象,构造方法中绑定要读取的数据源
- 使用FileInputStream对象中的read()方法读取文件
- 释放资源
代码示例:
import java.io.FileInputStream;
import java.io.IOException;
public class Demo01FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("D:\\a.txt");//文件中只有123三个数字
int read = fileInputStream.read();
System.out.println(read);
int read1 = fileInputStream.read();
System.out.println(read1);
int read2 = fileInputStream.read();
System.out.println(read2);
int read3 = fileInputStream.read();
System.out.println(read3);
fileInputStream.close();
}
}
控制台打印:
49
50
51
-1
可以看到,控制台依次打印出了三个数字在ASCII表上对应的序号。因为文件中只有三个数字,所以到了第四次读取数据的时候,结果就会变成-1。
以上读取文件是一个重复的过程,所以可以使用循环优化,假如说文件中有100个数字,或者不知道有多少数据,这个时候就要用while循环来进行读取,当结果为-1的时候,说明读取完了,结束循环。先在文件中随便写入一批数据
代码示例:
public class Demo01FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("D:\\a.txt");
// 记录读取到的字节
int read = 0;
while ((read = fileInputStream.read()) != -1) {
System.out.print((char)read);
}
fileInputStream.close();
}
}
控制台打印:
567812345567134678367878178278234782345789234578934783245
当读取返回的结果返回-1的时候,非常完美的打印出了文件的数字。
字节输入流一次输入多个字节
上面的字节输入,哪怕用的while循环,read()方法也是一个字节一个字节的输入,效率特别低。
read()方法有个有参构造
-
int read(byte[] b)
:从该输入流读取最多b.length
个字节的数据为字节数组。
该方法中的byte[]有什么作用?返回值int是什么?带着问题一块看下面的代码: