目录
IO流
-
补充:‘a’英文字母,在windows操作系统中是一个字节,但是‘a’字符在java中占用两个字节
-
java中所有的流都在java.io.*下。 char在java下是占两字符的
1.IO流是什么
-
I:Input:输入
-
O:Output:输出
2.IO流的分类:
一种是按照流的方向进行分类:
往内存中去叫做输入(Input)。或者叫做读(Read)。
从内存中出来叫做输出(Output)。或者叫做写(Write)。
另一种方式是按照读取数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取一个字节byte,等同于一次读取8个二进制,这种流是万能的,什么类型的文件都可以读取。八廓文本文件,图片,声音文件。
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文件而存在的,这种流不能读取:图片、声音、时评等文件。只能读取纯文本文件(后缀 .txt),连word文件都无法读取
例: a中国boy张三 按照字节: 第一次读'a'(在Windows系统中占一个字节) 第二次读'中'的一半('中'字符在windows系统中占用2个字节) 第三次读'中'的另外一半 第四次读'国'的一半 第五次读'国'的另外一半 . . . 按照字符:(缺点只能读普通的文本文档) 第一次读'a'字符('a'字符在windows系统中占用1个字节) 第二次读'中'字符('中'字符在windows系统中占用2个字节) 第三次读'国'字符 第四次读'b' 字符 . . . txt只是操作系统中的一个普通的文件
3.java IO流这块有四大家族:
四大家族的首领:
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流
注意:在java中只要"类名"以Sream结尾的都是字节流。以”Reader/Writer结尾的都是字符流“
-
四大家族的首领都是抽象类。(abstract class)
-
所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。
-
使用完流之后一定要关闭否则会占用资源
所有的输出流OutputStream
都实现了:java.io.Flushable接口
,都是可刷新的,都有flush()方法。用完输出流的时候,输出流在最终输出之后一定要Flush(刷新一下。这个刷新表示将管道/通道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用是清空管道。
注意:如果不刷新Flush(),可能导致会数据丢失。
4.十六个流
5.InputStream和OutputStream
5.1InputStream
文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
字节的方式,完成输入的操作完成读的操作
用byte数组
5.1.1read读取字节
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/18:20 * @Description:文件字节输入流,万能的,任何类型的文件都可以采用这个流来读 * 字节的方式,完成输入的操作,完成读的操作 */ public class inputStream { public static void main(String[] args) { //创建文件字节输入流对象 //文件路径:D:\javaTest\temp.txt //以下路径都是采用绝对路径 FileInputStream fileInputStream = null; try { fileInputStream= new FileInputStream("D:\\javaTest\\temp.txt"); //或者:D:/javaTest/temp.txt //开始读 int readDate1 =fileInputStream.read();//97 System.out.println(readDate1); //调用一下read指针就会移动一个位置 int readDate2 =fileInputStream.read();//98 System.out.println(readDate2); int readDate3 =fileInputStream.read();//99 System.out.println(readDate3); int readDate4 =fileInputStream.read();//100 System.out.println(readDate4); int readDate5 =fileInputStream.read();//101 System.out.println(readDate5); int readDate6 =fileInputStream.read();//102 System.out.println(readDate6); int readDate7 =fileInputStream.read();//-1 System.out.println(readDate7);//没有元素是就返回-1 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //在finally语句块当中确保流一定关闭。 if(fileInputStream!=null){//避免空指针异常 //关闭的前提是:流不是空,流是null的时候没必要关闭 try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
相对路径
IDEA默认路径是当前工程(project)的根,工程下有很多模块
"chapter23/src/tempfile2" "tempfile"
绝对路径
D:\\javaTest\\temp.txt
5.1.1改进
package com; /** * 一次读取单个字节 */ import java.io.*; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/17/21:03 * @Description: * * once read one byte * 缺点:一次读取一个字节,内存和硬盘交互太平凡,基本上时间资源都耗费在交互上面了 */ public class javase { public static void main(String[] args) { FileInputStream iis =null; try { iis = new FileInputStream("D:/Test01/text.txt"); /* int number= 0; while(number!=-1){ number = iis.read(); System.out.println(number);//这里的结果会输出-1 }*/ //改进: int number =0; while((number = iis.read())!=-1){ System.out.println(number);//不会输出-1 } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (iis != null) { try { iis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.1.2一次读取多个字节
字节(Stream)最终遍历方式
采用byte数组,一次读取多个字节,最多读取"数组.length"个字节。
5.1.2.1错误案例
不应该全部转成字符串,应该是读了多少个就转多少。
全部都转换可能有重复的部分
fis.read(bytes):这个方法返回的值是:读取到的字节数量。(不是字节本身)
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/19:50 * @Description: */ public class InputStreamTest { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("SwingTest/src/com/IO/pages.txt"); byte []bytes = new byte[4];//每次只能读四个长度 //这个方法返回的值是:读取到的字节数量。(不是字节本身) int resnum=fis.read(bytes); System.out.println(resnum);//4 System.out.println(new String(bytes));//abcd /** * new String(bytes);将byte数组转成字符串 */ //但是这里不应该全部转成字符串,应该是读了多少,就转多少。 int resnum1=fis.read(bytes); System.out.println(resnum1);//2 System.out.println(new String(bytes));//efcd //cd还在,只是把ab换掉了(具体看内存图) int resnum2=fis.read(bytes); System.out.println(resnum2);//1个都没读到返回-1 System.out.println(new String(bytes)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.1.2.2解决方法
将byte转成String使用
new String(byte)
new String(byte,0,num)
默认从0开始,到num结束
num用read(byte)获得
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/19:50 * @Description: */ public class InputStreamTest { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("SwingTest/src/com/IO/pages.txt"); byte []bytes = new byte[4];//每次只能读四个长度 //这个方法返回的值是:读取到的字节数量。(不是字节本身) int resnum=fis.read(bytes); /** * 读了多少,就转多少。 * read()会返回一次读取到的字节数量,不包含最后可能重复的部分 */ System.out.println(resnum);//4 System.out.println(new String(bytes,0,resnum)); //resnum=4 int resnum1=fis.read(bytes); System.out.println(resnum1);//2 System.out.println(new String(bytes,0,resnum1)); //restum1 = 2 int resnum2=fis.read(bytes); System.out.println(resnum2);//1个都没读到返回-1 //System.out.println(new String(bytes,0,resnum2)); //restum2 = 0 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.1.2.3遍历方式
改进while循环
fis.read(byte)方法读到的是字节数量不是字节本身
package com; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/17/22:03 * @Description: */ public class test02 { public static void main(String[] args) { FileInputStream inputStream =null; try { inputStream=new FileInputStream("tempfile"); byte []Byte =new byte[4];//一次最多读取四个字节 while(true) { //这个方法的返回值是:读取到的字节数量(不是字节本身) int readcount = inputStream.read(Byte); if (readcount == -1){ break; } //把byte数组转化成字符串 System.out.println(new String(Byte, 0, readcount));//读多少个就是多少个,没读到就返回-1 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(inputStream==null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.1.2.4最终遍历方式
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/20:25 * @Description: */ public class InputStreamTest01 { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("SwingTest/src/com/IO/pages.txt"); byte []bytes = new byte[50];//创建byte数组 int num=0; //没有读完不会返回-1,读完了返回-1,-1赋给m,m==-1就结束循环 while((num=fis.read(bytes))!=-1){ System.out.println(new String(bytes,0,num)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.1.2.5FileInputStream其他常用方法
//fileInputStraem.availble(); //fileInputStream.skip();
FileInputStream类的其他常用方法: int available():返回流当中剩余额度没有读到的字节数量 long skip(long n):跳过几个字节不读
1.获取字节数量fis.available()
这种方式可以不用循环直接读一次就够了(之前循环读是因为byte数组限定了长度,不能确定一次读多少合适)
但是这种方式不太适合太大的文件,因为byte[]数组不能装太大。
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/22:51 * @Description: */ public class InputTest { public static void main(String[] args) { FileInputStream fis = null; try { //创建FileInputStream对象 fis= new FileInputStream("SwingTest/src/com/IO/pages.txt"); System.out.println("总字节数量"+fis.available());//6 //读一个 int res =fis.read(); System.out.println("剩下"+fis.available()+"个字节没有读");//5 //创建byte数组,fis.available()可以获得剩下的总字节数 byte []bytes = new byte[fis.available()]; fis.read(bytes); System.out.println(new String(bytes));//bcdef } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally {//关闭文件 if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
文件内容:
2.跳过字符串
fis.skip(n) n为跳过元素的个数
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/15/22:51 * @Description: */ public class InputTest { public static void main(String[] args) { FileInputStream fis = null; try { fis= new FileInputStream("SwingTest/src/com/IO/pages.txt"); //跳过三个 fis.skip(3); //得到的是d的字节码 System.out.println(fis.read());//100 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5.2FileOutStream
文件字节输出流,负责写
从内存到硬盘
写完之后一定要flush()刷新
-
该种方式会把文件清空掉再写入,谨慎使用
package com.IO; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/0:10 * @Description: */ public class OutPutStreamTest { public static void main(String[] args) { FileOutputStream fos =null; try { fos = new FileOutputStream("pages");//没有文件会创建文件 byte [] bytes ={ 97,98,99,100,101,102}; //这里是字节码写到文件内的是字符。 //将byte数组全部写出 fos.write(bytes); //写完之后一定要刷新 fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
写完之后一定要刷新。
byte数组里是数字(Ascall码),写到文件里面就是字符。
输出结果:
-
追加的方式
ios =new FileOutputStream("myfile",true); //加上true之后会追加在原文件的末尾
package com.IO; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/0:10 * @Description: */ public class OutPutStreamTest { public static void main(String[] args) { FileOutputStream fos =null; try { fos = new FileOutputStream("pages",true); byte [] bytes ={ 97,98,99,100,101,102}; //这里是字节码写到文件内的是字符。 //将byte数组全部写出 fos.write(bytes); fos.write(bytes,0,2);//再写byte数组0开始往后2个数(ab) String chinese = "我是中国人"; byte []b =chinese.getBytes();//将字符串转成byte类型 fos.write(b); //写完之后一定要刷新 fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.2输出结果
5.3.文件的复制
package com.IO; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/10:02 * @Description:文件的拷贝(使用FileInputStream,FileOutStream完成文件拷贝。) * 拷贝的过程应该是一边读一边写 * 使用以上的字节流拷贝文件的时候,文件类型随意,万能的 */ public class IOtest { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos =null; try { //创建输入输出流对象 fis = new FileInputStream("pages"); fos = new FileOutputStream("page_copy"); byte []bytes = new byte[ fis.available()]; int num =0; //fis.read()将pages文件内容读到bytes数组中 while((num=fis.read(bytes))!=-1){ System.out.println(new String(bytes,0,num)); //将bytes数组中的内容写到page_copy文件内 fos.write(bytes,0,num);//读多少写多少 }; } catch (IOException e) { e.printStackTrace(); }finally { //注意这里要分开处理异常,因为一起处理,前一个发生异常后面那个就关不了了。 //一起try的时候,其中一个出现异常可能会影响到另一个流的关闭 if ( fis!= null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
图列演示
6.FileReader和FileReader
用char数组
文件字符输入流,只能读取普通文本文件
读取文件内容时,比较方便,快捷。
框架都是一样的
6.1FileReader
//FileREAD和FileWrite package com; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/18/16:09 * @Description:文件字符输入流 */ public class test07 { public static void main(String[] args) { FileReader read =null; try { //创建文件字符输入流 read =new FileReader("tempfile"); /*测试: //创建char字符 char[] ch =new char[4];//一次读取四个字符 read.read(ch); for(char num:ch){ System.out.println(num); }*/ int Count =0; while((Count =read.read(ch))!= -1){ System.out.println(new String(ch,0,Count)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(read != null){ try { read.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.2FileWrite
可以直接写入String字符串,也可以写入char数组
会把文件内容清空再写入
不想清空 new Filewriter("file",true),与OutputStream用法相同
package com; import java.io.FileWriter; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/18/16:26 * @Description: */ public class test08 { public static void main(String[] args) { FileWriter fileWriter = null; try { //可以直接写入字符数组和字符串数组 fileWriter =new FileWriter( "file"); //写入 fileWriter.write("我是中国人"); fileWriter.write("\n");//输入换行 char []ins = {'我','是','美','人'}; fileWriter.write(ins,0,2); } catch (IOException e) { e.printStackTrace(); }finally { if(fileWriter !=null){ try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.3文件拷贝
用FileReader和FileWriter实现
读多少写多少
package com.IO; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/10:47 * @Description:使用FileReader和FileWriter拷贝 */ public class ReaderCopy { public static void main(String[] args) { FileReader fileReader =null; FileWriter fileWriter =null; try { //读 fileReader = new FileReader("page_copy"); //写 fileWriter = new FileWriter("page_copy_plus"); int num =0; char[]chars = new char[1024*1024];//1M //一边读一边写 while((num=fileReader.read(chars))!= -1){//向char数组里面读 fileWriter.write(chars,0,num);//读多少写多少 }; fileWriter.flush(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fileReader!=null){ try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } if(fileWriter!=null){ try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
7.缓冲流
使用这个流的时候不需要自定义char和byte数组,自带缓冲
对于包装流来说,只需要关闭最外层的流就行,里面的节点流回自动关闭。(查源代码)
特色:readLine():已读读一行,读取一个文本行但是不带换行符。
//包装流(处理流)和节点流 BufferedReader //关闭只用关闭最外层 package com; import java.io.*; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/19/10:46 * @Description: */ public class test10 { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("javaSE//src//com//javase.java"); //当一个构造方法需要传入流时,这和被传入的流叫做节点流 BufferedReader bufferedReader = new BufferedReader(reader);//FileReader是Reader的子类,传入子类也认可 //外部负责包装的叫做包装流(处理流) String s = null; while((s=bufferedReader.readLine())!=null){ System.out.println(s); } } }
8.转换流
将字节流转成字符流
InputStreamReader:将InputStream转换成Reader
OutputStreamWriter:将OutputStream转换成Writer
8.1套娃
//InputStreamReader package com; import java.io.*; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/9:09 * @Description: */ public class test11 { public static void main(String[] args) throws Exception { //创建字节流 FileInputStream filer= new FileInputStream("javaSE//src//com//javase.java"); //字节流转换为字符流 InputStreamReader isr =new InputStreamReader(filer); //创建BufferedReader对象,这个构造方法只能传一个字符流,不能传字节流 BufferedReader bufferedReader =new BufferedReader(isr); String str =null; //多合一 BufferedReader reader =new BufferedReader(new InputStreamReader(new FileInputStream("\"javaSE//src//com//javase.java\""))); while((str = bufferedReader.readLine())!=null) { System.out.println(str); } //关闭只用关闭最外层 bufferedReader.close(); } }
这种方式节点流和包装流是相对的
//OutputStreamWriter package com; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStreamWriter; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/9:30 * @Description:合并的写法 */ public class test12 { public static void main(String[] args) throws Exception { BufferedWriter writer =new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy",true))); //开始写 writer.write("HelloWorld"); writer.write("\n"); writer.write("HelloKity"); //刷新 writer.flush(); //关闭 writer.close(); } }
9.数据流
java.io.DataOutputStream:数据专属的流 这个流可以将数据连同数据的类型一并写入文件 注意:这个文件不是普通文本文档(这个文件使用记事本打不开)
类似于加密方式
package com; //DataInputStream:数据字节输入流 //DataoutStream写的文件只能使用DatainputStream去读,并且读的时候必须知道写入是的顺序 //读的顺序要和写的顺序相同,才可以正常取出数据 import java.io.DataOutputStream; import java.io.FileOutputStream; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/10:00 * @Description: */ public class test13 { public static void main(String[] args) throws Exception { DataOutputStream das =new DataOutputStream(new FileOutputStream("Data")); byte b =127; short s =456; int i =12; long l =7894; double d =456.123; float f =1.23f; boolean bo = true ; char c ='a'; //写入 das.writeByte(b);//把数据及数据类型一并放入文件当中 das.writeShort(s); das.writeInt(i); das.writeLong(l); das.writeDouble(d); das.writeFloat(f); das.writeBoolean(bo); das.writeChar(c); //刷新 das.flush(); //关闭 das.close(); } }
package com; import java.io.*; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/10:00 * @Description: */ public class test14 { public static void main(String[] args) throws IOException { //读出 DataInputStream dataINputStream = new DataInputStream(new FileInputStream("Data")); Byte b1=dataINputStream.readByte(); Short s1= dataINputStream.readShort(); int i1=dataINputStream.readInt(); Long l1=dataINputStream.readLong(); Double d1=dataINputStream.readDouble(); float f1=dataINputStream.readFloat(); boolean b2=dataINputStream.readBoolean(); char c1=dataINputStream.readChar(); System.out.println(b1); System.out.println(s1); System.out.println(i1); System.out.println(l1); System.out.println(d1); System.out.println(f1); System.out.println(b2); System.out.println(c1); } }
10.标准输出流
10.1PrintStream
PrintStream(new FileOutputStream);
System.setOut(PrintStream)更改输出方向
package com.IO; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/12:16 * @Description:标准输出流默认输入到控制台 */ public class printTest { public static void main(String[] args) throws FileNotFoundException { //联合起来写 PrintStream ps = System.out; //分开写 ps.println(2); ps.println("sfdaas"); ps.println('s'); //标准流不需要手动close() //标准输出流不在指向控制台,指向"log"文件 PrintStream printStream = new PrintStream(new FileOutputStream("log")); //修改输出方向,将输出方向修改到"log"文件 System.setOut(printStream); System.out.println("HelloWord"); System.out.println("HellotheWord"); } }
10.2日志
//更改输出的路径 PrintStream 日志实现: package com; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/10:33 * @Description: */ public class logger { public static void log(String msg) { try { //标准输出流指向日志文件 PrintStream ps = new PrintStream(new FileOutputStream("copy",true));//追加 //改变输出方向 System.setOut(ps); //日期当前时间格式化 Date date =new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); String time =simpleDateFormat.format(date); System.out.println(time+":"+msg); } catch (FileNotFoundException e) { e.printStackTrace(); } } } package com; import java.util.logging.Logger; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/12:35 * @Description: */ public class test { public static void main(String[] args) { logger.log("helloworld"); logger.log("hellokitty"); logger.log("nihaoshijie"); } }
11.File类
java.long.Object ----->java.io.File
File类不是个流不能完成文件的读和写
只是一个文件路径名的抽象表现形式。
一个file对象有可能对应的是目录,也有可能是文件。
11.1常用方法
f.exist(): 判断是否存在
f.createNewFile(): 创建新文件
f.mkdir(): 创建新目录
f.getParent(): 获取父路径 返回值String类型
f.getParentFile(): 与getParent只是返回值类型不一样,也是返回的父路径 返回值File类型
f.getAbsolutePath():获取绝对路径
f.getname():获取文件名
f.isDirectory():判断是否是一个目录
f.isFile():判断是否是一个文件
f.lastModified获取文件最后一次修改时间 返回值类型long(毫秒)
f.length():获取文件的大小
f.listFiles():获取当前目录下所有子目录 返回值类型是
File[]数组
package com; import javax.xml.crypto.Data; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/20/13:05 * @Description: */ public class test15 { public static void main(String[] args) throws IOException { File f =new File("D:\\Test01"); System.out.println(f.exists());//判断是否存在文件 //如果不存在以文件形式创建 // if(!f.exists()){ // f.createNewFile(); // } //如果不存在以目录的形式创建 // if(!f.exists()){ // f.mkdir(); // } //创建多层路径 File f2 =new File("D:\\a\\b\\c\\d\\e"); if(!f2.exists()){ //以多重目录的形式创建 f.mkdirs(); } File f1 =new File("D:\\a\\b"); if(f1.exists()){ String parentspath =f.getParent(); File file =f.getParentFile(); file.getAbsolutePath();//获取绝对路径 } File f3 = new File(""); f3.getName();//获取文件名 /* 判断是文件还是目录 */ System.out.println("是否是文件:"+f3.isDirectory()); System.out.println("是否是目录:"+f3.isFile()); long haomiao =f3.lastModified();//返回的是毫秒 //创建日期对象,传入毫秒 Date times = new Date(haomiao); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); sdf.format(times); System.out.println("获取最后一次文件修改时间"+ sdf.format(times)); //获取文件大小 f3.length(); //获取当前目录下的所有子文件 File f4 =new File("javaSE"); File [] file = f4.listFiles(); for (File files:file) { System.out.println(files.getAbsolutePath()); } } }
11.2拷贝目录
12.对象流
12.1序列化和反序列化
把java对象放在文件上称为序列化
序列化就是排好队,一块一块的给它放到文件当中
反序列化就是把硬盘文件中一块一块的东西拿到内存当中,按顺序组装成一个对象
序列化多个对象
调用 oos.writeObject()方法就是序列化
实现serializable接口(标志性接口)
12.2注意
参与序列化和反序列化的对象,必须要实现Serialzable接口。 通过源代码发现,Serialzable接口只是一个标志接口: public interface Serialable{ } 这个接口当中什么代码都没有。 只是起到标识的作用,java虚拟机看到这个类实现了Serialzable接口可能会对这个类,进行特殊待遇 这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号。
12.3序列化
package com.IO; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/17:13 * @Description:序列化 */ public class ObjectOutputTest { public static void main(String[] args) throws IOException { //创建ObjectOutputStream对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Student")); //创建Student对象 Student student = new Student(); //序列化对象 oos.writeObject(student); //刷新 oos.flush(); //关闭 oos.close(); } } //实现Serializable接口 class Student implements Serializable { //java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号 //这里没有手动写出来,java虚拟机会默认提供序列化版本号 }
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/17:33 * @Description:反序列化 */ public class ObjectInputStreamTest { public static void main(String[] args) throws IOException, ClassNotFoundException { //创建对象 ObjectInputStream ois = new ObjectInputStream( new FileInputStream("Student")); //开始反序列化读 Object o =ois.readObject(); //反序列化回来是一个学生对象,所以会调用学生对象的toString方法 System.out.println(o); } }
12.4序列化多个对象
将对象放到集合当中序列化集合
package com.IO; import java.io.*; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/19:57 * @Description: */ public class ObjectTest { public static void main(String[] args) throws IOException { //创建Set集合 Set<Customer> sets = new TreeSet(); sets.add(new Customer(12)); sets.add(new Customer(13)); sets.add(new Customer(18)); sets.add(new Customer(19)); //创建对象流 ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("File_set")); //序列化 oos.writeObject(sets); //刷新 oos.flush(); //关闭 oos.close(); } } class Customer implements Serializable,Comparable<Customer>{ private int age; public Customer(int age) { this.age = age; } @Override public String toString() { return "Customer{" + "age=" + age + '}'; } @Override public int compareTo(Customer o) { return this.age-o.age; } }
package com.IO; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Set; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/09/16/20:06 * @Description: */ public class ObjectTest_show { public static void main(String[] args) throws IOException, ClassNotFoundException { //创建Object ObjectInputStream ois= new ObjectInputStream(new FileInputStream("File_set")); //反序列化 Object obj =ois.readObject(); //判断是不是属于Set集合 System.out.println(obj instanceof Set); //直接转型成Set集合 Set<Customer> Customers=(Set)obj; for(Customer Customer: Customers){ System.out.println(Customer); } } }
-
注意:如果不用集合序列化多个对象,序列化第二个的时候就会报错
-
所以序列化多个对象最好是用集合
12.5transient
不希望其中某个属性被序列化
//使用transient关键字之后 package com; import java.io.Serializable; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/22/11:22 * @Description: */ public class User implements Serializable { private int age; private transient String name;//name不参与序列化操作 //transient表示游离的,不参加序列化 public User(int age, String name) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
12.6序列化版本号
//java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。 //这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。 //建议将序列化版本号手动的写出来,不建议自动生成 序列化反序列化完成之后。修改代码,再反序会出现异常。序列化版本号发生了变动。 /*java语言中是采用什么机制来区分的? 第一:首先通过对类名进行对比,如果类名不一样肯定不是同一类。 第二:如果类名一样,就靠序列化版本号进行区分。*/
不是同一个类会报异常
-
自动生成序列化版本号的缺陷:
不能修改代码,一修改代码就会报错。因为只要修改就会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(这样就不好了)
最终结论:凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。这样即使这个类被修改了,但是版本号不变,java虚拟机会认为是用同一个类
private static final long serialVersionUID = 1L; //java虚拟机识别一个累的时候先通过类名,如果类名一致,再通过序列化版本号。
13.IO+Properties联合使用
IO流:文件的读和写
Properties:是一个Map集合,key和value都是String类型。
package test; import java.io.FileInputStream; import java.io.FileReader; import java.util.Properties; /** * Created with IntelliJ IDEA. * * @Author: Mr.chen * @Date: 2022/07/24/17:04 * @Description:配置文件 */ /** * Properties 可保存在流中或从流中加载。 * void load(InputStream inStream)从输入流中读取属性列表(键和元素对)。 */ public class IoPropertiestests { public static void main(String[] args) throws Exception { /* Properties是一个Map集合,key和value都是String类型。 想将userinfo文件中的数据加载到Properties对象当中。 */ //新建一个输入流对象 //FileReader reader = new FileReader("javase/javaSE/src/userinfo"); FileInputStream inputStream = new FileInputStream("/Test01/javase/userinfo"); //新建一个Map集合 Properties pro = new Properties(); //调用Properties对象的load方法将文件中的数据加载到Map集合中。 pro.load(inputStream);//文件中的数据顺着管道加载到Map集合中,其中等号左边作key,右边作value //通过key来回去value呢? String username =pro.getProperty("username"); /** * String getProperty(String key)用指定的键在此属性列表中搜索属性。 */ System.out.println(username); String password = pro.getProperty("password"); System.out.println(password); } }
注意
属性配置文件重复会覆盖
username=admin password=123 ################属性配置文件中#是注释符号################ #属性配置文件的key重复了value就会被自动覆盖 #最好不要有空格 password = 456 #key和value之间也可用:隔开