Java学习笔记-Day28 Java IO流(二) 流式部分
一、流(Stream)的分类
如果需要将Java中能够表达所有数据缓存在内存中(包括字符类型或二进制类型),最适宜于使用的数据类型是:byte[],原因是Java中所有的数据类型占据的空间都是byte型的整数倍数。
(1)根据流动方向的不同,流分为 输入流 和 输出流。
- 输入流(读):内存读取磁盘的数据。
- 输出流(写):内存的数据写入到磁盘。
(2)对于输入流和输出流,由于传输格式的不同,又分为 字节流 和 字符流。
-
字节流:是指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于字节输入流类(InputStream)和字节输出流类(OutputStream)。
-
字符流:是指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于字符输入流类(Reader)和字符输出流类(Writer)。
二、字节流
1、OutputStream(字节输出流)
OutputStream类(java.io.OutputStream)是一个抽象类,提供了Java向流中以字节为单位写入数据的公开接口,大部分字节输出流都继承自OutputStream抽象类。
- 部分方法
(1)
void flush()
:刷新此输出流,并强制写出任何缓冲的输出字节。
(2)
void close()
:先会刷新此输出流,再关闭此输出流,并释放与此流相关联的任何系统资源。
(3)
void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。
(4)
void write(byte[] b, int off, int len)
:将指定的字节数组从偏移 off开始,写入 len个字节到此输出流。
(5)
abstract void write(int b)
:将指定的字节写入此输出流。
2、InputStream(字节输入流)
InputStream类(java.io.InputStream )是一个抽象类,提供了Java中从流中以字节为单位读取数据的公开接口,大部分字节输入流都继承自InputStream抽象类。
- 部分方法
(1)
int available()
:返回从该输入流中可以读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
(2)
void close()
:关闭此输入流,并释放与流相关联的任何系统资源。
(3)
void mark(int readlimit)
:标记此输入流中的当前位置。
(4)
void reset()
:将此流重新定位到上次在此输入流上调用 mark方法时的位置。
(5)
boolean markSupported()
:测试这个输入流是否支持 mark和 reset方法。
(6)
abstract int read()
:从输入流读取数据的下一个字节。
(7)
int read(byte[] b)
:从输入流读取一些字节数,并将它们存储到缓冲区 b 。
(8)
int read(byte[] b, int off, int len)
:从输入流读取最多 len字节的数据到一个字节数组。
(9)
long skip(long n)
:跳过并丢弃来自此输入流的 n字节数据。
3、FileOutputStream(文件输出流 / 原始字节输出流)
FileOutputStream(文件输出流)继承于OutputStream抽象类,是进行文件内容写操作的最基本类工具,FileOutputStream能够将内存中的数据输出到文件中。
FileOutputStream是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。有些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FileOutputStream 用于写入诸如图像数据之类的原始字节的流。如果是要将字符流输出到文件,请使用 FileWriter。
- 构造方法
(1)
FileOutputStream(File file) throws FileNotFoundException
:使用File对象创建文件输出流对象,如果文件打开失败,将抛出FileNotFoundException异常。
(2)
FileOutputStream(File file, boolean append) throws FileNotFoundException
:使用File对象创建文件输出流对象,并由参数append指定是否追加文件内容,true为追加,false为不追加(将会直接删除以前的文件内容)。如果文件存在但是是一个目录而不是常规文件,不存在但不能创建,或者由于任何其他原因无法打开,那么抛出一个FileNotFoundException 异常。
(3)
FileOutputStream(String name) throws FileNotFoundException
:直接使用文件名或路径创建文件输出流对象,如果文件打开失败,将抛出FileNotFoundException异常。
(4)
FileOutputStream(String name, boolean append) throws FileNotFoundException
:直接使用文件名或路径创建文件输出流对象,并由参数append指定是否追加,true为追加,false为不追加(将会直接删除以前的文件内容)。如果文件存在但是是一个目录而不是常规文件,不存在但不能创建,或者由于任何其他原因无法打开,那么抛出一个FileNotFoundException 异常。
- 部分方法
(1)
void close()
:关闭此文件输出流,并释放与此流有关的所有系统资源。
(2)
protected void finalize()
:清理到文件的连接,并确保在不再引用此文件输出流时调用此流的 close 方法。
(3)
FileChannel getChannel()
:返回与此文件输出流有关的唯一 FileChannel 对象。
(4)
FileDescriptor getFD()
:返回与此流有关的文件描述符。
(5)
void write(byte[] b)
:将 b.length 个字节从指定 byte 数组写入此文件输出流中。
(6)
void write(byte[] b, int off, int len)
:将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
(7)
void write(int b)
:将指定字节写入此文件输出流。
4、FileInputStream(文件输入流 / 原始字节输入流)
FileInputStream(文件输入流 )继承于InputStream抽象类,是进行文件内容读操作的最基本类工具,FileOutputStream能够获取文件中的数据。
FileInputStream 用于读取诸如图像数据之类的原始字节的流。要从文件中读取字符流,请使用 FileReader。
- 构造方法
(1)
FileInputStream(File file)
:通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
(2)
FileInputStream(FileDescriptor fdObj)
:创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
(3)
FileInputStream(String name)
:通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
- 部分方法
(1)
int available()
:返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
(2)
void close()
:关闭此文件输入流并释放与流相关联的任何系统资源。
(3)
protected void finalize()
:确保当这个文件输入流的 close方法没有更多的引用时被调用。
(4)
FileChannel getChannel()
:返回与此文件输入流相关联的唯一的FileChannel对象。
(5)
FileDescriptor getFD()
:返回表示与此 FileInputStream正在使用的文件系统中实际文件的连接的 FileDescriptor对象。
(6)
int read()
:从该输入流读取一个字节的数据。
(7)
int read(byte[] b)
:从该输入流读取最多 b.length个字节的数据为字节数组。
(8)
int read(byte[] b, int off, int len)
:从该输入流读取最多 len字节的数据为字节数组。
(9)
long skip(long n)
:跳过并从输入流中丢弃 n字节的数据。
5、DataOutputStream(数据输出流)
DataOutputStream(数据输出流)可以使程序以便携的方式将Java基本数据类型和字符串类型的数据写入到输出流。
写入文件的是字节类型的数据,Java的基本数据类型都有自己的字节大小,如:int类型的字节大小为 4 byte、float类型的字节大小为 4 byte等。字符串的字节大小不固定。
- 构造方法
(1)
DataOutputStream(OutputStream out)
:创建一个新的数据输出流,以将数据写入指定的底层输出流。
- 部分方法
(1)
void writeUTF(String str)
:使用修改的UTF-8编码以机器无关的方式将字符串写入基础输出流。
(2)
void writeDouble(double v)
:使用类 Double 的 doubleToLongBits 方法将double参数转换成 long ,然后该 long 值作为8字节的数量、高字节写入基础输出流。
(3)
void writeFloat(float v)
:使用类 Float 的 floatToIntBits 方法将float参数转换成 int ,然后该 int值作为一个4字节的数量、高字节写入基础输出流。
(4)
void writeInt(int v)
:将 int作为四字节,高位字节写入底层输出流。
(5)
void writeLong(long v)
:将 long写入底层输出流,为8字节,高字节为首。
(6)
void writeShort(int v)
:将 short写入底层输出流作为两个字节,高字节优先。
(7)
void write(int b)
:将指定的字节(参数 b的低8位)写入底层输出流。
- 写入数据到文件中(抛出异常的代码)
public class TestOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("E://a.txt");
DataOutputStream dos = new DataOutputStream(fos);
int i = 100;
double d = 200.0;
float f = 300f;
String name = "小明";
String addr = "中国";
dos.writeInt(i);
dos.writeDouble(d);
dos.writeFloat(f);
dos.close();
fos.close();
}
}
- 写入数据到文件中(使用try/catch/finally语句处理异常的代码)
public class TestOutputStream {
public static void main(String[] args) {
FileOutputStream fos = null;
DataOutputStream dos = null;
try {
fos = new FileOutputStream("E://a.txt");
dos = new DataOutputStream(fos);
int i = 100;
String name = "小明";
String addr = "中国";
dos.writeInt(i);
dos.writeUTF(name);
dos.writeUTF(addr);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dos != null) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6、DataInputStream(数据输入流)
程序可以使用DataInputStream(数据输入流)直接读取输入流中Java基本数据类型和字符串类型的数据。
注意:数据的数据类型的读取顺序要与写入顺序一致,不一致的话会抛出 EOFException 异常。
EOFException 是End Of File Exception,当输入过程中意外到达文件或流的末尾时,抛出此异常。
- 构造方法
(1)
DataInputStream(InputStream in)
:创建使用指定的底层InputStream的DataInputStream。
- 部分方法
(1)
String readUTF()
:读取已使用 修改的 UTF-8格式编码的字符串。
(2)
int readInt()
:读取四个输入字节并返回一个 int值。
(3)
double readDouble()
:读取八个输入字节并返回一个 double值。
(4)
float readFloat()
:读取四个输入字节并返回一个 float值。
(5)
boolean readBoolean()
:读取一个输入字节,并返回 true如果该字节不为零, false如果该字节是零。
(6)
byte readByte()
:读取并返回一个输入字节。
(7)
char readChar()
:读取两个输入字节并返回一个 char值。
(8)
int read(byte[] b)
:从包含的输入流中读取一些字节数,并将它们存储到缓冲区数组 b 。
(9)
int read(byte[] b, int off, int len)
:从包含的输入流读取最多 len个字节的数据为字节数组。
- 读取文件中的数据(抛出异常的代码)
public class TestInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E://a.txt");
DataInputStream dis = new DataInputStream(fis);
String addr = dis.readUTF();
int i = dis.readInt();
String name = dis.readUTF();
System.out.println("i="+i);
System.out.println("name="+name);
System.out.println("addr="+addr);
dis.close();
fis.close();
}
}
- 读取文件中的数据(使用try/catch/finally语句处理异常的代码)
public class TestInputStream {
public static void main(String[] args) {
FileInputStream fis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream("E://a.txt");
dis = new DataInputStream(fis);
int i = dis.readInt();
String name = dis.readUTF();
String addr = dis.readUTF();
System.out.println("i=" + i);
System.out.println("name=" + name);
System.out.println("addr=" + addr);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、文件的复制
通过FileOutPutStream与FileInputStream,实现简单的文件复制操作。
因为要复制的文件的文件类型不确定,所以使用字节流来操作。
文件复制的操作:通过FileInPutStream(文件输入流)读取某个文件的字节数据,并存入内存中,再通过FileOutPutStream(文件输出流)将内存中的字节数据写入目标文件中。
public class CopyFile {
public static void main(String[] args) {
copy("D://a.txt","E://b.txt");
}
public static void copy(String srcpath,String destpath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcpath);
fos = new FileOutputStream(destpath);
int len=0;
byte[] b = new byte[1024];
if((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
System.out.println("文件复制成功!");
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(fis != null) {
fis.close();
}
if(fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、字符流
虽然FileInputStream类和FileOutputStream类可以高效率地读写文件,但对于Unicode编码的文件,我们需要自行将读取到的字节数据根据编码规则还原为字符串,因此使用它们有可能出现乱码。考虑到Java是跨平台的语言,要经常操作Unicode编码的文件,使用基于以字符为读写的基本单元的字符流来操作文件是有必要的。以字符为单位进行数据输出的工具继承自Writer抽象类,以字符为单位进行数据输入的工具继承自Reader抽象类。
1、Writer(字符输出流)
Writer类(java.io.Writer )和OutputStream类一样也提供了统一的往流中写入数据的方法,和OutputStream不同的是,写入数据的单位由字节变成了字符。
- 部分方法
(1)
Writer append(char c)
:将指定的字符附加到此Writer对象。
(2)
Writer append(CharSequence csq)
:将指定的字符序列附加到此Writer对象。
(3)
Writer append(CharSequence csq, int start, int end)
:将指定字符序列的子序列附加到此Writer对象。
(4)
abstract void close()
:关闭流,先刷新。
(5)
abstract void flush()
:刷新流。
(6)
void write(char[] cbuf)
:写入一个字符数组。
(7)
abstract void write(char[] cbuf, int off, int len)
:写入字符数组的一部分。
(8)
void write(int c)
:写入一个字符。
(9)
void write(String str)
:写入一个字符串。
(10)
void write(String str, int off, int len)
:写入一个字符串的一部分。
2、Reader(字符输入流)
以字符为单位进行数据读取的工具继承自Reader,Reader会将读取到的数据按照标准的规则转换为Java字符串对象。
Reader类(java.io.Reader)也提供的统一读取数据的方法,和InputStream不同,实际开发时更多的是调用不同Reader提供的特殊读取方法。
- 部分方法
(1)
abstract void close()
:关闭流,并释放与之相关联的任何系统资源。
(2)
void mark(int readAheadLimit)
:标记流中的当前位置。
(3)
void reset()
:重置流。
(4)
boolean markSupported()
:告诉这个流是否支持mark()操作。
(5)
int read()
:读一个字符。
(6)
int read(char[] cbuf)
:将字符读入数组。
(7)
abstract int read(char[] cbuf, int off, int len)
:将字符读入数组的一部分。
(8)
int read(CharBuffer target)
:尝试将字符读入指定的字符缓冲区。
(9)
boolean ready()
:告诉这个流是否准备好被读取。
(10)
long skip(long n)
:跳过字符。
3、FileReader(文件读取流)
FileReader类(java.io.FileReader)称为文件读取流,允许以字符流的形式对文件进行读操作。与FileWriter相似,该类将从文件中逐个地读取字符,效率比较低下,因此一般也将该类对象包装到缓冲流(BufferedReader)中进行操作。
*构造方法
(1)
FileReader(File file) throws FileNotFoundException
:使用File对象创建文件读取流对象,如果文件打开失败,将抛出FileNotFoundException异常。
(2)
FileReader(String name) throws FileNotFoundException
:使用文件名或路径创建文件读取流对象,如果文件打开失败,将抛出FileNotFoundException异常。
//1、创建FileReader对象
FileReader fr = new FileReader("C:\\information.txt");
//2、创建File对象,用来获取文件的长度
File file = new File("C:\\information.txt");
//3、创建一个长度为 文件长度 的字符数组
char[] c = new char[(int) file.length()];
System.out.println((int) file.length());
//4、使用FileReader对象的read方法读取文件内容,存入字符数组,返回字符个数
int num = fr.read(c);
System.out.println(num);//num是字符个数
System.out.println(c);
注意:文件中字符的字节大小:中文字符为2字节,数字字符和英文字符为1字节。
4、FileWriter(文件写入流)
FileWriter类(java.io.FileWriter )称为文件写入流,以字符流的形式对文件进行写操作。FileWriter将逐个向文件写入字符,效率比较低下,因此一般将该类对象包装到缓冲流(BufferedWriter)中进行操作。
- 构造方法
(1)
FileWriter(File file) throws IOException
:使用File对象创建文件写入流对象,如果文件打开失败,将抛出IOException异常,必须处理异常。
(2)
FileWriter(File file, boolean append) throws IOException
:使用File对象创建文件写入流对象,并由参数append指定是否追加。如果文件打开失败,将抛出IOException异常,必须处理异常。
(3)
FileWriter(String name) throws IOException
:直接使用文件名或路径创建文件写入流对象。如果文件打开失败,将抛出IOException异常,必须处理异常。
(4)
FileWriter(String name, boolean append) throws IOException
:直接使用文件名或路径创建文件写入流对象,并由参数append指定是否追加。如果文件打开失败,将抛出IOException异常,必须处理异常。
- 将数据写入文件
//1、创建FileWriter对象
FileWriter fw = new FileWriter("C:\\information.txt");
//2、调用writer方法完成写的动作
fw.write("abcd1234");
//3、刷新流,数据才能进入文件
fw.flush();
//4、关闭流,也会默认刷新流
fw.close();
- 在文件的内容后增添数据
//1、创建FileWriter对象
FileWriter fw = new FileWriter("C:\\information.txt",true);
//2、调用append方法完成添加的动作
fw.append("\r\n刚添加的数据");
//3、关闭流,也会默认刷新流
fw.close();
注意:调用write()或者append()方法,只是将数据写到内存中,需要通过flush()方法或者close()方法,将内存中的数据写到文件中。在流使用结束后,一定要记得关闭流。\r\n
是文件中的换行。
5、BufferedReader(缓冲读取流)
BufferedReader类(java.io.BufferedReader)拥有8192字符的缓冲区。当BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并置入缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不足,才会再从文件中读取。
- 构造方法
(1)
BufferedReader(Reader in)
:创建使用默认大小的输入缓冲区的缓冲字符输入流。
(2)
BufferedReader(Reader in, int sz)
:创建使用指定大小的输入缓冲区的缓冲字符输入流。
- 部分方法
String readLine()
:一次性读取一行文本(以换行符\n
、回车符\r
区分),如果读取到流的末尾,无法读取更多的数据,则返回null。
//1、创建FileReader对象
FileReader fr = new FileReader("D:\\information.txt");
//2、创建BufferedReader对象,FileReader对象作为参数
BufferedReader br = new BufferedReader(fr);
//3、创建字符串变量s
String s = null;
//4、使用BufferedReader对象的readLine方法读取一行字符,赋值给字符串变量s
while((s = br.readLine())!=null) {
System.out.println(s);
}
//5、关闭BufferedReader流
br.close();
//6、关闭FileReader流
fr.close();
6、BufferedWriter(缓冲写入流)
BufferedWriter类(java.io.BufferedWriter)拥有8192字符的缓冲区。使用BufferedWriter时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。
- 构造方法
(1)
BufferedWriter(Writer out)
:创建使用默认大小的输出缓冲区的缓冲字符输出流。
(2)
BufferedWriter(Writer out, int sz)
:创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
- 部分方法
(1)
void write(char[] cbuf, int off, int len)
:写入字符数组的一部分。
(2)
void write(int c)
:写一个字符。
(3)
void write(String s, int off, int len)
:写一个字符串的一部分。
//1、创建FileWriter对象
FileWriter fw = new FileWriter("D:\\information.txt");
//2、创建BufferedWriter对象,FileWriter对象作为参数
BufferedWriter bw = new BufferedWriter(fw);
//3、调用BufferedWriter对象的write方法
bw.write("abcd123456");
//4、关闭BufferedWriter流
bw.close();
//5、关闭FileWriter流
fw.close();