1. IO流概述
一切皆为字节
所有的文件数据(文件,图片,视频)在存储的时候都是以二进制数字的形式存储的,都是一个一个的字节,在传输的时候也是如此
1⃣️ 所以字节流可以传输任意文件数据
2⃣️ 无论使用什么样的流对象,底层传输的都是的二进制数据
字节流
字符流
基本概述
可以看到java中的io流可以分为字节流和字符流,顾名思义,字节流传递的是字节,字符流以字符的单位读写数据(⚠️底层传递的依旧是字节,只不过自己做了编码和解码转换为字符)
而按照操作分类,io流可以分为输入流和输出流,OutputStream 这个抽象类是表示字节输出流的所有类的超类,定义了一些共性的方法,InputStream抽象类是表示输入字节流的所有类的超类(Reader,Writer同理)
2. 字节流
详细使用方法查看在线api,这里只简单介绍
2.1 字节输入流
2.1.1 基本概述
输入流就是将数据匆硬盘读取到内存(java程序 --> JVM --> OS(操作系统) --> OS调用读数据的方法 --> 读文件)
字节输入流的顶层是InputStream
这一个抽象类,里面定义了基本的方法,最值得关注的当然是read
方法
/**
Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned.
This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
A subclass must provide an implementation of this method.
*/
// 读取字节流中的下一个字节并返回(int),如果没有可读,则返回-1
// 子类必须实现这个方法
public abstract int read() throws IOException;
我们使用他的子类(以FileInputStream为例)
FileInputStream
是InputStream
的直接子类
2.1.2 基本使用
构造方法
使用步骤
FileInputStream fis = new FileInputStream("D:\\a.txt");
//一次读一个字节 读取完毕返回-1
int len = 0;
while((len = fis.read())!= -1){
System.out.println((char)len);
}
fis.close();
一次读取多个字节
① 方法的参数byte[]的作用:缓存作用,通常定义为1024(1k)
② 方法的返回值int:读取的有效字节个数
FileInputStream fis = new FileInputStream("D:\\a.txt");
byte[] bytes = new byte[1024];//存储多少字节
int len = 0;
while((len = fis.read(bytes))!= -1){
System.out.println(new String(bytes,0,len));
}
System.out.println(len);
fis.close();
读取到的字节被存储在byte数组中,可以转成String再输出,因为1024个字节不一定都填满,所以根据有效位数来初始化String
2.1.3 看看源码
这里我们先只关注读取方法
/**
* Reads a byte of data from this input stream. This method blocks
* if no input is yet available.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* file is reached.
* @exception IOException if an I/O error occurs.
*/
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
/**
* Reads a subarray as a sequence of bytes.
* @param b the data to be written
* @param off the start offset in the data
* @param len the number of bytes that are written
* @exception IOException If an I/O error has occurred.
*/
private native int readBytes(byte b[], int off, int len) throws IOException;
/**
* Reads up to <code>b.length</code> bytes of data from this input
* stream into an array of bytes. This method blocks until some input
* is available.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the file has been reached.
* @exception IOException if an I/O error occurs.
*/
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. If <code>len</code> is not zero, the method
* blocks until some input is available; otherwise, no
* bytes are read and <code>0</code> is returned.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array <code>b</code>
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the file has been reached.
* @exception NullPointerException If <code>b</code> is <code>null</code>.
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
* <code>len</code> is negative, or <code>len</code> is greater than
* <code>b.length - off</code>
* @exception IOException if an I/O error occurs.
*/
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
实际上调用的都是native方法
2.2 字节输出流
2.2.1 基本概述
写入数据就是将数据从内存写入硬盘(java程序 --> JVM --> OS(操作系统) --> OS调用写数据的方法 --> 把数据写到文件)
OutputStream 这个抽象类是表示字节输出流的所有类的超类,定义了一些共性的方法,我们使用他的子类FileOutputStream
2.2.2 基本使用
构造方法
构造方法会创建一个FileOutputStream对象,根据构造方法中传递的文件/文件路径,创建一个空的文件,再把FileOutputStream对象指向文件
常用方法
文件输出流的使用步骤
try {
//创建FileOutputStream,构造方法传入目的地
FileOutputStream fos = new FileOutputStream("D:\\a.txt");
//调用write方法将数据写入文件
fos.write(97);
//释放资源
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
一次写多个字节
如果我想向文件中写入100,那么我得调用3此write方法,分别传入1,0,0的ASCII值
fos.write(49);
fos.write(48);
fos.write(48);
也可以传入字节数组
注意:
① 如果写的第一个字节是正数(且在0-127范围内),会去查询ASCII表
② 如果第一个写的字节是负数,那么第一个字节会和第二个字节组成一个中文查系统默认码表
byte[] bytes = {65,66,67,68};
fos.write(bytes);
或者可以把字符串转成字节数组,再写入
byte[] bytes = "你好".getBytes();
fos.write(bytes);
追加写
会在之前的文件后面继续写而不是覆盖之前的文件
append为true的时候就是追加写
换行写
fos.write("\r\n".getBytes());
回车符 \r 和换行符 \n :
- 回车符:回到一行的开头(return)
- 换行符:下一行(newline)
系统中的换行:
- Windows系统里,每行结尾是 回车+换行 ,即 \r\n ;
- Unix系统里,每行结尾只有 换行 ,即 \n ;
- Mac系统里,每行结尾是 回车 ,即 \r 。从 Mac OS X开始与Linux统一