本文总结整理自 Java零基础教学最新入门视频(1-8 File类与IO流)
参考《Java开发实战经典 第2版》
IO流
I:输入,把硬盘中数据读到内存中使用。
O:输出,把内存中数据写入硬盘中保存。
流:数据。数据又分为字节和字符。
因此IO流分为字符流和字节流。
Java中IO操作,以文件的操作为例,主要的操作步骤如下:
( 1 ) 用File类打开一个文件。
( 2 ) 通过字节流或字符流的子类指定输出的位置。
( 3 ) 进行读/写操作。
( 4 ) 关闭输入/输出流。
字节流
一切的数据归根结底都是字节,无论是文本、图片还是音视频。无论什么样的流对象,底层传输始终是二进制数据。
字节流主要是操 byte类型数据,以byte数组为准,主要操作类就是OutputStream类和InputStream 类 。
- 字节输出流OutputStream
OutputStream是整个IO包中字节输出流最大的父类,它实现了Closeable和Flushable接口。
主要的方法有:
void write(byte b[]) throws IOException;
void write(byte b[], int off, int len) throws IOException;
void flush() throws IOException;
void close() throws IOException;
abstract void write(int b) throws IOException;
jdk1.7后Closeable接口实现AutoCloseable接口,该接口中顶一个一个close方法,可以自动释放资源。避免用户没有手动调用close释放资源导致资源不能再使用。当然还是建议开发者显示地手动调用close。
抽象类不可实例化,必须要通过子类实例化。
当操作的数据对象是文件时,可以使用FileOutputStream类。
写入数据原理:
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\Willow.txt");
if (!file.exists()){
file.createNewFile();
}
//写入文件
OutputStream out1 = new FileOutputStream(file);
String string = "Hello,Willow!";
out1.write(string.getBytes());
out1.close();
//构造第二个参数代表是否追加
OutputStream out2 = new FileOutputStream(file,true);
out2.write("good".getBytes());
out2.close();
}
换行写时,需要输入换行符。
Windows下:"\r\n"
Linux下:"/n"
Mac下:"/r"
- 字节输入流InputStream
InputStream是整个IO包中字节输入流最大的父类,它实现了Closeable接口。
主要的方法有:
int read(byte b[], int off, int len) throws IOException;
int read(byte b[]) throws IOException;
int available() throws IOException;
void close() throws IOException;
abstract int read() throws IOException;
仍然需要子类实例化。当操作的数据对象是文件时,可以使用FileInputStream类。
数据读取原理和写入原理类似,只是os调用的是读还写方法。
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\Willow.txt");
if (!file.exists()){
file.createNewFile();
}
//读取文件
InputStream inputStream = new FileInputStream(file);
byte bytes[] = new byte[128];
inputStream.read(bytes);
System.out.println(new String(bytes));
inputStream.close();
}
上述代码中先申请一个byte数组去接文件中读取的内容,但是这个大小不知道申请多少合适,大了浪费空间,小了文件内容接不全。因此应先判断文件大小,根据文件大小开辟合适空间。
byte bytes[] = new byte[(int) file.length()];
如果不知道read的内容有多大,那么需要判断是否读取到文件末尾方式。read()方法每次读取一个字节,如果到达文件末尾,read()方法会返回-1。read(byte b[])方法返回读取到的字节长度。
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\Willow.txt");
if (!file.exists()){
file.createNewFile();
}
//读取文件
InputStream inputStream = new FileInputStream(file);
StringBuffer buffer = new StringBuffer();
int temp = -1;
//read每次读取一个字节
while ((temp = inputStream.read())!=-1){
buffer.append((char)temp);
}
System.out.println(buffer.toString());
inputStream.close();
}
图片复制
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\0.jpg");
if (!file.exists()){
return;
}
File fileOut = new File("D:\\Willow.jpg");
if (!fileOut.exists()){
fileOut.createNewFile();
}
//读取文件
InputStream inputStream = new FileInputStream(file);
//写入文件
OutputStream outputStream = new FileOutputStream(fileOut);
int temp = -1;
//一个字节一个字节拷贝,如果文件太大,使用read(byte b[])方法读取,再写入。
while ((temp = inputStream.read())!=-1){
outputStream.write((char)temp);
}
inputStream.close();
outputStream.close();
}
字符流
当字节流读取文本时,可能遇到中文,一个中文可能占用多个字节存储,无法正确读取,而字符流以字符为单位,可以正确处理文本文件。
一个字符等于两个字节。Writer是字符输出流,Reader是字符写入流。
- 字符输出流Writer
Writer实现接口Appendable、Closeable和Flushable接口。Appendable接口代表内容可以被追加。
主要的方法有:
void write(String str) throws IOException;
void write(char[] cbuf) throws IOException;
abstract void flush() throws IOException;
abstract void close() throws IOException;
抽象类不可实例化,必须要通过子类实例化。
当操作的数据对象是文件时,可以使用FileWriter类。
注意:write方法只把数据写到内存缓冲区中,并不会直接写到文件中,需要调用flush方法将缓冲区中数据刷到文件中,或者close时会全部刷过去后再释放资源。
追加写入和换行写入同FileOutputStream。
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\Willow.txt");
if (!file.exists()){
file.createNewFile();
}
Writer writer = new FileWriter(file);
String string = "Hello,world!";
writer.write(string);
writer.close();
//追加续写,传参true
Writer writer1 = new FileWriter(file,true);
writer1.write("你好吗");
writer1.close();
}
- 字符输入流Reader
Reader实现接口Readable、Closeable接口。
主要的方法有:
int read(char[] cbuf) throws IOException;
int read() throws IOException;
abstract void close() throws IOException;
抽象类不可实例化,必须要通过子类实例化。
当操作的数据对象是文件时,可以使用FileReader类。
public static void main(String[] args) throws InterruptedException, IOException {
File file = new File("D:\\Willow.txt");
if (!file.exists()){
file.createNewFile();
}
Reader reader = new FileReader(file);
char[] chars = new char[(int) file.length()];
reader.read(chars);
System.out.println(chars);
reader.close();
//循环判断是否读完
Reader reader1 = new FileReader(file);
int temp = -1;
while ((temp = reader1.read()) != -1){
System.out.print((char) temp);
}
}
其他
字节流和字符流区别:字符流使用缓冲区,字节流没有使用缓冲区。
使用字节流好还是字符流好?字节流更好,因为文件在硬盘存储或传输时都是以字节方式进行,字符只有在内存中才形成,因此开发中字节流使用更广泛。
正常写代码时不应往外抛异常,应该捕获异常:
public static void main(String[] args) {
try {
File file = new File("D:\\Willow555.txt");
InputStream inputStream = new FileInputStream(file);
System.out.println(inputStream.read());
}catch (IOException e){
e.printStackTrace();
System.out.println("error");
}
}