一文搞定Java的输入输出流等常见流

Kitty ·
更新时间:2024-11-14
· 698 次阅读

文章目录1.IO流分析2.常用的IO流3.FileInputStream4.FileOutputStream5.通过Stream类实现文件复制6.FileReader7.FileWriter8.BufferedReader缓冲流9.DataInputStream和DataOutputStream数据流10.标准输出流PrintStream11.File类12.拷贝目录练习(重点)13.ObjectInputStream和ObjectOutputStream对象流14.IO +Properties联合使用 1.IO流分析 什么是IO? I:Input O:Output
通过IO可以完成对硬盘的读和写。
在这里插入图片描述 IO流的分类。
有多种分类方式: 一种方式是:按照列的方向进行分类,以内存为参照物,往内存中去叫做输入(Input),或者叫做读(Read).往内存中出来叫做输出(Output),或者叫做写。 第二种:以读取数据方式的不同进行分类:
有的流是按照字节的方式读取数据。一次读取一个字节byte,等同于读取8个二进制。这种流是万能的,什么文件都可以读取,比如:文本,图片,视频…
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片,视频等文件,连word文件都不能读取。
例如:假设文本文件file.txt,采用字符流的话:
a中国bo张三
第一次读:‘a’字符('a’字符在win系统中占用1个字节)
第二次读:’中’字符('中‘字符在win系统中占用2个字节)
总结列的分类:
输入流 ,输出流。
字节流,字符流。 Java中char字符占用两个字节,但系统中占一个字节。
注意:Java中的IO流都已经写好了,我们要会用就可以了。主要研究怎么new流对象,调用哪个对象的哪个方法读,哪个方法写。 2.常用的IO流

Java中所有的流在:java.io.*;
Java IO流的四大家族(都为抽象类):

java.io.InputStream 字节输入流 java.io.OutputStream 字节输出流 java.io.Reader 字符输入流。 java.io.Writer 字符输出流。
Java中以Stream结尾的都是字节流,以Reader/Writer结尾的都是字符流。 所有的流都是可关闭的,都有close()方法,流是一个管道,是内存和硬盘之间的管道,用完后一定要关闭,不然会浪费很多资源。 所有的输出流:都实现了java.io.Flushiable接口,都是可刷新的,都有flush方法,输出流最后输出之后,一定要记得flush(),刷新一下,这个刷新表示将管道中剩余为输出的数据强行输出完(清空管道),刷新就是为了清空管道。如果没有flush()肯能会造成数据丢失。 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.DateInputStream
java.io.DateOutputStream
标准流
java.io.PrintWriter
java.io.PrintStream
对象流
java.io.ObjectInputStream
java.io.ObjectOutputStream 3.FileInputStream 文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。 read()方法读取一个字节的数据,到文件末尾返回-1。 public class FileInputStreamTest1 { public static void main(String[] args) { //创建文件字节输入流对象 FileInputStream fis = null; { try { fis = new FileInputStream("E:\\A/Cat.txt");//双斜杠代表一个斜杠或用反斜杠 while (true) { int readData = fis.read();//读取到字节本身 if(readData==-1) break; System.out.println(readData); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally {//在finally语句块中确保流一定关闭 if (fis != null) {//关闭流的前提是,流不是空 try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } read(byte[] t):一次最多读取t.length个字节,返回读取的数量,注意在数组中第二次读的数据,将第一次读的数据覆盖,第一次没有覆盖的数据还在数组中。如果一个都没有读取到将返回-1。减少内存和硬盘的交互。
可以利用String类的转换方法,将byte数组转换成String. public class FileInputStreamTest2 { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("Chapter1\\Team"); // 准备一个byte数组 byte[] bytes = new byte[4]; int readCount =0; while ((readCount=fis.read(bytes))!=-1){ System.out.println(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(); } } } } } IDEA默认的当前路径是工程project的根,不是模块。 available()方法:返回流当中剩余的没有读到的字节数。 skip()方法:跳过几个字节不读。 public class FileInputStreamTest3 { public static void main(String[] args) { FileInputStream pis = null; try { pis = new FileInputStream("Chapter1\\Team"); /* int readByte = pis.read(); // 剩余的字节数量,其作用为... System.out.println(pis.available()); // 作用 byte[] bytes= new byte[pis.available()]; // 不需要循环了,因为数组不能太大所以不适合大文件 int readCount = pis.read(bytes); System.out.println(new String(bytes));*/ // skip跳过几个字节不读取 pis.skip(3); System.out.println(pis.read()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(pis != null){ try { pis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 4.FileOutputStream 文件字节输出流,负责写。 从内存到硬盘 write(int b)方法。 write(byte[] b)方法。 write(byte[] b,int off,int len)方法。 public class FileOutputStreamTest1 { public static void main(String[] args) { FileOutputStream fos = null; try { // 文件不存在会新建,将源文件清空再写入 // fos=new FileOutputStream("Chapter1\\Team"); // 以追加的方式写入 fos = new FileOutputStream("Chapter1\\Team",true); byte[] bytes = {97,98,99}; String s ="我是一个中国人"; byte[] aa= s.getBytes();//将字符串转换成byte[]数组 fos.write(aa); fos.write(bytes); // 写部分 fos.write(bytes,0,1); // 注意写完后要刷新 fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 5.通过Stream类实现文件复制

使用FileInputStream+ FileOutputStream完成文件的拷贝。

适用于任何文件。 练习: public class Copy1 { public static void main(String[] args) { FileInputStream fis =null; FileOutputStream fos =null; try { fis = new FileInputStream("F:\\视频\\VID_20190425_125038.mp4"); fos = new FileOutputStream("D:\\VID_20190425_125038.mp4"); // 一边读一边写 byte[] bytes = new byte[1024*1024];//一次最多1M 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 { if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 6.FileReader 文件字符输入流,只能读取普通文本。 读取文本内容时,比较方便,快捷。 操作跟FileInputStream类似,将byte数组,改为char数组即可,也可以用String的方法将其装换成字符串形式。 7.FileWriter 文件字符输出流,写。 只能输出普通文本。
例子:
char[] chars = {’我‘,’是‘,'中’} write(chars) writer(chars,0,2); writer("我是中国人“); 不想被清空再创建输出流对象是,在文件名后面的第二个可填项,添加true) public class FileWriterTest1 { public static void main(String[] args) { FileWriter out = null; try { out = new FileWriter("file",true); out.write("我是中国人" + "哈哈"); } catch (IOException e) { e.printStackTrace(); } finally { if(out!=null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 通过Writer实现拷贝普通文件:操作跟Stream一样,只不过将byte数组改为Char数组。 8.BufferedReader缓冲流 带有缓冲区的字符输入流。 使用这个流的时候不需要自定义char数组,或byte数组,自带缓冲。 readLine()方法:读一行。 public class BufferedReaderTest1 { public static void main(String[] args) { FileReader reader = null; try { reader = new FileReader("file"); } catch (FileNotFoundException e) { e.printStackTrace(); } //当一个流的构造方法需要一个流的时候,这个被传进来的流叫做“节点流”。 //外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流 //当前FileReader是节点流,BufferedReader流叫做包装流 BufferedReader sc = new BufferedReader(reader); //对于包装流来说,只需要关闭外层流就行,里面的节点流会自动关闭 // readLine方法 String s =null; while (true) { try { if (!((s=sc.readLine())!=null)) break; } catch (IOException e) { e.printStackTrace(); } System.out.println(s); } try { sc.close(); } catch (IOException e) { e.printStackTrace(); } } }

练习二:涉及装换流

package Day1; import java.io.*; public class BufferedReaderTest2 { public static void main(String[] args) { FileInputStream in = null; BufferedReader ge=null; try { /*//字节流 in = new FileInputStream("file"); // 通过转换流转换,in是节点流,reader是包装流 InputStreamReader reader = new InputStreamReader(in); // 这个构造方法只能传一个字符流,不能传字节流,reader是节点流 ge = new BufferedReader(reader);*/ String line = null; // 将以上三个步骤合并 ge= new BufferedReader(new InputStreamReader(new FileInputStream("file"))); while((line=ge.readLine())!=null){ System.out.println(line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(ge!=null){ try { ge.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 9.DataInputStream和DataOutputStream数据流 DataOutputStream这个流可以将数据连同数据的类型一并写入文件。 不是普通文档。 DateOutputStream写的文件,只能使用DataInputStream去读。并且度的时候需要提前知道写入的顺序。读的顺序要和写的顺序一致,才可以正常取出数量。 package Day2; import javax.swing.*; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class DateInputStreamTest1 { public static void main(String[] args) { DataOutputStream dos = null; { try { dos = new DataOutputStream(new FileOutputStream("Team")); // 写数据 byte b = 0; short s = 300; int i = 322; long c = 455L; double d = 3.4; boolean sex = false; char f = 'a'; // 写,包括类型 dos.writeByte(b); dos.writeShort(s); dos.writeInt(i); dos.writeLong(c); dos.writeDouble(d); dos.writeBoolean(sex); dos.writeChar(f); // 刷新 dos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (dos != null) { try { dos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } 10.标准输出流PrintStream 标准的字节输出流,默认输出流,默认输出到控制台。 标准输出流不需要手动close关闭。 存在节点流,和包装流。 package Day2; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamTest1 { public static void main(String[] args) throws FileNotFoundException { System.out.println("Hello World!"); PrintStream print = System.out; print.println("Oh my god!"); // 可以改变标准输出流的方向 /* System.gc(); System.currentTimeMillis(); PrintStream print = System.out; System.exit(0); System.arraycopy()*/ // 标准输出流指向file文件,不指向控制台 PrintStream printStream=new PrintStream(new FileOutputStream("file")); // 修改输出方向 System.setOut(printStream); System.out.println("Hello SZ"); } }

练习2:

package Day2; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamTest1 { public static void main(String[] args) throws FileNotFoundException { System.out.println("Hello World!"); PrintStream print = System.out; print.println("Oh my god!"); // 可以改变标准输出流的方向 /* System.gc(); System.currentTimeMillis(); PrintStream print = System.out; System.exit(0); System.arraycopy()*/ // 标准输出流指向file文件,不指向控制台 PrintStream printStream=new PrintStream(new FileOutputStream("file")); // 修改输出方向 System.setOut(printStream); System.out.println("Hello SZ"); } }

练习三(记录日志):

package Day2; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; public class LogTest1 { public static void main(String[] args) { logs("成功完成了日志的代码!"); logs("完成Java的学习!"); logs("登入系统成功!"); logs("你向某某支付XXX钱!"); logs("你收到来着某某的XXXXXXXX人民币!"); } public static void logs (String s){ // 指向日志文件 PrintStream log =null; try { log = new PrintStream(new FileOutputStream("log.txt",true)); // 改变输出方向 System.setOut(log); // 获取当前时间 Date nowTime = new Date(); SimpleDateFormat ss = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); String times=ss.format(nowTime); System.out.println(times+" "+s); } catch (FileNotFoundException e) { e.printStackTrace(); } //不需要关闭 } } 11.File类 File类和四大家族没有关系,所以不能完成文件的读取。
File对象代表什么? 文件和目录路径名的抽象表示形式。
C:\Drivers 这是一个File对象。
C:\Drevers\reader.txt 也是一个File对象。 File只是一个路径名的表现形式。
FIle的常用方法: 以下通过练习来说明 package Day2; import java.io.File; import java.io.IOException; public class FileTest1 { public static void main(String[] args) { // 创建一个File对象 File f1 = new File("D:\\tt.txt"); // 判断文件是否存在 System.out.println(f1.exists()); // 1.如果D:\tt.txt不存在,以文件的形式创建 /* if(!f1.exists()){ try { f1.createNewFile(); } catch (IOException e) { e.printStackTrace(); } }*/ // 2.如果不存在,以目录的形式创建 /*if(!f1.exists()){ f1.mkdir(); }*/ // 3.以多重目录新建 /* File f2 =new File("D:\\xi\\c\\z\\a"); if(!f2.exists()){ f2.mkdirs(); }*/ // 4.获取文件的父路径 File f3 = new File("D:\\WeChat\\locales"); String parentPath = f3.getParent(); System.out.println(parentPath); // 5.获取绝对路径 File f4 = new File("Team"); System.out.println(f4.getAbsolutePath()); } }

练习2:

package Day2; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; public class FileTest2 { public static void main(String[] args) { File f1 = new File("D:\\resources"); // 6.获取文件名 System.out.println(f1.getName()); // 7.判断是否时一个目录 System.out.println(f1.isDirectory()); // 8.判断是否是一个文件 System.out.println(f1.isFile()); // 9.获去文件最后一次修改时间 long haoMiao = f1.lastModified(); // 将总毫秒树转换成日期 Date time = new Date(haoMiao); SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); System.out.println(sd.format(time)); // 10.获取文件大小,字节 System.out.println(f1.length()); // 11.获取当前目录下所有的子文件 File[] files = f1.listFiles(); for(File file :files){ System.out.println(file); } } } 12.拷贝目录练习(重点) package Day2; import java.io.*; public class CopyContent1 { public static void main(String[] args) { // 拷贝源 File srcFile = new File("F:\\QQ"); // 拷贝目标(放哪里) File destFile = new File("D:\\"); // 调用方法 copyDir(srcFile,destFile); } private static void copyDir(File srcFile, File destFile) { if(srcFile.isFile()){//如果是文件递归结束 /*是文件就拷贝,一边读,一边写*/ FileInputStream in = null; FileOutputStream out = null; try { //读 in = new FileInputStream(srcFile); //写 String path = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" )+srcFile.getAbsolutePath().substring(3); out = new FileOutputStream(path); byte[] bytes = new byte[1024*1024]; int readCount =0; while((readCount=in.read(bytes))!=-1){ out.write(bytes,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(); } } } return; } // 获取源的子目录 File[] files= srcFile.listFiles(); for(File file :files){ if(file.isDirectory()) { // 获取所有文件的绝对路径 // System.out.println(file.getAbsolutePath()); // 新建目标,对应的目录,将源目录除根目录外,其余加到目标目录后面 String srcDir = file.getAbsolutePath(); String destDir = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" )+ srcDir.substring(3); File newFile = new File(destDir); if (!newFile.exists()) { newFile.mkdirs(); } } // 字目录可能还是目录 copyDir(file,destFile); } } } 13.ObjectInputStream和ObjectOutputStream对象流 序列化(Serialize):将内存的对象数据信息存到磁盘中。(拆分对象) 反序列化(DeSerialize):将硬盘的数据重新恢复到内存当中,恢复成java对象。
在这里插入图片描述 参与序列化和反序列化的对象必须实现Serializalbe接口。 Serializalbe接口,只是一个标志性接口,起到标志作用,让JVM参考,JVM会为该类创建一个序列化版本号。 序列化版本号的作用:(区分类)
第一:Java通过类名进行比对,如果类名不一样,肯定不是同一个类。
第二:如果类名一样,靠序列化版本号区分。
就算两个人写了同一个类,jvm但不是同一个类,这个时候序列化版本号可以将他们区分。 十年前写的代码放在硬盘,后面改动源代码,重新编译之后,生成了全新的字节码文件。(自动序列化缺点:代码确定后,不能修改,JVM就会认为不是同一个类)
==结论:凡是实现Serializable的类,建议收到将序列化版本号写出来,不建议自动生成。
private static final long serizlVersionUID =456464656546465465L; 建议全球唯一
== IDEA自动生成版本号,先到settings->Inspections(搜索Serializable接口),后面鼠标移动到类名,ALt+回车。 package Day2; import java.io.*; public class ObjectInputStreamTest1 { public static void main(String[] args) { Student ss = new Student(1111,"zhangsh"); ObjectOutputStream oss =null; try { // 序列化 oss = new ObjectOutputStream(new FileOutputStream("Students")); //序列化对象 oss.writeObject(ss); oss.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if(oss!=null){ try { oss.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Student implements Serializable{//可序列化接口 private int no; private 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; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "no=" + no + ", name='" + name + '\'' + '}'; } }

反序列化:

package Day2; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectInputStreamTest2 { public static void main(String[] args) { ObjectInputStream ois =null; try { ois = new ObjectInputStream(new FileInputStream("Students")); //反序列化 Object obj = ois.readObject(); System.out.println(obj); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally { if(ois!=null){ try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 将对象放到集合当中,序列化集合,要求对象和集合都要实现Serializalbe接口。 package Day2; import java.io.*; import java.util.ArrayList; import java.util.List; public class ObjectInputStreamTest1 { public static void main(String[] args) { ObjectOutputStream oss =null; List list= new ArrayList(); list.add(new Student(33,"adsfsa")); list.add(new Student(36,"aa")); list.add(new Student(39,"adsa")); try { // 序列化 oss = new ObjectOutputStream(new FileOutputStream("Students")); //序列化对象 oss.writeObject(list); oss.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if(oss!=null){ try { oss.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Student implements Serializable{//可序列化接口 private int no; private 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; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "no=" + no + ", name='" + name + '\'' + '}'; } } 集合中的对象反序列化,返回的是list类型,需要强转。
在这里插入图片描述 如果希望某个属性不参与序列化,可以在属性前加 transient关键字,表示游离的。 14.IO +Properties联合使用

IO流:文件的读和写。
Properties:是一个Map集合,key和value都是String类型。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


作者:轻松玩编程



输出 输入 java的 JAVA

需要 登录 后方可回复, 如果你还没有账号请 注册新账号