IO 概述
什么是 IO
Java中IO操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输岀也叫做作写出数据。
IO的分类
根据数据的流向分为:输入流和输出流。
输入流:把数据从其他设备上读取到内存中的流。
输出流:把数据从内存中写出到其他设备上的流。
格局数据的类型分为:字节流和字符流。
顶级父类们
字节流
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个ー个的字节,在传输时也是一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
字节输出流——OutputStream
java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
java.io.OutputStream
public abstract void write(int b) throws IOException;
// 将指定的字节输出流。
public void write(byte b[]) throws IOException{...};
// 将b.length字节从指定的字节数组写入此输出流。
public void write(byte b[], int off, int len) throws IOException{...};
// 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
public void flush() throws IOException{};
// 刷新此输出流并强制任何缓冲的输出字节被写出。
public void close() throws IOException {};
// 关闭此输出流并释放与此流相关联的任何系统资源。
FileOutputStream类
- OutputStream抽象类,有很多的子类,其中FileOutputStream类是它其中一个简单的子类。
- java.io.FileOutputStream是文件输出流,用于将数据写出到文件。
写出字节数据
写出字节:write(int b)方法,每次可以写出一个字节数据
字节输出流的使用步骤:
- 创建一个 FileOutputStream对象,构造方法中传递写入数据的目的地。
- 调用FileOutputStream对象中的方法write,把数据写入到文件中。
- 释放资源(流使用会占用一定的内存,使用完毕要把内存清空提供程序的效率)。
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoFosWrite {
public static void main(String[] args) throws IOException {
// 使用文件名创建字节流对象
FileOutputStream fos = new FileOutputStream("FOS.txt");
// 写出数据
// 写出第一个字节
fos.write(97);
// 写出第二个字节
fos.write(98);
// 写出第三个字节
fos.write(99);
// 关闭资源
fos.close();
}
}
运行结果:生成了一个"FOS.txt"文件
FOS.txt文件大小是3个字节,内容是abc
写入数据的原理(内存-->硬盘):
Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用写数据的方法 --> 把数据写到文件中
写数据的时候,会把要写入的数据转换为二进制数。在打开文件的时候,都会查询编码表(例如:ASCII表),把字节转换为字符表示。
write(byte b[])方法
作用:将b.length字节从指定的字节数组写入此输出流。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS1.txt");
byte[] bytes = {97, 98, 99};
// 将3个字节从bytes字节数组写入fos输出流。
fos.write(bytes);
fos.close();
}
}
运行结果:生成了一个"FOS1.txt"文件
write(byte b[], int off, int len)方法
作用:从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS2.txt");
byte[] bytes = {97, 98, 99, 100, 101, 102};
// 将3个字节从bytes字节数组写入fos输出流。
fos.write(bytes, 1, 4);
fos.close();
}
}
运行结果:生成了一个"FOS2.txt"文件
write方法简单练习
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class Demo03Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS3.txt");
// 调用String类中的getBytes()方法,把一串字符转换为byte数组
byte[] bytes = "大佬,你好!".getBytes();
// 将该数组转换为集合输出
System.out.println(Arrays.toString(bytes));
// 将多个字节从bytes字节数组写入fos输出流。
fos.write(bytes);
fos.close();
}
}
控制台输出
[-27, -92, -89, -28, -67, -84, -17, -68, -116, -28, -67, -96, -27, -91, -67, -17, -68, -127]
运行结果:还生成了一个"FOS3.txt"文件
字节输出流的续写和换行
public FileOutputStream(File file, boolean append)
// 创建文件输出流以写入由指定的File对象表示的文件。
public FileOutputStream(String name, boolean append)
// 创建文件输出流以指定的名称写入文件。
这两个构造方法,参数中都需要传入一个 boolean类型的值,true表示追加数据,false表示清空原有数据这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01OutputAppend {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt", true);
// 往"a.txt"文件中写入"大佬,"内容
byte[] bytes1 = "大佬,".getBytes();
fos.write(bytes1);
// 往"a.txt"文件中追加写入"你好!"内容
byte[] bytes2 = "你好!".getBytes();
fos.write(bytes2);
fos.close();
}
}
运行结果:生成了一个"a.txt"文件
如果需要换行:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02OutputAppend {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("b.txt", true);
// 往"a.txt"文件中写入"大佬,"内容
byte[] bytes1 = "大佬,".getBytes();
fos.write(bytes1);
// 换行 "\\n" 或者 "\\r"
byte[] bytes = "\\n".getBytes();
fos.write(bytes);
// 往"a.txt"文件中追加写入"你好!"内容
byte[] bytes2 = "你好!".getBytes();
fos.write(bytes2);
fos.close();
}
}
运行结果:生成了一个"b.txt"文件
字节输入流 —— InputStream
java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close()
// 关闭此输入流并释放与此流相关联的任何系统资源。
public abstract int read()
// 从输入流读取数据的下一个字节。
public int read(byte[] b)
// 从输入流中读取一些字节数,并将它们存储到字节数组b中。
FileInputStream类
java.io.FileInputStream类是文件输入流,从文件中读取字节。
构造方法
public FileInputStream(String name) throws FileNotFoundException
// 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名name命名。
public FileInputStream(File file) throws FileNotFoundException
// 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的File对象file命名。
当我们创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException异常。
读取数据的原理(硬盘-->内存):
Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用读取数据的方法 --> 读取文件
字节输入流的使用步骤
- 创建FileInputStream对象,构造方法中绑定要读取的数据源。
- 使用FileInputStream对象中的方法read,读取文件。
- 释放资源。
下面这个例子中使用的read()方法是一个字节一个字节的读取的。
import java.io.FileInputStream;
import java.io.IOException;
public class DemoInputRead {
public static void main(String[] args) throws IOException {
// 创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/A");
// 使用FileInputStream对象中的方法read,读取文件
// char=65 对应 A
int lien0 = fis.read();
char c0 = (char) lien0;
System.out.println(lien0 + "对应" + c0);
// char=10 对应 /n
int lien1 = fis.read();
char c1 = (char) lien1;
System.out.println(lien1 + "对应" + c1);
// char=66 对应 B
int lien2 = fis.read();
char c2 = (char) lien2;
System.out.println(lien2 + "对应" + c2);
// char=10 对应 /n
int lien3 = fis.read();
char c3 = (char) lien3;
System.out.println(lien3 + "对应" + c3);
// 释放资源
fis.close();
}
}
文件A的内容:
如果已经将文件A的内容读取完了,那么再读取的话,会返回-1。
FileInputStream类中的部分方法
int available()
// 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
void close()
// 关闭此输入流并释放与该流关联的所有系统资源。
int read()
// 从输入流中读取数据的下一个字节。
int read(byte b[])
// 从输入流中读取一定数量的字节,并将其存储在緩神区数组b中。
int read(byte b[], int off, int len)
// 将输入流中最多len个数据字节读入byte数组。
long skip(long n)
// 跳过和丢弃此输入流中数据的n个字节。
read(byte b[])方法
import java.io.FileInputStream;
import java.io.IOException;
public class Demo02InputRead {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/B");
// 创建一个byte数组,存储读取的字节
byte[] bytes = new byte[2];
// 开始读取,每次读取两个
// 第一次读取: bytes = {97, 98},len1 = 2
int len1 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\\t\\t"
+ "len = " + len1
);
// 开始读取,每次读取两个
// 第二次读取: bytes = {99, 100},len2 = 2
int len2 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\\t\\t"
+ "len = " + len2
);
// 开始读取,每次读取两个
// 第三次读取: bytes = {101, 100},len3 = 2
int len3 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\\t\\t"
+ "len = " + len3
);
// 开始读取,每次读取两个
// 第四次读取: bytes = {101, 100},len4 = 2
int len4 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\\t\\t"
+ "len = " + len4
);
}
}
文件B内容:
控制台输出
bytes = ab len = 2
bytes = cd len = 2
bytes = ed len = 1
bytes = ed len = -1
解析:
第一次读取:读取第1个字节和第2个字节,将初始数组的{0, 0} 替换为 {a, b}
第二次读取:读取第3个字节和第4个字节,将第一次读取后的数组的{a, b} 替换为 {c, d}
第三次读取:读取第5个字节,发现没有可以读取的了,于是将第二次读取的数组的 {c, d}里面的c替换为e,而d没得替换,即{e, d}
第四次读取:因为第三次读取的时候,已经读取完了,没有可以读取的了,依旧还是原来的数组{e, d}
第一次读取两个字节(len1=2),第二次读取两个字节(len2=2),第三次读取1个字节(len3=2),第四次没得读取(len4=-1)。
读取完后,再读取,返回值是-1。
字节流练习:图片复制
文件复制的步骤:
- 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
- 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
- 使用字节输入流对象中的方法read读取文件。
- 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
- 释放资源。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoCopyFile {
public static void main(String[] args) throws IOException {
// 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
// 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
// 使用字节输入流对象中的方法read读取文件。
int len = 0;
while ((len = fis.read()) != -1) {
// 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
fos.write(len);
}
// 释放资源。先关闭写的,再关闭读的。
fis.close();
fos.close();
}
}
运行结果:
程序优化:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02CopyFile {
public static void main(String[] args) throws IOException {
// 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
// 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
// 使用字节输入流对象中的方法read读取文件。
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
// 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
fos.write(bytes, 0, len);
}
// 释放资源。
fis.close();
fos.close();
}
}