java中的IO流
Posted yu011
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的IO流相关的知识,希望对你有一定的参考价值。
1、IO流概述
2、文件专属
---2.1关于FileInputStream
---2.2关于FileOutputStream
---2.3文件的拷贝
---2.4FileReader
---2.5FileWriter
3、缓冲区流专属
4、转换流
5、数据流专属
6、标准输出流
IO流概述
- 什么是IO?
I:Input(硬盘到内存);O:Output(内存到硬盘)
通过IO可以完成硬盘文件的读和写。 - IO流的分类
1、输入流、输出流
按照流的方向进行分类:以内存作为参照物,往内存中去,叫做输入(Input),或者叫做读(Read)。从内存中出来,叫做输出(Output),或者叫做写(Write)。
2、字节流
按照读取数据方式不同进行分类:有的流是按照字节的方式读取数据,一次读取1个字节(byte),等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件、图片、声音文件、视频文件等。
3、字符流
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的。这种流不能读取图片、声音、视频等文件,只能读取纯文本文件,连word文件都无法读取。
假设文件file.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读:a字符("a"字符在windows系统中占用1个字节。)
第二次读:中字符("中"字符在windows系统中占用2个字节。) - java中IO流的四大版块:
①、java.io.InputStream; 字节输入流
②、java.io.OutputStream; 字节输出流
③、java.io.Reader; 字符输入流
④、java.io.Writer; 字符输出流
注:类名以Stream结尾的都是字节流。以Reader/Writer结尾的都是字符流。以上四大板块都是抽象类。
1、所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close ()方法。流相当于内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。
2、所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。输出流在最终输出之后,一定要用flush()刷新。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道),刷新的作用就是清空管道。
注意:如果没有flush()可能会导致丢失数据。 - java.io包下需要掌握的16个流:
文件专属:
java.io.FileInputStream(重点)
java.io.FileOutputStream(重点)
java.io.FileReader
java.io.FileWriter
转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreanWriter
缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
数据流专属:
iava.io.DataInputStream
java.io.DataOutputStream
标准输出流:
java.io.PrintWriter
java.io.PrintStream(重点)
对象专属流:
java.io.ObjectInputStream(重点)
java.io.ObjectOutputStream(重点)
文件专属
关于FileInputStream
- 概述
1、文件字节输入流,是万能的。任何类型的文件都可以采用这个流来读。
2、字节的方式完成输入的操作和读的操作(硬盘到内存)
3、关于路径:
IDEA的默认的当前路径是Project的根。 - 代码示例(txt文件内容是zhang):
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo{
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:111.txt");
/*int read():
从该输入流读取一个字节的数据。*/
int readDate = fis.read();
System.out.println(readDate);
/*当读到文件的末尾,再读的时候
就读取不到任何数据了,就会返回-1。*/
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally语句块当中确保流一定关闭。
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
输出(ASCII码的形式):122(字母z)
- 用循环读取数据:
1、while循环
while (true){
int readDate = fis.read();
if (readDate == -1){
break;
}
System.out.println(readDate);
}
输出:
2、改良while循环
int readDate = 0;
while ((readDate = fis.read()) != -1){
System.out.println(readDate);
}
3、以下代码会出现错误:
while (fis.read() != -1){
System.out.println(fis.read());
}
//fis.read()会使指针下移,会漏掉一个字节
输出:
4、缺点:
一次读取一个字节(byte),这样内存和硬盘交互太频繁,时间/资源耗费在交互上面了。
- 往byte数组中读
int read(byte[] b)
1、从该输入流读取最多 b.length个字节的数据为字节数组。(返回值是读取到的字节数量,不是字节本身。)
减少硬盘和内存的交互,提高程序的执行效率。
2、代码示例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo{
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:111.txt");
byte[] bytes = new byte[4];
System.out.println(fis.read(bytes));
//读取到zhan,输出4
System.out.println(fis.read(bytes));
//读取到g,输出:1
System.out.println(fis.read(bytes));
//没有读到,输出:-1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3、将字节数组全部转换为字符串:
byte[] bytes = new byte[4];
System.out.println(fis.read(bytes));
System.out.println(new String(bytes));
System.out.println(fis.read(bytes));
System.out.println(new String(bytes));
System.out.println(fis.read(bytes));
System.out.println(new String(bytes));
输出:
第二次读取到的“g”会把第一次读取到的“zhan”里面的“z”覆盖掉。
4、改良
不应该全部都转换,应该是读取了多少个字节,转换多少个。
使用String(char[] value, int offset, int count)
分配一个新的 String ,其中包含字符数组参数的子阵列中的字符。(offset代表起始位置,count代表长度)
例:
byte[] bytes = new byte[4];
int readCount = fis.read(bytes);
System.out.println(readCount);
System.out.println(new String(bytes, 0, readCount));
readCount = fis.read(bytes);
System.out.println(readCount);
System.out.println(new String(bytes, 0, readCount));
输出:
- FileInputStream读取数据最终版本
代码示例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo{
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:111.txt");
byte[] bytes = new byte[4];
/*while (true){
int readCount = fis.read(bytes);
if (readCount==-1){
break;
}
System.out.print(new String(bytes,0,readCount));
}*/
//再改进
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
System.out.print(new String(bytes,0,readCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
输出:
- FileInputStream的其它常用方法
1、int available()
返回流中剩余(没有被读到)字节数的估计值,从而不会被下一次调用此输入流的方法阻塞。
代码示例:
//读一个字节(有5个字节)
int readByte = fis.read();
System.out.println("剩下的没有读的字节数:" + fis.available());
//输出:4
/*对于小文件使用这种方式读取,可以不用循环*/
byte[] bytes = new byte[fis.available()];
int readCount = fis.read(bytes);
System.out.println(new String(bytes));
/*这种方式不太适合太大的文件,因为byte[]数组不能太大*/
2、long skip(long n)
跳过并从输入流中丢弃 n字节的数据。
代码示例:
fis = new FileInputStream("D:111.txt");
byte[] bytes = new byte[fis.available()];
/*跳过两个字节不读取*/
fis.skip(2);
int readCount = fis.read(bytes);
System.out.println(new String(bytes));
/*输出:ang*/
关于FileOutputStream
- 概述
文件字节输出流,负责写。
从内存到硬盘。 - 代码示例:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo{
public static void main(String[] args) {
FileOutputStream fos = null;
try {
/*这种方式谨慎使用,这种方式会
先将原文件清空,然后重新写入。*/
fos = new FileOutputStream("D://111.txt");
//开始写
byte[] bytes = {97,98,99,100};
//将byte数组全部写出(abcd)
fos.write(bytes);
//将byte数组一部分写出(ab)
fos.write(bytes,0,2);
//写完之后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行后:
- 追加的方式在文件末尾写入
FileOutputStream(String name, boolean append)
以追加的方式在文件末尾写入,不会清空原文件内容。
代码示例:
fos = new FileOutputStream("D://111.txt",true);
byte[] bytes = {97,98,99,100};
fos.write(bytes);
fos.write(bytes,0,2);
fos.flush();
运行后:
- 写入字符串
代码示例:
fos = new FileOutputStream("D://111.txt",true);
//写入字符串
String s = "我是修电脑的";
//转换成byte类型
byte[] bytes = s.getBytes();
//写入
fos.write(bytes);
fos.flush();
运行后:
文件的拷贝
代码示例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo{
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建一个输入流对象
fis = new FileInputStream("D://111.txt");
//创建一个输出流对象
fos = new FileOutputStream("D://222.txt");
//核心:边读边写
byte[] bytes = new byte[1024 * 1024];
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//分开try,一起可能会导致另一个流的关闭
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行后:
FileReader
- 概述
文件宇符输入流,只能读取普通文本。填取文本内容时,比较方便,快捷。 - 代码示例:
FileReader fr = null;
try {
fr = new FileReader("D://111.txt");
char[] chars = new char[4];
int readCount = 0;
while ((readCount = fr.read(chars)) != -1){
System.out.println(new String(chars,0,readCount));
}
输出:
FileWriter
- 概述
文件字符输出流(写)。只能输出普通文本。 - 代码示例
import java.io.FileWriter;
import java.io.IOException;
public class Demo {
public static void main(String[] args) {
FileWriter out = null;
try {
out = new FileWriter("D://222.txt");
//开始写
char[] chars = {‘修‘,‘电‘,‘脑‘};
out.write(chars);
out.write(chars,1,2);
out.write("
");
out.write("我是真不会");
//刷新
out.flush();
} catch (IOException ioException) {
ioException.printStackTrace();
}finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行后:
- 文件复制
使用FileReader和FileWriter进行拷贝的话,只能拷贝“普通文本"文件。
代码示例:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo {
public static void main(String[] args) {
FileWriter out = null;
FileReader in = null;
try {
//读
in = new FileReader("D://111.txt");
//写
out = new FileWriter("D://222.txt");
//边读边写
char[] chars = new char[1024 * 512];
int readCount = 0;
while ((readCount = in.read(chars)) != -1){
out.write(chars,0,readCount);
}
//刷新
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行后:
缓冲区流专属
BufferedReader
- 概述
是一个带有缓冲区的字符输入流。使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,其自带缓冲。 - 代码示例:
import java.io.BufferedReader;
import java.io.FileReader;
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("D://111.txt");
/*1、当一个流的构造方法中需要一个流的时候,
这个被传进来的流叫做:节点流。
2、外部负责包装的这个流,叫做:包装流,
还有一个名字叫做:处理流。
3、就当前这个程序来说:FileReader就是一个节点流。
BufferedReader就是包装流/处理流。*/
BufferedReader br = new BufferedReader(fr);
//读一行,但不会读出换行符
/*String firstLine = br.readLine();
System.out.println(firstLine);
String secondLine = br.readLine();
System.out.println(secondLine);*/
String s = null;
while ((s = br.readLine()) != null){
System.out.println(s);
}
/*
* 关闭流
* 对于包装流来说,只需要关闭最外层流就行,
* 里面的节点流会自动关闭。(详见源代码)
* br.close();
* */
}
}
输出:
BufferedWriter
- 概述:
带有缓冲的字符输出流 - 代码示例:
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
public class Demo {
public static void main(String[] args) throws Exception {
BufferedWriter out1 = new BufferedWriter(new FileWriter("D://222.txt"));
//转换流的方式
//BufferedWriter out2 = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D://222.txt",true)));
out1.write("这是BufferedWriter");
out1.write("
");
out1.write("这是BW第二行");
out1.flush();
out1.close();
}
}
运行后:
转换流
- 将字节流转换成字符流
java.io.InputStreamReader
java.io.OutputStreanWriter - 代码示例:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) throws Exception {
//字节流
FileInputStream fis = new FileInputStream("D://111.txt");
//通过转换流转换
//这里的fis是节点流,reader是包装流
InputStreamReader reader = new InputStreamReader(fis);
//这个构造方法只能传一个字符流,不能传字节流。
//这里的reader是节点流,br是包装流
BufferedReader br = new BufferedReader(reader);
//最强套娃
//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D://111.txt")));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//关闭最外层
br.close();
}
}
输出:
数据流专属
DataOutputStream
- 概述
1、DataOutputStream(OutputStream out)
创建一个新的数据输出流,以将数据写入指定的底层输出流。
2、这是一个数据专属的流。
3、这个流可以将数据连同数据的类型一并写入文件。
4、注意:这个文件不是普通文本文档。(这个文件用记事本打不开) - 代码示例:
import java.io.DataOutputStream;
import java.io.FileOutputStream;
public class Demo {
public static void main(String[] args) throws Exception{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data"));
//写数据
byte b = 11;
short s = 22;
int i = 33;
long l = 44L;
float f = 55F;
double d = 66.66;
boolean bl = true;
char c = ‘a‘;
//写,把数据以及数据的类型一并写入到文件当中。
dos.writeByte(b);
dos.writeInt(i);
dos.writeShort(s);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeBoolean(bl);
dos.writeChar(c);
//刷新和关闭
dos.flush();
dos.close();
}
}
运行后(用记事本方式打开为乱码):
DataInputStream
- 概述
1、DataInputStream(InputStream in)
创建使用指定的底层InputStream的DataInputStream。
2、数据字节输入流。
3、DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。
4、读的顺序需要和写的顺序一致,才可以正常取出数据。 - 代码示例
import java.io.DataInputStream;
import java.io.FileInputStream;
public class Demo {
public static void main(String[] args) throws Exception{
DataInputStream dis = new DataInputStream(new FileInputStream("data"));
//开始读
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
boolean bl = dis.readBoolean();
char c = dis.readChar();
//输出
System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(bl);
System.out.println(c);
//关闭
dis.close();
}
}
输出:
标准输出流
PrintStream
- 概述
标准的字节输出流,默认输出到控制台。
以上是关于java中的IO流的主要内容,如果未能解决你的问题,请参考以下文章