Java IO流
2021/6/6 14:23:03
本文主要是介绍Java IO流,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
IO流
1. IO流概述
1.1 什么是IO流
- I:Input
- O:Output
- 通过IO可以完成硬盘文件的读写
1.2 IO流的分类
- 分类方式
- 按照流的方向进行分类
- 以内存作为参照物
- 输入流:
- 往内存中去叫做输入(Input )或读(Read)
- 输出流:
- 从内存中取出浇输出(Output)或写(Write)
- 输入流:
- 以内存作为参照物
- 按照读取数据的方式不同分类
- 字节流:
- 按照字节的方式读取数据,一次读一个字节(byte)即8个二进制位
- 这种流是万能的,可以读取任何文件(文本文件,图片,声音等)
- 字符流:
- 按照字符的方式读取,一次读取一个字符(为了方便读取普通文本文件而存在)
- 只能读取纯文本文件(能用普通记事本编辑的文件)
- 字节流:
- 按照流的方向进行分类
- 综上,流分为
- 输入,输出流
- 字符流,字节流
1.3 Java中的IO流
- 所有的流都在java.util.*下
- 只需要学习如何new对象,每个对象的功能即可
- IO过程
1.3.1 Java中IO流的四大家族
-
java.io.InputStream 字节输入流
-
java.io.OutputStream 字节输出流
-
java.io.Reader 字符输入流
-
java.io.Writer 字符输出流
四大家族的首领都是抽象类(abstract class)
-
所有流都实现了
- java.io.Closeable接口,都是可关闭的,都有clos()方法
- 流是一个管道,用完需要关闭,这样就不会占用资源
-
所以的输出流都实现了
- java.io.Flushable接口,都是可刷新的,都有flush()方法
- 流是一个管道,输出后管道内会有残留,需要flush()方法来冲刷,强行输出完,否则数据会部分丢失
-
注意
- Java中类名以Stream结尾的都是字节流
- 以Reader/Writer结尾的都是字符流
1.3.2 java.io包下需要掌握的16个流
-
文件专属
- java.io.FileInputStream(重点掌握)
- java.io.FileOutputStream(重点掌握)
- java.io.FileReader
- java.io.FileWriter
-
转换流:(将字节流转换为字符流)
- java.io.InputStreamReader
- java.io.OutputStreamWriter
-
缓冲流专属
- java.io.BufferedReader
- java.io.BufferedWriter
- java.io.BufferedInputStream
- java.io.BufferedOutputStream
-
数据流专属
- java.io.DataInputStream
- java.io.dataoutputStream
-
标准输出流
- java.io.PrintWriter
- java.io.PrintStream
-
对象专属流
- java.io.ObjectInputStream(重点掌握)
- java.io.ObjectOutputStream(重点掌握)
2. FileInputStream的使用
- java.io.FileInputStream
- 文件字节输入流,万能的,任何类型的文件都可以读
- 字节的方式完成输入的操作,完成读的操作
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class Main { /* java.io.FileInputStream: */ public static void main(String[] args) { //创建文件字节输入流对象 FileInputStream fis=null; try { fis=new FileInputStream("/Users/mac/Desktop/draft/hello.txt"); while (true){ int readData=fis.read();//返回值为读到的字节本身,读之前会移动到下一个字节(移动,读,移动,读) if(readData==-1){//如果没有内容会返回-1,退出循环 break; } System.out.println(readData); } /* 改造while循环 int readData=0; while ((readData=fis.read())!=-1){ System.out.println(readData); } */ } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) {//空的流不用关,避免空指针异常 try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- 往byte数组中读数据
fis=new FileInputStream("/Users/mac/Desktop/draft/hello.txt");//文件内容:abcdef byte[] bytes=new byte[4];//准备一个byte数组,一次最多读四个字节(自定义的) int readCount=fis.read(bytes);//返回的是读取的长度 System.out.println(readCount);//4 System.out.println(new String(bytes));//abcd System.out.println(new String(bytes,0,readCount));//abcd,从0开始读readCount个字节 readCount=fis.read(bytes); System.out.println(readCount);//2 System.out.println(new String(bytes));//efcd 把原来的ab覆盖,cd还在 System.out.println(new String(bytes,0,readCount));//ef readCount=fis.read(bytes); System.out.println(readCount);//-1 读不到返回-1
- FileInputStream最终版
fis=new FileInputStream("/Users/mac/Desktop/draft/hello.txt"); byte[] bytes=new byte[4]; int readCount=0; while((readCount=fis.read(bytes))!=-1){//读一次转一次,如果没读到(返回-1)就退出循环 System.out.print(new String(bytes,0,readCount));//最终读完文件所有数据 }
- 其它方法
- available()获取目前可读的字节数
- skip() 跳过几个字节不读
fis=new FileInputStream("/Users/mac/Desktop/draft/hello.txt"); byte[] bytes=new byte[fis.available()];//创建一个和目前文件大小一样的数组,一次性读完 int readCount=fis.read(bytes); System.out.println(new String(bytes,0,readCount));
3. FileOutputStream的使用
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Main { public static void main(String[] args) { FileOutputStream fos=null; try { //在append参数上加true,不会清空原来文件,否则会清空原来的文件在写入 //文件不存在会新建 fos=new FileOutputStream("/Users/mac/Desktop/draft/hh.txt",true); byte[] bytes={97,98,99,100}; //将byte数组全部写出 fos.write(bytes);//abcd //将byte数组部分写出 fos.write(bytes,0,2);//ab } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
3.1 文件的复制
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Main { public static void main(String[] args) { FileInputStream fis=null; FileOutputStream fos=null; try { //创建一个输入流,读文件 fis=new FileInputStream("/Users/mac/Desktop/draft/hh.txt"); //创建一个输出流,写文件 fos=new FileOutputStream("/Users/mac/Desktop/draft/hhh.txt"); //复制就是一边读一边写 byte[] bytes=new byte[1024];//一次读1KB int readCount=0; //边读边写 while ((readCount=fis.read(bytes))!=-1){ fos.write(bytes,0,readCount); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //分开try,否则上面关闭错误,进入catch语句块,导致下面读没关 if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
4. FileReader和FileWriter
4.1 FileReader
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class Main { public static void main(String[] args) { FileReader reader=null; try { reader=new FileReader("/Users/mac/Desktop/draft/hhh.txt"); char[] chars=new char[4];//一次读取四个字符 /*reader.read(chars); 读入数组,不接收返回值,用foreach输出 for(char c:chars){ System.out.println(c); }*/ int readCount=0; while ((readCount=reader.read(chars))!=-1){//边读边输出 System.out.print(new String(chars,0,readCount)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
4.2 FileWriter
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Main { public static void main(String[] args) { FileWriter out=null; try { out=new FileWriter("/Users/mac/Desktop/draft/hhh.txt"); //创建char数组 char[] chars={'我','是','中','国','人'}; out.write(chars);//全部写出 out.write(chars,2,3);//从2开始写出三个字符 out.write("我是一名Java软件工程师!");//写出字符串 out.write("\n");//写出换行符 out.write("hello world"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
4.3 普通文本文件的复制
import java.io.*; public class Main { public static void main(String[] args) { FileReader in=null; FileWriter out=null; try { //创建字符流 in=new FileReader("/Users/mac/Desktop/draft/hh.txt"); out=new FileWriter("/Users/mac/Desktop/draft/copy.txt"); //创建缓冲数组 char[] chars=new char[1024*512];//一次读1MB int readCount=0; while ((readCount=in.read(chars))!=-1){//读入数组,返回读入字节数 out.write(chars,0,readCount);//数组中数据写出到文件 } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5. 带有缓冲区的字符流
- 不需要定义byte或char数组,自带缓冲
- 传入一个字符流,BufferedReader用完会自动把流关闭
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; public class Main { public static void main(String[] args) throws Exception { //创建字符输入流 FileReader reader=new FileReader("/Users/mac/Desktop/draft/hh.txt"); //创建自带缓冲的字符输入流 //这里传入构造方法的字符输入流(FileReader),称为节点流 //而负责包装的这个流称为包装/处理流(BufferedReader) BufferedReader br=new BufferedReader(reader); String s=null; //一次读一行,不带换行符,读完后,没有内容,返回null while ((s=br.readLine())!=null){ System.out.println(s); } } }
5.1 节点流和包装流
- 两个节点流,两个包装流
- FileInputStream相对于InputStreamReader,FileInputStream是节点流,InputStreamReader是包装流
- InputStreamReader相对于BufferedReader,InputStreamReader是节点流,BufferedReader是包装流
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws Exception { //创建字节流 FileInputStream fis=new FileInputStream("/Users/mac/Desktop/draft/hh.txt"); //转换流 InputStreamReader isr=new InputStreamReader(fis); //缓冲字符流 BufferedReader br=new BufferedReader(isr); String line=null; while ((line=br.readLine())!=null){ System.out.println(line); } } }
6. 数据流
6.1 DataOutputStream
- 可以将数据连同数据类型一起写入文件
- 不是普通文件,是加密后的文件(记事本打不开),读的顺序必须和写入顺序一致
import java.io.DataOutputStream; import java.io.FileOutputStream; public class Main { public static void main(String[] args) throws Exception { //创建数据流 DataOutputStream dos=new DataOutputStream(new FileOutputStream("data")); //写数据 byte b=100; short s=200; int i=300; long l=400; float f=500; double d=600; boolean bo=true; char c='a'; dos.writeByte(b); dos.writeShort(s); dos.writeInt(i); dos.writeLong(l); dos.writeFloat(f); dos.writeDouble(d); dos.writeBoolean(bo); dos.writeChar(c); //刷新 dos.flush(); //关闭流 dos.close(); } }
6.2 DataInputStream
import java.io.DataInputStream; import java.io.FileInputStream; public class Main { 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 bo=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(b); System.out.println(c); } }
7. 标准字节输出流
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; public class Main { public static void main(String[] args) throws Exception { //合起来写 System.out.println("hello"); //分开写 //System.out返回一个PrintStream对象 PrintStream ps=System.out; ps.println("hello"); //标准输出流指向文件,不指向控制台 PrintStream printStream=new PrintStream(new FileOutputStream("/Users/mac/Desktop/draft/hhhh.txt")); //修改输出方向为文件 System.setOut(printStream); //输出到文件中 System.out.println("hello"); } }
7.1 利用标准字节输出流编写的日志工具
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; public class LogTool { public static void log(String msg) { try { //创建标准输出流,指向文件,使用追加方式,否则第二次调用该函数会覆盖重写 PrintStream ps = new PrintStream(new FileOutputStream("/Users/mac/Desktop/draft/log.txt",true)); //设置输出方向 System.setOut(ps); //获取当前时间 Date nowdate=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss-SSS"); String strTime=sdf.format(nowdate); System.out.println(strTime+":"+msg); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
- 测试
public class Main { public static void main(String[] args) { //测试工具 LogTool.log("调用了System类的gc()方法,建议启动垃圾回收"); LogTool.log("调用了UserService的doSome()方法"); } }
8. File类
8.1 File
- File类不能完成读和写
- File是文件和目录路径的抽象表示形式
- File可能文件也可能是对应的目录
8.2File类的常用方法
import java.io.File; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { //创建一个File对象 File f1=new File("/Users/mac/Desktop/draft/a/b/c"); //判断是否存在 System.out.println(f1.exists()); //如果不存在,新建 if (!f1.exists()) { //以文件的方式新建 //f1.createNewFile(); //以目录(文件夹)的方式新建 //f1.mkdir(); //创建多重目录 //f1.mkdirs(); } File f2=new File("/Users/mac/Desktop/draft/hhhh.txt"); //获取文件的父路径 String parentPath=f2.getParent(); System.out.println(parentPath); //获取父文件 File parentFile=f2.getParentFile(); System.out.println("获取 parentFile 的绝对路径:"+parentFile.getAbsolutePath()); System.out.println("获取 f2 的绝对路径:"+f2.getAbsolutePath()); } }
import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; public class Main { public static void main(String[] args) { File f1=new File("/Users/mac/Desktop/draft"); //获取文件名 System.out.println(f1.getName());//copy.txt //判断是否是一个目录 System.out.println(f1.isDirectory());//false //判断是否是一个文件 System.out.println(f1.isFile()); //获取文件最后一次修改时间 long haoMiao=f1.lastModified(); System.out.println(haoMiao);//1621843065077 1970年到现在的总毫秒数 //将毫秒转换为日期 Date time=new Date(haoMiao); SimpleDateFormat sdf=new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh 时 mm 分 ss 秒 SSS 毫秒"); String modifytime=sdf.format(time); System.out.println(modifytime);//2021 年 05 月 24 日 03 时 57 分 45 秒 077 毫秒(不一定是现在的时间) //获取文件的大小 System.out.println(f1.length());//953字节 //获取当前目录下所有子文件 File[] files=f1.listFiles(); //打印目录下所有文件名 for(File file:files){ System.out.println(file.getName()); } } }
9. 序列化与反序列化
9.1 序列化
-
参与序列化和反序列化的对象必须实现Serializable接口
-
Serializable接口起标志作用,内容是空的
- 这个接口是给java虚拟机参考的
- Java虚拟机看到这个接口,自动生成一个序列化版本号
-
序列化版本号
-
Java根据类名区分类,如果类名相同,用序列化版本号来区分
-
自动生成序列化版本号的缺陷:
- 一旦代码确定后,不能进行后续的修改
- 如果修改,编译后生成全新的 序列化版本号,虚拟机会认为是一个全新的类
-
改进方法
-
凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号
-
private static final long serialVersionUID=1L;
-
即使修改代码,序列化版本号不变,虚拟机认为是同一个类
-
-
- 序列化的实现
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class Main2 { public static void main(String[] args) throws Exception { //创建Student对象 Student s=new Student(1111,"zhangsan"); //序列化 ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("Student")); //序列化对象 oos.writeObject(s); //刷新 oos.flush(); //关闭 oos.close(); } }
import java.io.Serializable; //实现Serializable接口 public class Student implements Serializable { private int no; private transient String name;//游离的不参与序列化 public Student(){ } public Student(int no, String name) { this.no = no; this.name = name; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } @Override public String toString() { return "Student{" + "no=" + no + ", name='" + name + '\'' + '}'; } }
- 序列化多个对象
import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; public class Main2 { public static void main(String[] args) throws Exception { List<Student> slist=new ArrayList<>(); slist.add(new Student(1111,"zhangsan")); slist.add(new Student(1112,"lisi")); slist.add(new Student(1113,"wangwu")); ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("Student")); //序列化一个集合 oos.writeObject(slist); oos.flush(); oos.close(); } }
9.2 反序列化
import java.io.FileInputStream; import java.io.ObjectInputStream; public class Main2 { public static void main(String[] args) throws Exception { ObjectInputStream ois=new ObjectInputStream(new FileInputStream("Student")); //开始反序列化,读 Object obj=ois.readObject();//返回一个student对象 System.out.println(obj); //关闭流 ois.close(); } }
- 反序列化多个对象
import java.io.FileInputStream; import java.io.ObjectInputStream; import java.util.List; public class Main2 { public static void main(String[] args) throws Exception { ObjectInputStream ois=new ObjectInputStream(new FileInputStream("Student")); List<Student> studentlist=(List<Student>) ois.readObject(); for(Student s:studentlist){ System.out.println(s); } ois.close(); } }
10. IO和Properties联合使用
- 配置文件
- 经常改变的数据写到一个文件中,用程序动态获取
- 属性配置文件
- 配置文件中的格式为 key=value 的格式,称为属性配置文件
- 建议以.properties结尾(不是必须的,只是这样写比较规范)
- Properties是专门存放属性配置文件的一个类
- 属性配置文件中#是注释
- key 重复 value 自动覆盖
- key和value中的值不要加空格
import java.io.FileReader; import java.util.Properties; public class Main { public static void main(String[] args) throws Exception { //创建字符输入流 FileReader fr=new FileReader("/Users/mac/IdeaProjects/333/src/userinfo.properties"); //创建一个Map集合 Properties pro=new Properties(); //调用Properties集合中的load方法将文件中的数据加载到Map集合中 pro.load(fr); //通过key获取value String s1=pro.getProperty("username"); System.out.println(s1); String s2=pro.getProperty("password"); System.out.println(s2); fr.close(); }
这篇关于Java IO流的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-27MQ底层原理资料详解:新手入门教程
- 2024-11-27MQ项目开发资料入门教程
- 2024-11-27RocketMQ源码资料详解:新手入门教程
- 2024-11-27本地多文件上传简易教程
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器
- 2024-11-26Java云原生资料:新手入门教程与实战指南
- 2024-11-26JAVA云原生资料入门教程