InputStream
此抽象类(不能被实例化)表示字节输入流的所有类的父类
常用方法:
- int read():读取一个字节的数据,并将字节的值作为int类型返回(0-255之间),如果没有读出或者读取结束返回-1
- void close():关闭输入流对象,释放相关系统资源
OutputStream
此抽象类(不能被实例化)表示字节输出流的所有类的父类
常用方法:
- void write(int n):向目的地中写入一个字节
- void close():关闭输出流对象,释放相关系统资源
Reader
用于读取字符流的抽象类,数据单位为字符
常用方法:
- int reader():读取一个字符的数据,并将字符的值作为int类型返回(0-65535)如果读取失败或者读取结束返回-1
- void close():关闭流对象,释放相关系统资源
Writer
用于输出的字符流抽象,数据单位为字符
常用方法:
-
void write(int n):向输出流中写入一个字符
-
void close():关闭流对象,释放相关系统资源
第一个简单的IO流程序
public class Demo1 {
public static void main(String[] args) {
//创建字节输入流对象
FileInputStream fis=null;
try {
fis=new FileInputStream("d:/a.txt");//注意不要加多余的回车或者空格
int s1=fis.read();//对应一个字符a的Ascll码
int s2=fis.read();
int s3=fis.read();
int s4=fis.read();
int read = fis.read();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println(read);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
//上述是一个一个读取,因此需要改进
改进样例,使得一次输出全部
public class Demo2 {
public static void main(String[] args) {
//创建字节输入流对象
FileInputStream fis=null;
try {
fis=new FileInputStream("d:/a.txt");
//如果想要输出字符
StringBuilder s1=new StringBuilder();
//借助循环实现一次多个读取
int temp=0;
while((temp=fis.read())!=-1){
System.out.println(temp);
s1.append((char)temp);
}
System.out.println( s1.toString());
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
//输出:
97
98
99
abc
三、File类的使用
1.file类的作用:
2.File类操作目录与文件的常用方法 2.1针对文件的操作方法File是java提供的针对磁盘中的文件或目录转换文件或目录的包装类,一个file类对象可以代表一个文件或者目录,File对象可以实现获取文件和目录属性等功能,可以实现对文件和目录的创建和删除
- creatNewFile():创建新文件
- delete():直接从磁盘上删除
- excits():查询磁盘中文件是否存在
- getAbsoultPath():获取绝对路径
- getPath():获取相对路径
- getName():获取文件名
- isFile():判断是否是文件
- length():查看文件中的字节数、
- isHidden:判断抽象路径名是不是隐藏文件
- exists():查询目录是否存在
- isDirectory:判断当前路径是否为目录
- mkdir():创建目录
- getParentFile():获取当前目录的父级目录
- list():返回一个字符串数组,包含目录中的文件和目录的路径名
- listFiles():返回一个File数组,表示用此抽象路径名表示目录中的文件
public class Demo1 {
public static void main(String[] args) throws Exception{
//创建一个File类对象
File file=new File("d:/1.txt");//'/'=='\'
//创建成功返回true,已经创建后返回false
System.out.println(file.createNewFile());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getName());
//删除
System.out.println(file.delete());
//判断是否存在
System.out.println(file.exists());
}
}
public class Demo2 {
public static void main(String[] args) {
File file=new File("d:/newFile");
//System.out.println(file.mkdir());//创建单级目录,若若要创建多级目录则使用mkdirs
System.out.println(file.exists());
System.out.println(file.getParentFile().getName());
String[] arr=file.list();
for(String s:arr){
System.out.println(s);
}
System.out.println("----------");
//与上面不同的是输出绝对路径
File[] file2=file.listFiles();
for(File f:file2){
System.out.println(f);
}
}
}
输出:
true
1
2
b
----------
d:newFile1
d:newFile2
d:newFileb
四、常用流对象
1.文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(如图像,视屏,文本)。java也提供了FileReader专门读取文本文件
FileoutStream通过字节的方式写数据到文件中,适合所有类型的文件。java也提供了FileWriter专门写入文本文件
文件字节输出流读取图片public class Demo3 {
public static void main(String[] args) {
FileInputStream file=null;
try {
file=new FileInputStream("d:/15.jpg");
int temp=0;
while((temp=file.read())!=-1){
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(file!=null){
try {
file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
文件字节输出流将一个文件读取后重写到新的文件
public class Demo3 {
public static void main(String[] args) {
FileInputStream file=null;
FileOutputStream fos=null;
try {
//创建文件字节输入流对象
file=new FileInputStream("d:/15.jpg");
//创建文件字节输出流对象
fos=new FileOutputStream("d:/new.jpg");
int temp=0;
while((temp=file.read())!=-1){
// System.out.println(temp);
//将读入的信息写到新的文件中
fos.write(temp);
}
//将数据从内存中写入到磁盘中
fos.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(file!=null){
try {
file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
通过缓冲区提高提高读写效率
方式一
通过创建一个指定长度的字节数组作为缓冲区,来提高IO流的读写效率,适用于读取较大图片时的缓冲区定义。如何理解呢?就好比之前运送十斤米是一粒一粒(字节)运送,现在将十斤米打包成若干份,这样就提高运送效率。
注意点:
- 缓冲区长度一定是2的整数幂,一般情况下1024长度比较合适。
public class FileStreamBufferDemo {
public static void main(String[] args) throws Exception {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis=new FileInputStream("d:/15.jpg");
fos=new FileOutputStream("d:/new.jpg");
//创建字节数组==创建缓冲区,提高读写效率
byte[] buff=new byte[1024];
int temp=0;
while((temp=fis.read(buff))!=-1){//read(数组)返回读取长度
fos.write(buff,0,temp);//一次拿一整包(数组名,开始下标,结束结束下标)
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
方式二
通过创建一个字节数组作为缓冲区,但是这个数组长度使用过输入流对象的available()返回当前文件的预估长度来定义的,在读写文件时,是在一次读写操作中完成文件读写操作的。(可以理解为空间换时间,提高效率但是占用内存)
注意点:
- 如果文件过大,那么对内存的占用也是比较大的。因此大文件使用方法一
public class FileStreamBuffer2 {
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
//创建文件输入流(读取)对象
fis=new FileInputStream("d:/15.jpg");
fos=new FileOutputStream("d:/new1.jpg");
byte[] buff=new byte[fis.available()];
fos.write(buff);
fos.flush();//将残留的数据强制输出
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
通过字节缓冲流提高读写效率
java缓冲流实在别的流上加缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。可以提高效率。
缓冲字节流:
通过内部缓存数组提高操作流的效率
- BufferedInputStream
- BufferedOutStream
public class FileStreamBufferDemo3 {
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try{
fis=new FileInputStream("d:/15.jpg");
bis=new BufferedInputStream(fis);
fos=new FileOutputStream("d:/aa.jpg");
bos=new BufferedOutputStream(fos);
//缓冲区中默认长度为8192
int temp=0;
while((temp=bis.read())!=-1){
bos.write(temp);
}
bos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//关闭流的顺序:后开的先关闭
if(bis!=null){
bis.close();
}
if (bos!=null){
bos.close();
}
if (fos!=null){
bos.close();
}
if (fis!=null){
fis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
定义文件拷贝工具类
public class FileTool {
public static void main(String[] args) {
fileCopy("d:/15.jpg","d:/123.jpg");
}
public static void fileCopy(String src,String des){
FileInputStream fis=null;
BufferedInputStream bis=null;
FileOutputStream fos=null;
BufferedOutputStream bos=null;
try{
bis=new BufferedInputStream(new FileInputStream(src));
bos=new BufferedOutputStream(new FileOutputStream(des));
int temp=0;
while((temp=bis.read())!=-1){
bos.write(temp);
}
bos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bos!=null){
bos.close();
}
if(fos!=null){
fos.close();
}
if(bis!=null){
bis.close();
}
if(fis!=null){
fis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2.文件字符流(基本与字节流格式一样) 文件字符输入流
public class Demo4 {
public static void main(String[] args) {
FileReader frd=null;
try{
//创建字符输入流对象
frd=new FileReader("d:/a.txt");
int temp=0;
while((temp=frd.read())!=-1){//返回Unocode值
System.out.println((char) temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(frd!=null){
frd.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
文件字符输出流
public class Demo4 {
public static void main(String[] args) {
FileReader frd=null;
FileWriter fwt=null;
try{
//创建字符输入流对象
frd=new FileReader("d:/a.txt");
fwt=new FileWriter("d:/new.txt");
int temp=0;
while((temp=frd.read())!=-1){
fwt.append((char)temp);
}
fwt.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(frd!=null){
frd.close();
}
if (fwt!=null){
frd.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用字符流实现文件的拷贝
public class Demo4 {
public static void main(String[] args) {
FileReader frd=null;
FileWriter fwt=null;
try{
//创建字符输入流对象
frd=new FileReader("d:/a.txt");
fwt=new FileWriter("d:/new.txt");
char[] buffer=new char[1024];
int temp=0;
while((temp=frd.read(buffer))!=-1){
fwt.write(buffer,0,temp);
}
fwt.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(frd!=null){
frd.close();
}
if (fwt!=null){
frd.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
字符缓冲流
提高了读取文本文件的效率
- BufferedReader
- BufferedWriter
复制文本并添加行号的工具类
public class Demo4 {
public static void main(String[] args) {
copyFile("d:/a.txt","d:/new1111.txt");
}
public static void copyFile(String src,String des){
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new FileReader(src));
bw=new BufferedWriter(new FileWriter(des));
String temp="";
int i=0;
while ((temp=br.readLine())!=null){
bw.write(++i+"."+temp);
bw.newLine();//实现换行
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
bw.close();
br.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.转换流
InputStreamReader/OutputStreamWriter用来实现将字节转换为字符流
- System.in是字节流对象,代表键盘的输入,如果我们想要按行接受用户的输入,就必须使用缓冲字符流BufferReader特有的方法readLIne(),但是BufferReader的构造方法必须是一个Reader对象,这时就要使用InputStreamReader
- System.out是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用字符流write(String str)方法,使用OutputStreamWriter将字节流转换为字符流
public class ConvertStream {
public static void main(String[] args) {
BufferedReader br=null;
BufferedWriter bw=null;
try{
br=new BufferedReader(new InputStreamReader(System.in));
bw=new BufferedWriter(new OutputStreamWriter(System.out));
//System.out.println(input);
while(true){
bw.write("请输入:");
String input=br.readLine();
if("exit".equals(input)){
break;
}
bw.write("您输入的是"+input);
bw.newLine();
bw.flush();
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bw!=null){
bw.close();
}
if (br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
通过字节流读取文本文件并添加行号
public class ConvertStream {
public static void main(String[] args) {
BufferedReader br=null;
BufferedWriter bw=null;
try{
br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/newone.txt")));
String temp="";
int i=0;
while((temp=br.readLine())!=null){
bw.write(++i+"."+temp);
bw.newLine();
}
bw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bw!=null){
bw.close();
}
if (br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
4字符输出流
在Java的IO包中专门提供了用于字符输出的流对象—PrintWriter。该对象具有自动行刷新缓冲字符输入流,特点是可以按行写出字符串,并可以通过println()方法实现自动换行
public class ConvertStream {
public static void main(String[] args) {
BufferedReader br=null;
PrintWriter pw=null;
try{
br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
pw=new PrintWriter("d:/newtwo.txt");
String temp=null;
int i=0;
while((temp=br.readLine())!=null){
pw.println(++i+"."+temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(pw!=null){
pw.close();
}
if (br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
5.字节数组流
ByteArrayInputStream和ByteArrayOutStream经常用在需要流和数组之间转化的情况
字节数组输入流
ByteArrayInputStream是将内存中字节数组当作数据源
public class Demo5 {
public static void main(String[] args) {
//获取byte数组
byte[] arr="abcdefg".getBytes();
ByteArrayInputStream bis=null;
StringBuilder sb=new StringBuilder();
try{
//该构造方法的参数是一个字节数组,这个字节数组就是数据源
bis=new ByteArrayInputStream(arr);
int temp=0;
while((temp=bis.read())!=-1){
sb.append((char)temp);
}
System.out.println(sb.toString());
}finally {
try {
}catch (Exception e){
e.printStackTrace();
}
}
}
}
字节数组输出流
ByteArrayOutputStream流对象是将流中的数据写入到字节数组中
package IO.File;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
public class Demo6 {
public static void main(String[] args) {
ByteOutputStream bos=null;
try{
bos=new ByteOutputStream();
bos.write('a');
bos.write('a');
bos.write('a');
bos.write('a');
//将字节数组输出流转换为字节数组
byte[] bytes = bos.toByteArray();
for(int i=0;i
System.out.println((char)bytes[i]);
}
}finally {
try {
}catch (Exception e){
e.printStackTrace();
}
}
}
}
6.数据流
数据流将“基本数据类型与字符串类型”作为数据源,允许程序以机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型
DateInputStream和DataOutputStream提供了可以存取与机器无关的所有Java基础类型
数据输出流
public class Demo7 {
public static void main(String[] args) {
DataOutputStream dos=null;
try{
dos=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/a.txt")));
dos.writeChar('a');
dos.writeInt(10);
dos.writeDouble(Math.random());
dos.writeBoolean(true);
dos.writeUTF("hello world");
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(dos!=null){
dos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
数据输入流
public class Demo7 {
public static void main(String[] args) {
DataInputStream dis=null;
try{
dis=new DataInputStream(new BufferedInputStream(new FileInputStream("d:/a.txt")));
//读取的顺序和写入的顺序一致
System.out.println("char "+dis.readChar());
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(dis!=null){
dis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
7.对象流
对象的本质还是数据
java的序列化和反序列化
当两个进程远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。
对象的序列化:将java对象转换为字节序列的过程称为对象的序列化。
对象的反序列化:把字节序列恢复为java对象的过程
序列化的作用
- 持久化
- 网络通信
序列化涉及的类和接口
ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中
ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把他们反序列化为一个对象,并将其返回
只有实现了Serializeble接口(空接口,只起到标记作用)的类的对象才能被序列化
操作基本数据类型
//和上述操作代码类似,这里简写 //创建对象 ObjectOutputStream oos=new ObjectOutputStream(~~~); oos.writeInt(); ... //读取 ObjectInputStream ois=new ObjectInputStream(~~~); sout(ois.readInt());//按顺序8.随机访问流
RandomAccessFile作用:
- 实现对一个文件做读和写的操作
- 可以访问文件的任意位置
9.File类在IO中的作用
五、Apache IO包当文件作为数据源或者目标时,可以使用File类指定文件以及文件的位置
Apache-commons工具包提供了IOUtils/FileUtils,方便对文件和目录进行操作
FileUtils的常用方法
-
cleanDirectory:清空目录,但不删除目录
-
contentEquals:比较两个文件的内容是否相同
-
copyDierctory:将一个目录内容拷贝到另一个目录。可以通过FileFilter过滤需要拷贝的文件
-
copyFile:将一个文件拷贝到一个新地址
-
copyFileToDirectoryL将一个文件拷贝到某个目录下
-
copyInputStreamToFile:将输入流的内容拷贝某个文件
-
readFileToString:将文件内容作为字符串返回
package IO.File; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; public class FileUtilDemo { public static void main(String[] args) throws IOException { String s=FileUtils.readFileToString(new File("d:/a.txt"),"utf-8"); System.out.println(s); } }
文件拷贝
package IO.File;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
public class FileUtilUtilDemo2 {
public static void main(String[] args) throws IOException {
FileUtils.copyDirectory(new File("d:/a"), new File("E:/a"), new FileFilter() {
//匿名内部类,实现接口
//文件拷贝时的过滤文件
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()||pathname.getName().endsWith("html")){
return true;
}
return false;
}
});
}
}
IOUtil的使用
它大部分方法都是重载的
常见方法:
-
buffer:将传入的方法进行包装,变成缓冲流,并可以通过参数指定缓冲流大小
-
contentEquals:比较两个流的内容是否一致
····查看文档
public class IOUtilDemo {
public static void main(String[] args) throws IOException {
String s=IOUtils.toString(new FileInputStream("d:/a.txt"),"utf-8");
System.out.println(s);
}
}
六、总结
按照流的分类方向
- 输入流:数据源到程序
- 输出流:程序到目的地
按照流的处理数据单元分类
- 字节流
- 字符流
按照流的功能分类
- 结点流:可以直接从数据源或者目的地读取数据
- 处理流:不直接连接到数据源或者目的地,通过对其他流的处理提高程序的性能
IO的四个基本抽象类
InputStream,OutputStream,Reader,Writer



