什么是io流
IO指的是输入流(input)和输出流(Output),流是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输。IO流就是用来处理设备间数据传输问题的。常见的应用:文件复制;文件上传;文件下载。
IO流分类
按数据的走向:
输入流:数据流从数据源到程序(以InputStream、Reader结尾)
输出流:数据流从程序到目的地(OutputSttream、Writer结尾)
按处理数据的类型:
字节流:以字节为单位处理数据(以Stream结尾)
字符流:以字符为单位处理数据(Reader,Writer结尾)
按处理对象分类:
节点流:可以直接从数据源或目的地读写数据(如FileInputStream、FileReader)
处理流:不直接连接到数据源或目的地,通过对其他流的处理提高程序的性能(如BufferedInputeStream、BufferedWriter等)
IO流的使用场景
-
如果操作的是纯文本文件,优先使用字符流
-
如果操作的是图片、视频、音频等二进制文件。优先使用字节流
-
如果不确定文件类型,优先使用字节流。
File类
File类是Java提供针对磁盘中的文件或目录转换对象的包装类,一个File对象可以代表一个文件或目录,File对象可以实现获取文件和目录属性的功能,可以对目录进行创建删除等。
针对文件的操作:
createNewFile() 创建新文件
delete() 删除文件
exist() 判断文件是否存在
getAbsolutePath()获取绝对路径
getName() 获取文件名
针对目录的操作:
exists() 查询目录是否存在
isDirectory() 判断当前路径是否为目录
mkdir() /mkdirs() 创建目录/创建多级目录
getParentFile() 获取当前目录的父级目录
list() 返回一个字符串数组包括目录中的文件和路径
listFiles() 返回一个File数组用此抽象路径名表示的目录中的文件
文件字节流
字节输入流(FileInputStream)
创建字节输入流对象:
//括号里面为输入文件的绝对路径
FileInputStream fis=new FileInputStream("D:/java/a.txt");
字节输入流读取数据的步骤:
1.创建字节输入对象。
2.调用字节输入流对象的读数据方法(调用read()方法)。
3.关闭流对象(调用close()方法)。
字节输出流(FileOutputStream)
创建字节输出流对象:
//括号里为写入文件的绝对路径
FileOutputStream fos=new FileOutputStream("d:/animal.jpeg");
字节输出流写数据的步骤:
1.创建字节输出流对象。
2.调用字节输出流对象的方法
3.关闭字节输出流对象
写数据默认是在第一行数据头部写入,如若换行则需要在数据最后加/r/n
public FileOutputStream(String name,boolean append)
//若第二个参数为ture,则在第一行数据尾部写入
字节缓冲流:
字节缓冲输出流 BufferOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BufferOutputStream fis=new BufferOutputStream("");//参数为读取数据的绝对路径
字节缓冲输入流 BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充。
BufferedInputStream fos=new BufferedInputStream("");//写入数据的路径
字节输入输出流代码展示:
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamBuffedDemo {
public static void main(String[] args) throws Exception { //异常处理:可以直接throws,也可以在代码中用try···catch···
FileInputStream fis=new FileInputStream("d:/picture/dog.jpeg");
FileOutputStream fos=new FileOutputStream("d:/animal1.jpeg");
byte[] b=new byte[1024];//字节缓冲区,一次读取一个字节数组的数据,提高读取效率
int temp=0;
while((temp=fis.read(b))!=-1) {
fos.write(b,0,temp);
}
fos.flush(); //将数据从内存中写入磁盘中
if(fis!=null) {
fis.close(); //关闭输入流对象
}
if(fos!=null) {
fos.close(); //关闭输出流对象
}
}
}
字符流
字符流中和编码解码问题相关的两个类
FileReader:它读取字节,并使用指定的编码将其解码为字符
方法:read();//可以读取一个字节的数据,也可以读取一个字节数组的数据。
FileWriter:使用指定的编码将写入的字符编码为字节
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileCopyTools2 {
public static void main(String[] args) {
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader("d:/aa.txt");
fw=new FileWriter("d:/aaa.txt");
char[] ch=new char[1024];//字符缓冲区
int temp=0;
while((temp=fr.read(ch))!=-1) {
fw.write(ch,0,temp);
}
fw.flush();
}catch(Exception e) {
e.printStackTrace();
}finally {
try { //此处使用try···catch··将异常捕获,第一个案例是通过throws将异常抛出
if(fr!=null){
fr.close();}
if(fw!=null) {
fw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
注意:每创建一个流对象,最后都要将其关闭。
字符缓冲流:
BufferedReader:针对字符输入流的缓冲流对象,提供了方便的按行读取的方法readline(),一次读取一整行的数据,效率高。
public class BufferedReaderDemo1 {
public static void main(String[] args) {
FileReader fr=null;
BufferedReader br=null;
try {
fr=new FileReader("d:/aa.txt");
br=new BufferedReader(fr);
String temp="";
while((temp=br.readLine())!=null) {
System.out.println(temp);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
if(br!=null)
br.close();
if(fr!=null)
fr.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
BufferedWriter:针对字符输出流的缓冲对象,提供了newline方法,可实现换行操作
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterDemo {
public static void main(String[] args) {
FileWriter fw=null;
BufferedWriter br=null;
try {
fw=new FileWriter("d:/aa.txt");
br=new BufferedWriter(fw);
br.write("ggg");
br.newLine();//此处进行换行
br.write("sf");
br.flush(); //文件输出结果为ggg
sf
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
if(br!=null)
br.close();
if(fw!=null)
fw.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
转换流
当用户输入一串字符时,用字节流read方法只能读取其第一位,若想要读取整串字符时需用到BuferedReader缓冲流其参数只能是一个Reader对象,故通过InputStreamReader流对字节流System.in(System.out)转换成Reader()对象,至此就可以通过BufferedReader的对象调用readline方法进行整行读取。
代码演示:
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));
String str=br.readLine();
bw.write(str);
bw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(bw!=null)
bw.close();
if(br!=null)
br.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
字节数组流
用于流和数组之间转化
ByteArrayInputStream:将字节数组作为数据源。
ByteArrayOutputStream:将字节数组作为目的地。
public class ByteArrayDemo {
public static void main(String[] args) {
byte[] b="sadsa".getBytes();
ByteArrayInputStream bis=null;
StringBuilder sb=new StringBuilder();
try {
bis=new ByteArrayInputStream(b);//其参数是一个字节数组对象,这个字节数组就是数据源
int i=0;
while((i=bis.read())!=-1) {
sb.append((char)i);
}
System.out.println(sb.toString());
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
数据流
数据流将“基本数据类型与字符串类型”作为数据源,从而让输入输出流操作Java基本数据类型与字符串类型
DataInputStream和DataOutputStream提供了所有基本类型数据方法
DataOutputStream dos = null;
DataInputStream dis = null;
try {
dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/aaa.txt")));
dos.writeBoolean(true);
dos.writeChar('as');
dos.writeDouble(dsa);
dos.writeInt(23);
dos.flush();
dis = new DataInputStream(new BufferedInputStream(new FileInputStream("d:/aaa.txt")));
//直接读取数据,注意:读取的顺序要与写入的顺序一致,否则不能正确读取
System.out.println(dis.readBoolean());
System.out.println(dis.readChar());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(dos!=null){
dos.close();
}
if(dis!=null){
dis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
对象流
Java的序列化和反序列化
对象序列化的作用:持久化:把对象的字节序列永久的保存到硬盘上。
网络通信:在网络上传送对象的字节序列
对象的序列化:把Java对象转换为字节序列的过程
对象的反序列化:把字节序列恢复为Java对象的过程
序列化使用的类和接口:
将对象序列化到文件中和反序列化:
package com.io_study;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectStream {
public static void main(String[] args) {
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try {
oos=new ObjectOutputStream(new FileOutputStream("d/"));
ois=new ObjectInputStream(new FileInputStream("d:/aaa"));
User u=new User(1,"hh","24");
oos.writeObject(u);
User u1=new User(2,"123","312");
ois.readObject();
oos.flush();
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
if(oos!=null) {
oos.close();
}
if(ois!=null) {
ois.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
随机访问流
1.RandomAccessFile可以实现两个作用:①实现对一个文件做读和写的操作。
②可以访问文件的任意位置。
2.三个核心方法:
①构造方法RandomAccessFile(String name, String mode):name用来确定文件;mode取r(读)或者rw(读写),通过mode可以确定流对文件的访问权限
②seek(long a):用来定位流对象读写文件的位置,a确定读写位置距离文件开头的字节个数
③getFilePointer() :获取流的当前读写位置。
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("d:/aaaa.txt","rw");
//将数据写入文件中
int[] arr = new int[]{10,20,30,40,50,60,70,80,90,100};
for (int i = 0; i < arr.length; i++) {
raf.writeInt(arr[i]);
}
//将数据隔三个读出
for (int i = 0; i < arr.length; i+=3) {
raf.seek(i*4);
System.out.print(raf.readInt() + "\t");;
}
System.out.println();
//将第四个数据替换成110
raf.seek(4*3);
raf.writeInt(110);
//将数据隔三个读出
for (int i = 0; i < arr.length; i+=3) {
raf.seek(i*4);
System.out.print(raf.readInt() + "\t");;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(raf!=null){
raf.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
File类在IO中的作用
当以文件作为数据源或自标时,除了可以使用字符串作为文件以及位置的指定以外,我们也可以使用File类指定。
BufferedReader br = null;
br = new BufferedReader(new FileReader(new File("路径")));
Apache IO包
FileUtils的使用
常用方法:
读入文件内容
readFileToString(文件需要写入的内容,字符集)
String con = FileUtils.readFileToString(new File("d:/aaa"),"UTF-8");
System.out.println(con);
将已筛选的目录拷贝到新位置:
copyDirectory(File srcDir, File destDir, FileFilter filter)
String destFilePath = "d:/aaa";
//将已筛选的目录复制,并保持原文件日期的新位置。
FileUtils.copyDirectory(file, new File(destFilePath), new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()) return true;
else {
boolean b1 = pathname.getName().endsWith(".txt");
boolean b2 = pathname.getName().endsWith(".jpg");
return b1 || b2;
}
}
});
IOUtils的使用
常用方法:
将输入流或数组中的内容转换为字符串
toString(InputStream input, String encoding)
String con = IOUtils.toString(new FileInputStream("d:/aaaa"),"UTF-8");
System.out.println(con);